go.ligato.io/vpp-agent/v3@v3.5.0/tests/e2e/040_bridge_domain_test.go (about) 1 // Copyright (c) 2019 Cisco and/or its affiliates. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at: 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package e2e 16 17 import ( 18 "context" 19 "strconv" 20 "testing" 21 22 . "github.com/onsi/gomega" 23 "github.com/onsi/gomega/types" 24 25 "go.ligato.io/vpp-agent/v3/proto/ligato/kvscheduler" 26 linux_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces" 27 linux_namespace "go.ligato.io/vpp-agent/v3/proto/ligato/linux/namespace" 28 vpp_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces" 29 vpp_l2 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l2" 30 . "go.ligato.io/vpp-agent/v3/tests/e2e/e2etest" 31 ) 32 33 func bridgeDomains(ctx *TestCtx) ([]map[string]string, error) { 34 stdout, err := ctx.ExecVppctl("show", "bridge-domain") 35 if err != nil { 36 return nil, err 37 } 38 return ParseVPPTable(stdout), nil 39 } 40 41 func bdAgeIs(min int) types.GomegaMatcher { 42 if min == 0 { 43 return HaveKeyWithValue("Age(min)", "off") 44 } 45 return HaveKeyWithValue("Age(min)", strconv.Itoa(min)) 46 } 47 48 func bdWithFlooding() types.GomegaMatcher { 49 return And( 50 HaveKeyWithValue("UU-Flood", "flood"), 51 HaveKeyWithValue("Flooding", "on")) 52 } 53 54 func bdWithForwarding() types.GomegaMatcher { 55 return HaveKeyWithValue("U-Forwrd", "on") 56 } 57 58 func bdWithLearning() types.GomegaMatcher { 59 return HaveKeyWithValue("Learning", "on") 60 } 61 62 // connect microservices into the same L2 network segment via bridge domain 63 // and TAP interfaces. 64 func TestBridgeDomainWithTAPs(t *testing.T) { 65 ctx := Setup(t) 66 defer ctx.Teardown() 67 68 const ( 69 vppTap1Name = "vpp-tap1" 70 linuxTap1Name = "linux-tap1" 71 linuxTap1Hostname = "tap" 72 linuxTap1IP = "192.168.1.2" 73 74 vppTap2Name = "vpp-tap2" 75 linuxTap2Name = "linux-tap2" 76 linuxTap2Hostname = "tap" 77 linuxTap2IP = "192.168.1.3" 78 79 vppLoopbackName = "loop1" 80 vppLoopbackIP = "192.168.1.1" 81 82 netMask = "/24" 83 ms1Name = "microservice1" 84 ms2Name = "microservice2" 85 bdName = "my-bd" 86 ) 87 88 vppTap1 := &vpp_interfaces.Interface{ 89 Name: vppTap1Name, 90 Type: vpp_interfaces.Interface_TAP, 91 Enabled: true, 92 Link: &vpp_interfaces.Interface_Tap{ 93 Tap: &vpp_interfaces.TapLink{ 94 Version: 2, 95 ToMicroservice: MsNamePrefix + ms1Name, 96 }, 97 }, 98 } 99 linuxTap1 := &linux_interfaces.Interface{ 100 Name: linuxTap1Name, 101 Type: linux_interfaces.Interface_TAP_TO_VPP, 102 Enabled: true, 103 IpAddresses: []string{linuxTap1IP + netMask}, 104 HostIfName: linuxTap1Hostname, 105 Link: &linux_interfaces.Interface_Tap{ 106 Tap: &linux_interfaces.TapLink{ 107 VppTapIfName: vppTap1Name, 108 }, 109 }, 110 Namespace: &linux_namespace.NetNamespace{ 111 Type: linux_namespace.NetNamespace_MICROSERVICE, 112 Reference: MsNamePrefix + ms1Name, 113 }, 114 } 115 116 vppTap2 := &vpp_interfaces.Interface{ 117 Name: vppTap2Name, 118 Type: vpp_interfaces.Interface_TAP, 119 Enabled: true, 120 Link: &vpp_interfaces.Interface_Tap{ 121 Tap: &vpp_interfaces.TapLink{ 122 Version: 2, 123 ToMicroservice: MsNamePrefix + ms2Name, 124 }, 125 }, 126 } 127 linuxTap2 := &linux_interfaces.Interface{ 128 Name: linuxTap2Name, 129 Type: linux_interfaces.Interface_TAP_TO_VPP, 130 Enabled: true, 131 IpAddresses: []string{linuxTap2IP + netMask}, 132 HostIfName: linuxTap2Hostname, 133 Link: &linux_interfaces.Interface_Tap{ 134 Tap: &linux_interfaces.TapLink{ 135 VppTapIfName: vppTap2Name, 136 }, 137 }, 138 Namespace: &linux_namespace.NetNamespace{ 139 Type: linux_namespace.NetNamespace_MICROSERVICE, 140 Reference: MsNamePrefix + ms2Name, 141 }, 142 } 143 144 vppLoop := &vpp_interfaces.Interface{ 145 Name: vppLoopbackName, 146 Type: vpp_interfaces.Interface_SOFTWARE_LOOPBACK, 147 Enabled: true, 148 IpAddresses: []string{vppLoopbackIP + netMask}, 149 } 150 151 bd := &vpp_l2.BridgeDomain{ 152 Name: bdName, 153 Flood: true, 154 Forward: true, 155 Learn: true, 156 UnknownUnicastFlood: true, 157 Interfaces: []*vpp_l2.BridgeDomain_Interface{ 158 { 159 Name: vppTap1Name, 160 }, 161 { 162 Name: vppTap2Name, 163 }, 164 { 165 Name: vppLoopbackName, 166 SplitHorizonGroup: 1, 167 BridgedVirtualInterface: true, 168 }, 169 }, 170 } 171 172 ctx.StartMicroservice(ms1Name) 173 ctx.StartMicroservice(ms2Name) 174 req := ctx.GenericClient().ChangeRequest() 175 err := req.Update( 176 vppTap1, 177 linuxTap1, 178 vppTap2, 179 linuxTap2, 180 vppLoop, 181 bd, 182 ).Send(context.Background()) 183 ctx.Expect(err).To(BeNil(), "Transaction creating BD with TAPs failed") 184 185 ctx.Expect(ctx.GetValueState(vppLoop)).To(Equal(kvscheduler.ValueState_CONFIGURED), 186 "BD BVI should be configured even before microservices start") 187 ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_CONFIGURED), 188 "TAP attached to a newly started microservice1 should be eventually configured") 189 ctx.Eventually(ctx.GetValueStateClb(vppTap2)).Should(Equal(kvscheduler.ValueState_CONFIGURED), 190 "TAP attached to a newly started microservice2 should be eventually configured") 191 192 if ctx.VppRelease() < "21.01" { // "show bridge-domain" hard to parse in VPP>=21.01 (https://jira.fd.io/browse/VPP-1969) 193 bds, err := bridgeDomains(ctx) 194 ctx.Expect(err).ToNot(HaveOccurred()) 195 ctx.Expect(bds).To(HaveLen(1)) 196 ctx.Expect(bds[0]).To(SatisfyAll( 197 bdAgeIs(0), bdWithFlooding(), bdWithForwarding(), bdWithLearning())) 198 } 199 200 ctx.Expect(ctx.PingFromMs(ms2Name, linuxTap1IP)).To(Succeed()) 201 ctx.Expect(ctx.PingFromMs(ms1Name, linuxTap2IP)).To(Succeed()) 202 ctx.Expect(ctx.PingFromMs(ms1Name, vppLoopbackIP)).To(Succeed()) 203 ctx.Expect(ctx.PingFromMs(ms2Name, vppLoopbackIP)).To(Succeed()) 204 ctx.Expect(ctx.PingFromVPP(linuxTap1IP)).To(Succeed()) 205 ctx.Expect(ctx.PingFromVPP(linuxTap2IP)).To(Succeed()) 206 ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") 207 208 // kill one of the microservices 209 // - "Eventually" is also used with linuxTap1 to wait for retry txn that 210 // will change state from RETRYING to PENDING 211 ctx.StopMicroservice(ms1Name) 212 ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_PENDING), 213 "Without microservice, the associated VPP-TAP should be pending") 214 ctx.Eventually(ctx.GetValueStateClb(linuxTap1)).Should(Equal(kvscheduler.ValueState_PENDING), 215 "Without microservice, the associated LinuxTAP should be pending") 216 ctx.Expect(ctx.GetValueState(vppTap2)).To(Equal(kvscheduler.ValueState_CONFIGURED), 217 "VPP-TAP attached to running microservice is not configured") 218 ctx.Expect(ctx.GetValueState(linuxTap2)).To(Equal(kvscheduler.ValueState_CONFIGURED), 219 "Linux-TAP attached to running microservice is not configured") 220 ctx.Expect(ctx.GetValueState(vppLoop)).To(Equal(kvscheduler.ValueState_CONFIGURED), 221 "BD BVI interface is not configured") 222 ctx.Expect(ctx.GetValueState(bd)).To(Equal(kvscheduler.ValueState_CONFIGURED), 223 "BD is not configured") 224 225 ctx.Expect(ctx.PingFromMs(ms2Name, linuxTap1IP)).ToNot(Succeed()) 226 ctx.Expect(ctx.PingFromMs(ms2Name, vppLoopbackIP)).To(Succeed()) 227 ctx.Expect(ctx.PingFromVPP(linuxTap1IP)).ToNot(Succeed()) 228 ctx.Expect(ctx.PingFromVPP(linuxTap2IP)).To(Succeed()) 229 ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") 230 231 // restart the microservice 232 ctx.StartMicroservice(ms1Name) 233 ctx.Eventually(ctx.GetValueStateClb(vppTap1)).Should(Equal(kvscheduler.ValueState_CONFIGURED), 234 "VPP-TAP attached to a re-started microservice1 should be eventually configured") 235 ctx.Expect(ctx.GetValueState(linuxTap1)).To(Equal(kvscheduler.ValueState_CONFIGURED), 236 "Linux-TAP attached to a re-started microservice1 is not configured") 237 238 // Waiting for TAP interface after restart 239 // See: https://github.com/ligato/vpp-agent/issues/1489 240 ctx.Eventually(ctx.PingFromMsClb(ms2Name, linuxTap1IP), "18s", "2s").Should(Succeed()) 241 ctx.Expect(ctx.PingFromMs(ms1Name, linuxTap2IP)).To(Succeed()) 242 ctx.Expect(ctx.PingFromMs(ms1Name, vppLoopbackIP)).To(Succeed()) 243 ctx.Expect(ctx.PingFromMs(ms2Name, vppLoopbackIP)).To(Succeed()) 244 ctx.Expect(ctx.PingFromVPP(linuxTap1IP)).To(Succeed()) 245 ctx.Expect(ctx.PingFromVPP(linuxTap2IP)).To(Succeed()) 246 ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") 247 248 // change bridge domain config to trigger re-creation 249 bd.MacAge = 10 250 req = ctx.GenericClient().ChangeRequest() 251 err = req.Update( 252 bd, 253 ).Send(context.Background()) 254 ctx.Expect(err).ToNot(HaveOccurred(), "Transaction updating BD failed") 255 256 ctx.Expect(ctx.PingFromMs(ms2Name, linuxTap1IP)).To(Succeed()) 257 ctx.Expect(ctx.PingFromMs(ms1Name, linuxTap2IP)).To(Succeed()) 258 ctx.Expect(ctx.PingFromMs(ms1Name, vppLoopbackIP)).To(Succeed()) 259 ctx.Expect(ctx.PingFromMs(ms2Name, vppLoopbackIP)).To(Succeed()) 260 ctx.Expect(ctx.PingFromVPP(linuxTap1IP)).To(Succeed()) 261 ctx.Expect(ctx.PingFromVPP(linuxTap2IP)).To(Succeed()) 262 ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") 263 264 if ctx.VppRelease() < "21.01" { // "show bridge-domain" hard to parse in VPP>=21.01 (https://jira.fd.io/browse/VPP-1969) 265 bds, err := bridgeDomains(ctx) 266 ctx.Expect(err).ToNot(HaveOccurred()) 267 ctx.Expect(bds).To(HaveLen(1)) 268 ctx.Expect(bds[0]).To(SatisfyAll( 269 bdAgeIs(10), bdWithFlooding(), bdWithForwarding(), bdWithLearning())) 270 } 271 } 272 273 // connect microservices into the same L2 network segment via bridge domain 274 // and AF-PACKET+VETH interfaces. 275 func TestBridgeDomainWithAfPackets(t *testing.T) { 276 ctx := Setup(t) 277 defer ctx.Teardown() 278 279 const ( 280 afPacket1Name = "vpp-afpacket1" 281 veth1AName = "vpp-veth-1a" 282 veth1BName = "vpp-veth-1b" 283 veth1AHostname = "veth1a" 284 veth1BHostname = "veth1b" 285 veth1IP = "192.168.1.2" 286 287 afPacket2Name = "vpp-afpacket2" 288 veth2AName = "vpp-veth-2a" 289 veth2BName = "vpp-veth-2b" 290 veth2AHostname = "veth2a" 291 veth2BHostname = "veth2b" 292 veth2IP = "192.168.1.3" 293 294 vppLoopbackName = "loop1" 295 vppLoopbackIP = "192.168.1.1" 296 297 netMask = "/24" 298 ms1Name = "microservice1" 299 ms2Name = "microservice2" 300 bdName = "my-bd" 301 ) 302 303 afPacket1 := &vpp_interfaces.Interface{ 304 Name: afPacket1Name, 305 Type: vpp_interfaces.Interface_AF_PACKET, 306 Enabled: true, 307 Link: &vpp_interfaces.Interface_Afpacket{ 308 Afpacket: &vpp_interfaces.AfpacketLink{ 309 HostIfName: veth1BHostname, 310 }, 311 }, 312 } 313 314 veth1a := &linux_interfaces.Interface{ 315 Name: veth1AName, 316 Type: linux_interfaces.Interface_VETH, 317 Enabled: true, 318 HostIfName: veth1AHostname, 319 IpAddresses: []string{veth1IP + netMask}, 320 Link: &linux_interfaces.Interface_Veth{ 321 Veth: &linux_interfaces.VethLink{ 322 PeerIfName: veth1BName, 323 }, 324 }, 325 Namespace: &linux_namespace.NetNamespace{ 326 Type: linux_namespace.NetNamespace_MICROSERVICE, 327 Reference: MsNamePrefix + ms1Name, 328 }, 329 } 330 331 veth1b := &linux_interfaces.Interface{ 332 Name: veth1BName, 333 Type: linux_interfaces.Interface_VETH, 334 Enabled: true, 335 HostIfName: veth1BHostname, 336 Link: &linux_interfaces.Interface_Veth{ 337 Veth: &linux_interfaces.VethLink{ 338 PeerIfName: veth1AName, 339 }, 340 }, 341 } 342 343 afPacket2 := &vpp_interfaces.Interface{ 344 Name: afPacket2Name, 345 Type: vpp_interfaces.Interface_AF_PACKET, 346 Enabled: true, 347 Link: &vpp_interfaces.Interface_Afpacket{ 348 Afpacket: &vpp_interfaces.AfpacketLink{ 349 HostIfName: veth2BHostname, 350 }, 351 }, 352 } 353 354 veth2a := &linux_interfaces.Interface{ 355 Name: veth2AName, 356 Type: linux_interfaces.Interface_VETH, 357 Enabled: true, 358 HostIfName: veth2AHostname, 359 IpAddresses: []string{veth2IP + netMask}, 360 Link: &linux_interfaces.Interface_Veth{ 361 Veth: &linux_interfaces.VethLink{ 362 PeerIfName: veth2BName, 363 }, 364 }, 365 Namespace: &linux_namespace.NetNamespace{ 366 Type: linux_namespace.NetNamespace_MICROSERVICE, 367 Reference: MsNamePrefix + ms2Name, 368 }, 369 } 370 371 veth2b := &linux_interfaces.Interface{ 372 Name: veth2BName, 373 Type: linux_interfaces.Interface_VETH, 374 Enabled: true, 375 HostIfName: veth2BHostname, 376 Link: &linux_interfaces.Interface_Veth{ 377 Veth: &linux_interfaces.VethLink{ 378 PeerIfName: veth2AName, 379 }, 380 }, 381 } 382 383 vppLoop := &vpp_interfaces.Interface{ 384 Name: vppLoopbackName, 385 Type: vpp_interfaces.Interface_SOFTWARE_LOOPBACK, 386 Enabled: true, 387 IpAddresses: []string{vppLoopbackIP + netMask}, 388 } 389 390 bd := &vpp_l2.BridgeDomain{ 391 Name: bdName, 392 Flood: true, 393 Forward: true, 394 Learn: true, 395 UnknownUnicastFlood: true, 396 Interfaces: []*vpp_l2.BridgeDomain_Interface{ 397 { 398 Name: afPacket1Name, 399 }, 400 { 401 Name: afPacket2Name, 402 }, 403 { 404 Name: vppLoopbackName, 405 SplitHorizonGroup: 1, 406 BridgedVirtualInterface: true, 407 }, 408 }, 409 } 410 411 ctx.StartMicroservice(ms1Name) 412 ctx.StartMicroservice(ms2Name) 413 req := ctx.GenericClient().ChangeRequest() 414 err := req.Update( 415 afPacket1, 416 veth1a, veth1b, 417 afPacket2, 418 veth2a, veth2b, 419 vppLoop, 420 bd, 421 ).Send(context.Background()) 422 ctx.Expect(err).ToNot(HaveOccurred(), "Transaction creating BD with AF-PACKETs failed") 423 424 ctx.Expect(ctx.GetValueState(vppLoop)).To(Equal(kvscheduler.ValueState_CONFIGURED), 425 "BD BVI should be configured even before microservices start") 426 ctx.Eventually(ctx.GetValueStateClb(afPacket1)).Should(Equal(kvscheduler.ValueState_CONFIGURED), 427 "AF-PACKET attached to a newly started microservice1 should be eventually configured") 428 ctx.Eventually(ctx.GetValueStateClb(afPacket2)).Should(Equal(kvscheduler.ValueState_CONFIGURED), 429 "AF-PACKET attached to a newly started microservice2 should be eventually configured") 430 431 if ctx.VppRelease() < "21.01" { // "show bridge-domain" hard to parse in VPP>=21.01 (https://jira.fd.io/browse/VPP-1969) 432 bds, err := bridgeDomains(ctx) 433 ctx.Expect(err).ToNot(HaveOccurred()) 434 ctx.Expect(bds).To(HaveLen(1)) 435 ctx.Expect(bds[0]).To(SatisfyAll( 436 bdAgeIs(0), bdWithFlooding(), bdWithForwarding(), bdWithLearning())) 437 } 438 439 ctx.Expect(ctx.PingFromMs(ms2Name, veth1IP)).To(Succeed()) 440 ctx.Expect(ctx.PingFromMs(ms1Name, veth2IP)).To(Succeed()) 441 ctx.Expect(ctx.PingFromMs(ms1Name, vppLoopbackIP)).To(Succeed()) 442 ctx.Expect(ctx.PingFromMs(ms2Name, vppLoopbackIP)).To(Succeed()) 443 ctx.Expect(ctx.PingFromVPP(veth1IP)).To(Succeed()) 444 ctx.Expect(ctx.PingFromVPP(veth2IP)).To(Succeed()) 445 ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") 446 447 // kill one of the microservices 448 // - both AF-PACKET and VETH use separate "Eventually" assertion since 449 // they react to different SB notifications 450 ctx.StopMicroservice(ms1Name) 451 ctx.Eventually(ctx.GetValueStateClb(afPacket1)).Should(Equal(kvscheduler.ValueState_PENDING), 452 "Without microservice, the associated AF-PACKET should be pending") 453 ctx.Eventually(ctx.GetValueStateClb(veth1a)).Should(Equal(kvscheduler.ValueState_PENDING), 454 "Without microservice, the associated VETH should be pending") 455 ctx.Expect(ctx.GetValueState(veth1b)).To(Equal(kvscheduler.ValueState_PENDING), 456 "Without microservice, the associated VETH should be pending") 457 ctx.Expect(ctx.GetValueState(afPacket2)).To(Equal(kvscheduler.ValueState_CONFIGURED), 458 "AF-PACKET attached to running microservice is not configured") 459 ctx.Expect(ctx.GetValueState(veth2a)).To(Equal(kvscheduler.ValueState_CONFIGURED), 460 "VETH attached to running microservice is not configured") 461 ctx.Expect(ctx.GetValueState(veth2b)).To(Equal(kvscheduler.ValueState_CONFIGURED), 462 "VETH attached to running microservice is not configured") 463 ctx.Expect(ctx.GetValueState(vppLoop)).To(Equal(kvscheduler.ValueState_CONFIGURED), 464 "BD BVI interface is not configured") 465 ctx.Expect(ctx.GetValueState(bd)).To(Equal(kvscheduler.ValueState_CONFIGURED), 466 "BD is not configured") 467 468 ctx.Expect(ctx.PingFromMs(ms2Name, veth1IP)).ToNot(Succeed()) 469 ctx.Expect(ctx.PingFromMs(ms2Name, vppLoopbackIP)).To(Succeed()) 470 ctx.Expect(ctx.PingFromVPP(veth1IP)).ToNot(Succeed()) 471 ctx.Expect(ctx.PingFromVPP(veth2IP)).To(Succeed()) 472 ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") 473 474 // restart the microservice 475 ctx.StartMicroservice(ms1Name) 476 ctx.Eventually(ctx.GetValueStateClb(afPacket1)).Should(Equal(kvscheduler.ValueState_CONFIGURED), 477 "AF-PACKET attached to a re-started microservice1 should be eventually configured") 478 ctx.Expect(ctx.GetValueState(veth1a)).To(Equal(kvscheduler.ValueState_CONFIGURED), 479 "VETH attached to re-started microservice1 is not configured") 480 ctx.Expect(ctx.GetValueState(veth1b)).To(Equal(kvscheduler.ValueState_CONFIGURED), 481 "VETH attached to re-started microservice1 is not configured") 482 483 // Waiting for AF-PACKET interface after restart 484 // See: https://github.com/ligato/vpp-agent/issues/1489 485 ctx.Eventually(ctx.PingFromMsClb(ms2Name, veth1IP), "18s", "2s").Should(Succeed()) 486 ctx.Expect(ctx.PingFromMs(ms1Name, veth2IP)).To(Succeed()) 487 ctx.Expect(ctx.PingFromMs(ms1Name, vppLoopbackIP)).To(Succeed()) 488 ctx.Expect(ctx.PingFromMs(ms2Name, vppLoopbackIP)).To(Succeed()) 489 ctx.Expect(ctx.PingFromVPP(veth1IP)).To(Succeed()) 490 ctx.Expect(ctx.PingFromVPP(veth2IP)).To(Succeed()) 491 ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") 492 493 // change bridge domain config to trigger re-creation 494 bd.MacAge = 10 495 req = ctx.GenericClient().ChangeRequest() 496 err = req.Update( 497 bd, 498 ).Send(context.Background()) 499 ctx.Expect(err).ToNot(HaveOccurred(), "Transaction updating BD failed") 500 501 if ctx.VppRelease() < "21.01" { // "show bridge-domain" hard to parse in VPP>=21.01 (https://jira.fd.io/browse/VPP-1969) 502 bds, err := bridgeDomains(ctx) 503 ctx.Expect(err).ToNot(HaveOccurred()) 504 ctx.Expect(bds).To(HaveLen(1)) 505 ctx.Expect(bds[0]).To(SatisfyAll( 506 bdAgeIs(10), bdWithFlooding(), bdWithForwarding(), bdWithLearning())) 507 } 508 509 ctx.Expect(ctx.PingFromMs(ms2Name, veth1IP)).To(Succeed()) 510 ctx.Expect(ctx.PingFromMs(ms1Name, veth2IP)).To(Succeed()) 511 ctx.Expect(ctx.PingFromMs(ms1Name, vppLoopbackIP)).To(Succeed()) 512 ctx.Expect(ctx.PingFromMs(ms2Name, vppLoopbackIP)).To(Succeed()) 513 ctx.Expect(ctx.PingFromVPP(veth1IP)).To(Succeed()) 514 ctx.Expect(ctx.PingFromVPP(veth2IP)).To(Succeed()) 515 ctx.Expect(ctx.AgentInSync()).To(BeTrue(), "Agent is not in-sync") 516 }