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 }