github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/network/debinterfaces/bridge_test.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package debinterfaces_test
     5  
     6  import (
     7  	"github.com/juju/testing"
     8  	gc "gopkg.in/check.v1"
     9  
    10  	"github.com/juju/juju/network/debinterfaces"
    11  )
    12  
    13  type BridgeSuite struct {
    14  	testing.IsolationSuite
    15  
    16  	expander debinterfaces.WordExpander
    17  }
    18  
    19  var _ = gc.Suite(&BridgeSuite{})
    20  
    21  func (s *BridgeSuite) SetUpSuite(c *gc.C) {
    22  	s.IsolationSuite.SetUpSuite(c)
    23  }
    24  
    25  func format(stanzas []debinterfaces.Stanza) string {
    26  	return debinterfaces.FormatStanzas(stanzas, 4)
    27  }
    28  
    29  func (s *BridgeSuite) SetUpTest(c *gc.C) {
    30  	s.expander = debinterfaces.NewWordExpander()
    31  }
    32  
    33  func (s *BridgeSuite) assertParse(c *gc.C, content string) []debinterfaces.Stanza {
    34  	stanzas, err := debinterfaces.ParseSource("", content, s.expander)
    35  	c.Assert(err, gc.IsNil)
    36  	return stanzas
    37  }
    38  
    39  func (s *BridgeSuite) checkBridge(input, expected string, c *gc.C, devices map[string]string) {
    40  	stanzas := s.assertParse(c, input)
    41  	bridged := debinterfaces.Bridge(stanzas, devices)
    42  	c.Check(format(bridged), gc.Equals, expected)
    43  	s.assertParse(c, format(bridged))
    44  }
    45  
    46  func (s *BridgeSuite) checkBridgeUnchanged(input string, c *gc.C, devices map[string]string) {
    47  	stanzas := s.assertParse(c, input)
    48  	bridged := debinterfaces.Bridge(stanzas, devices)
    49  	c.Check(format(bridged), gc.Equals, input[1:])
    50  	s.assertParse(c, format(bridged))
    51  }
    52  
    53  func (s *BridgeSuite) TestBridgeDeviceNameNotMatched(c *gc.C) {
    54  	input := `
    55  auto eth0
    56  iface eth0 inet manual`
    57  	s.checkBridgeUnchanged(input, c, map[string]string{"non-existent-interface": "br-non-existent"})
    58  }
    59  
    60  func (s *BridgeSuite) TestBridgeDeviceNameAlreadyBridged(c *gc.C) {
    61  	input := `
    62  auto br-eth0
    63  iface br-eth0 inet dhcp
    64      bridge_ports eth0`
    65  	s.checkBridgeUnchanged(input, c, map[string]string{"br-eth0": "br-eth0-2"})
    66  }
    67  
    68  func (s *BridgeSuite) TestBridgeDeviceIsBridgeable(c *gc.C) {
    69  	input := `
    70  auto eth0
    71  iface eth0 inet dhcp`
    72  
    73  	expected := `
    74  auto eth0
    75  iface eth0 inet manual
    76  
    77  auto br-eth0
    78  iface br-eth0 inet dhcp
    79      bridge_ports eth0`
    80  	s.checkBridge(input, expected[1:], c, map[string]string{"eth0": "br-eth0"})
    81  }
    82  
    83  func (s *BridgeSuite) TestBridgeDeviceIsBridgeableButHasNoAutoStanza(c *gc.C) {
    84  	input := `
    85  iface eth0 inet dhcp`
    86  
    87  	expected := `
    88  iface eth0 inet manual
    89  
    90  iface br-eth0 inet dhcp
    91      bridge_ports eth0`
    92  	s.checkBridge(input, expected[1:], c, map[string]string{"eth0": "br-eth0"})
    93  }
    94  
    95  func (s *BridgeSuite) TestBridgeDeviceIsNotBridgeable(c *gc.C) {
    96  	input := `
    97  iface work-wireless bootp`
    98  	s.checkBridgeUnchanged(input, c, map[string]string{"work-wireless": "br-work-wireless"})
    99  }
   100  
   101  func (s *BridgeSuite) TestBridgeSpecialOptionsGetMoved(c *gc.C) {
   102  	input := `
   103  auto eth0
   104  iface eth0 inet static
   105      mtu 1500
   106  
   107  auto eth1
   108  iface eth1 inet static
   109      address 192.168.1.254
   110      gateway 192.168.1.1
   111      netmask 255.255.255.0
   112      dns-nameservers 8.8.8.8
   113      dns-search ubuntu.com
   114      dns-sortlist 192.168.1.1/24 10.245.168.0/21 192.168.1.0/24
   115      mtu 1500`
   116  
   117  	expected := `
   118  auto eth0
   119  iface eth0 inet manual
   120      mtu 1500
   121  
   122  auto eth1
   123  iface eth1 inet manual
   124      mtu 1500
   125  
   126  auto br-eth0
   127  iface br-eth0 inet static
   128      bridge_ports eth0
   129  
   130  auto br-eth1
   131  iface br-eth1 inet static
   132      address 192.168.1.254
   133      gateway 192.168.1.1
   134      netmask 255.255.255.0
   135      dns-nameservers 8.8.8.8
   136      dns-search ubuntu.com
   137      dns-sortlist 192.168.1.1/24 10.245.168.0/21 192.168.1.0/24
   138      bridge_ports eth1`
   139  	s.checkBridge(input, expected[1:], c, map[string]string{"eth0": "br-eth0", "eth1": "br-eth1"})
   140  }
   141  
   142  func (s *BridgeSuite) TestBridgeVLAN(c *gc.C) {
   143  	input := `
   144  auto eth0.2
   145  iface eth0.2 inet static
   146      address 192.168.2.3/24
   147      vlan-raw-device eth0
   148      mtu 1500
   149      vlan_id 2`
   150  
   151  	expected := `
   152  auto eth0.2
   153  iface eth0.2 inet manual
   154      vlan-raw-device eth0
   155      mtu 1500
   156      vlan_id 2
   157  
   158  auto br-eth0.2
   159  iface br-eth0.2 inet static
   160      address 192.168.2.3/24
   161      bridge_ports eth0.2`
   162  	s.checkBridge(input, expected[1:], c, map[string]string{"eth0.2": "br-eth0.2"})
   163  }
   164  
   165  func (s *BridgeSuite) TestBridgeBond(c *gc.C) {
   166  	input := `
   167  auto eth0
   168  iface eth0 inet manual
   169      bond-miimon 100
   170      bond-master bond0
   171      bond-mode active-backup
   172      bond-lacp-rate slow
   173      bond-xmit-hash-policy layer2
   174      mtu 1500
   175  
   176  auto eth1
   177  iface eth1 inet manual
   178      bond-miimon 100
   179      bond-master bond0
   180      bond-mode active-backup
   181      bond-lacp-rate slow
   182      bond-xmit-hash-policy layer2
   183      mtu 1500
   184  
   185  auto bond0
   186  iface bond0 inet static
   187      address 10.17.20.211/24
   188      gateway 10.17.20.1
   189      dns-nameservers 10.17.20.200
   190      bond-slaves eth0 eth1
   191      bond-mode active-backup
   192      bond-xmit_hash_policy layer2
   193      bond-miimon 100
   194      mtu 1500
   195      hwaddress 52:54:00:1c:f1:5b
   196      bond-lacp_rate slow`
   197  
   198  	expected := `
   199  auto eth0
   200  iface eth0 inet manual
   201      bond-miimon 100
   202      bond-master bond0
   203      bond-mode active-backup
   204      bond-lacp-rate slow
   205      bond-xmit-hash-policy layer2
   206      mtu 1500
   207  
   208  auto eth1
   209  iface eth1 inet manual
   210      bond-miimon 100
   211      bond-master bond0
   212      bond-mode active-backup
   213      bond-lacp-rate slow
   214      bond-xmit-hash-policy layer2
   215      mtu 1500
   216  
   217  auto bond0
   218  iface bond0 inet manual
   219      bond-slaves eth0 eth1
   220      bond-mode active-backup
   221      bond-xmit_hash_policy layer2
   222      bond-miimon 100
   223      mtu 1500
   224      hwaddress 52:54:00:1c:f1:5b
   225      bond-lacp_rate slow
   226  
   227  auto br-bond0
   228  iface br-bond0 inet static
   229      address 10.17.20.211/24
   230      gateway 10.17.20.1
   231      dns-nameservers 10.17.20.200
   232      hwaddress 52:54:00:1c:f1:5b
   233      bridge_ports bond0`
   234  	s.checkBridge(input, expected[1:], c, map[string]string{"bond0": "br-bond0"})
   235  }
   236  
   237  func (s *BridgeSuite) TestBridgingIdempotent(c *gc.C) {
   238  	input := `
   239  auto eth0
   240  iface eth0 inet manual
   241      bond-miimon 100
   242      bond-master bond0
   243      bond-mode active-backup
   244      bond-lacp-rate slow
   245      bond-xmit-hash-policy layer2
   246      mtu 1500
   247  
   248  auto bond0
   249  iface bond0 inet manual
   250      bond-mode active-backup
   251      bond-xmit-hash-policy layer2
   252      hwaddress ether 7c:d3:0a:bb:e2:0a
   253      bond-slaves eth0
   254      mtu 1500
   255      bond-lacp-rate slow
   256      bond-miimon 100
   257  
   258  auto br-bond0
   259  iface br-bond0 inet static
   260      address 10.20.2.253/22
   261      gateway 10.20.0.1
   262      bridge_ports bond0`
   263  
   264  	s.checkBridgeUnchanged(input, c, map[string]string{"bond0": "br-bond0", "bond0.1000": "br-bond0.1000", "bond0.1001": "br-bond0.1001", "bond0.1002": "br-bond0.1002"})
   265  }
   266  
   267  func (s *BridgeSuite) TestBridgeNoIfacesDefined(c *gc.C) {
   268  	input := `
   269  mapping eth0
   270      script /path/to/pcmcia-compat.sh
   271      map home,*,*,*                  home
   272      map work,*,*,00:11:22:33:44:55  work-wireless
   273      map work,*,*,01:12:23:34:45:50  work-static`
   274  	s.checkBridgeUnchanged(input, c, map[string]string{"eth0": "br-eth0"})
   275  }
   276  
   277  func (s *BridgeSuite) TestBridgeBondMaster(c *gc.C) {
   278  	input := `
   279  auto ens5
   280  iface ens5 inet manual
   281      bond-lacp_rate slow
   282      mtu 1500
   283      bond-master bond0
   284      bond-xmit_hash_policy layer2
   285      bond-mode active-backup
   286      bond-miimon 100`
   287  	s.checkBridgeUnchanged(input, c, map[string]string{"ens5": "br-ens5"})
   288  }
   289  
   290  func (s *BridgeSuite) TestBridgeNoIfacesDefinedFromFile(c *gc.C) {
   291  	stanzas, err := debinterfaces.ParseSource("testdata/ifupdown-examples", nil, s.expander)
   292  	c.Assert(err, gc.IsNil)
   293  	input := format(stanzas)
   294  	s.checkBridge(input, input, c, map[string]string{"non-existent-interface": "non-existent-bridge"})
   295  }
   296  
   297  func (s *BridgeSuite) TestBridgeAlias(c *gc.C) {
   298  	input := `
   299  auto eth0
   300  iface eth0 inet static
   301      gateway 10.14.0.1
   302      address 10.14.0.102/24
   303  
   304  auto eth0:1
   305  iface eth0:1 inet static
   306      address 1.2.3.5`
   307  
   308  	expected := `
   309  auto eth0
   310  iface eth0 inet manual
   311  
   312  auto br-eth0:1
   313  iface br-eth0:1 inet static
   314      address 1.2.3.5
   315  
   316  auto br-eth0
   317  iface br-eth0 inet static
   318      gateway 10.14.0.1
   319      address 10.14.0.102/24
   320      bridge_ports eth0`
   321  	s.checkBridge(input, expected[1:], c, map[string]string{"eth0": "br-eth0", "eth0:1": "br-eth0:1"})
   322  }
   323  
   324  func (s *BridgeSuite) TestBridgeMultipleInterfaces(c *gc.C) {
   325  	input := `
   326  auto enp1s0f3
   327  iface enp1s0f3 inet static
   328    address 192.168.1.64/24
   329    gateway 192.168.1.254
   330    dns-nameservers 192.168.1.254
   331    dns-search home
   332  
   333  iface enp1s0f3 inet6 dhcp`
   334  
   335  	expected := `
   336  auto enp1s0f3
   337  iface enp1s0f3 inet manual
   338  
   339  iface enp1s0f3 inet6 manual
   340  
   341  auto br-enp1s0f3
   342  iface br-enp1s0f3 inet static
   343      address 192.168.1.64/24
   344      gateway 192.168.1.254
   345      dns-nameservers 192.168.1.254
   346      dns-search home
   347      bridge_ports enp1s0f3
   348  
   349  iface br-enp1s0f3 inet6 dhcp
   350      bridge_ports enp1s0f3`
   351  	s.checkBridge(input, expected[1:], c, map[string]string{"enp1s0f3": "br-enp1s0f3"})
   352  }
   353  
   354  func (s *BridgeSuite) TestSourceStanzaWithRelativeFilenames(c *gc.C) {
   355  	stanzas, err := debinterfaces.Parse("testdata/TestInputSourceStanza/interfaces")
   356  	c.Assert(err, gc.IsNil)
   357  	c.Assert(stanzas, gc.HasLen, 3)
   358  	bridged := debinterfaces.Bridge(stanzas, map[string]string{"eth0": "br-eth0"})
   359  
   360  	expected := `
   361  auto lo
   362  iface lo inet loopback
   363  
   364  auto eth0
   365  iface eth0 inet manual
   366  
   367  auto eth1
   368  iface eth1 inet static
   369      address 192.168.1.64
   370      dns-nameservers 192.168.1.254
   371  
   372  auto eth2
   373  iface eth2 inet manual
   374  
   375  auto br-eth0
   376  iface br-eth0 inet dhcp
   377      bridge_ports eth0`
   378  
   379  	c.Assert(debinterfaces.FormatStanzas(debinterfaces.FlattenStanzas(bridged), 4), gc.Equals, expected[1:])
   380  }
   381  
   382  func (s *BridgeSuite) TestSourceDirectoryStanzaWithRelativeFilenames(c *gc.C) {
   383  	stanzas, err := debinterfaces.Parse("testdata/TestInputSourceDirectoryStanza/interfaces")
   384  	c.Assert(err, gc.IsNil)
   385  	c.Assert(stanzas, gc.HasLen, 3)
   386  
   387  	bridged := debinterfaces.Bridge(stanzas, map[string]string{"eth3": "br-eth3"})
   388  
   389  	expected := `
   390  auto lo
   391  iface lo inet loopback
   392  
   393  auto eth3
   394  iface eth3 inet manual
   395  
   396  auto br-eth3
   397  iface br-eth3 inet static
   398      address 192.168.1.128
   399      dns-nameservers 192.168.1.254
   400      bridge_ports eth3`
   401  
   402  	c.Assert(debinterfaces.FormatStanzas(debinterfaces.FlattenStanzas(bridged), 4), gc.Equals, expected[1:])
   403  }
   404  
   405  func (s *BridgeSuite) TestBridgeInet6Only(c *gc.C) {
   406  	input := `
   407  auto enxe0db55e41d5b
   408  iface enxe0db55e41d5b inet6 static
   409      address 3ffe:1234:5678::1/64
   410      gateway 3ffe:1234:5678::2
   411  `
   412  	expected := `
   413  auto enxe0db55e41d5b
   414  iface enxe0db55e41d5b inet6 manual
   415  
   416  auto br-xe0db55e41d5b
   417  iface br-xe0db55e41d5b inet6 static
   418      address 3ffe:1234:5678::1/64
   419      gateway 3ffe:1234:5678::2
   420      bridge_ports enxe0db55e41d5b`
   421  
   422  	s.checkBridge(input, expected[1:], c, map[string]string{"enxe0db55e41d5b": "br-xe0db55e41d5b"})
   423  }