go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/srplugin/vppcalls/vpp2106/srv6_test.go (about) 1 // Copyright (c) 2021 Bell Canada, Pantheon Technologies 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 vpp2106_test 16 17 import ( 18 "fmt" 19 "net" 20 "testing" 21 22 . "github.com/onsi/gomega" 23 govppapi "go.fd.io/govpp/api" 24 "go.ligato.io/cn-infra/v2/logging/logrus" 25 26 vpp_ifs "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/interface" 27 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/interface_types" 28 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/ip_types" 29 vpp_sr "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/sr" 30 vpp_vpe "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/vpe" 31 "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/ifaceidx" 32 "go.ligato.io/vpp-agent/v3/plugins/vpp/srplugin/vppcalls" 33 vpp2106 "go.ligato.io/vpp-agent/v3/plugins/vpp/srplugin/vppcalls/vpp2106" 34 "go.ligato.io/vpp-agent/v3/plugins/vpp/vppmock" 35 srv6 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/srv6" 36 ) 37 38 const ( 39 ifaceA = "A" 40 ifaceB = "B" 41 ifaceBOutOfidxs = "B" 42 swIndexA = 1 43 invalidIPAddress = "XYZ" 44 memif1 = "memif1/1" 45 memif2 = "memif2/2" 46 ) 47 48 var ( 49 sidA = sid("A::") 50 sidB = sid("B::") 51 sidC = sid("C::") 52 nextHop = net.ParseIP("B::").To16() 53 nextHopIPv4 = net.ParseIP("1.2.3.4").To4() 54 ) 55 56 // TODO add tests for new nhAddr4 field in end behaviours 57 // TestAddLocalSID tests all cases for method AddLocalSID 58 func TestAddLocalSID(t *testing.T) { 59 // Prepare different cases 60 cases := []struct { 61 Name string 62 FailInVPP bool 63 FailInVPPDump bool 64 ExpectFailure bool 65 cliMode bool // sr-proxy can be se only using CLI -> using VPE binary API to send VPP CLI commands 66 MockInterfaceDump []govppapi.Message 67 Input *srv6.LocalSID 68 Expected govppapi.Message 69 }{ 70 { 71 Name: "addition with end behaviour", 72 Input: &srv6.LocalSID{ 73 Sid: sidToStr(sidA), 74 InstallationVrfId: 10, 75 EndFunction: &srv6.LocalSID_BaseEndFunction{ 76 BaseEndFunction: &srv6.LocalSID_End{ 77 Psp: true, 78 }, 79 }, 80 }, 81 Expected: &vpp_sr.SrLocalsidAddDel{ 82 IsDel: false, 83 Localsid: sidA, 84 Behavior: vpp2106.BehaviorEnd, 85 FibTable: 10, // installationVrfId 86 EndPsp: true, 87 }, 88 }, 89 { 90 Name: "addition with endX behaviour (ipv6 next hop address)", 91 Input: &srv6.LocalSID{ 92 Sid: sidToStr(sidA), 93 InstallationVrfId: 10, 94 EndFunction: &srv6.LocalSID_EndFunctionX{ 95 EndFunctionX: &srv6.LocalSID_EndX{ 96 Psp: true, 97 NextHop: nextHop.String(), 98 OutgoingInterface: ifaceA, 99 }, 100 }, 101 }, 102 Expected: &vpp_sr.SrLocalsidAddDel{ 103 IsDel: false, 104 Localsid: sidA, 105 Behavior: vpp2106.BehaviorX, 106 FibTable: 10, // installationVrfId 107 EndPsp: true, 108 SwIfIndex: interface_types.InterfaceIndex(swIndexA), 109 NhAddr: toAddress(nextHop.String()), 110 }, 111 }, 112 { 113 Name: "addition with endX behaviour (ipv4 next hop address)", 114 Input: &srv6.LocalSID{ 115 Sid: sidToStr(sidA), 116 InstallationVrfId: 10, 117 EndFunction: &srv6.LocalSID_EndFunctionX{ 118 EndFunctionX: &srv6.LocalSID_EndX{ 119 Psp: true, 120 NextHop: nextHopIPv4.String(), 121 OutgoingInterface: ifaceA, 122 }, 123 }, 124 }, 125 Expected: &vpp_sr.SrLocalsidAddDel{ 126 IsDel: false, 127 Localsid: sidA, 128 Behavior: vpp2106.BehaviorX, 129 FibTable: 10, // installationVrfId 130 EndPsp: true, 131 SwIfIndex: swIndexA, 132 NhAddr: toAddress(nextHopIPv4.String()), 133 }, 134 }, 135 { 136 Name: "addition with endT behaviour", 137 Input: &srv6.LocalSID{ 138 Sid: sidToStr(sidA), 139 InstallationVrfId: 10, 140 EndFunction: &srv6.LocalSID_EndFunctionT{ 141 EndFunctionT: &srv6.LocalSID_EndT{ 142 Psp: true, 143 VrfId: 11, 144 }, 145 }, 146 }, 147 Expected: &vpp_sr.SrLocalsidAddDel{ 148 IsDel: false, 149 Localsid: sidA, 150 Behavior: vpp2106.BehaviorT, 151 FibTable: 10, // installationVrfId 152 SwIfIndex: 11, 153 EndPsp: true, 154 }, 155 }, 156 { 157 Name: "addition with endDX2 behaviour", 158 Input: &srv6.LocalSID{ 159 Sid: sidToStr(sidA), 160 InstallationVrfId: 10, 161 EndFunction: &srv6.LocalSID_EndFunctionDx2{ 162 EndFunctionDx2: &srv6.LocalSID_EndDX2{ 163 VlanTag: 1, 164 OutgoingInterface: ifaceA, 165 }, 166 }, 167 }, 168 Expected: &vpp_sr.SrLocalsidAddDel{ 169 IsDel: false, 170 Localsid: sidA, 171 Behavior: vpp2106.BehaviorDX2, 172 FibTable: 10, // installationVrfId 173 EndPsp: false, 174 VlanIndex: 1, 175 SwIfIndex: swIndexA, 176 }, 177 }, 178 { 179 Name: "addition with endDX4 behaviour", 180 Input: &srv6.LocalSID{ 181 Sid: sidToStr(sidA), 182 InstallationVrfId: 10, 183 EndFunction: &srv6.LocalSID_EndFunctionDx4{ 184 EndFunctionDx4: &srv6.LocalSID_EndDX4{ 185 NextHop: nextHopIPv4.String(), 186 OutgoingInterface: ifaceA, 187 }, 188 }, 189 }, 190 Expected: &vpp_sr.SrLocalsidAddDel{ 191 IsDel: false, 192 Localsid: sidA, 193 Behavior: vpp2106.BehaviorDX4, 194 FibTable: 10, // installationVrfId 195 EndPsp: false, 196 SwIfIndex: swIndexA, 197 NhAddr: toAddress(nextHopIPv4.String()), 198 }, 199 }, 200 { 201 Name: "addition with endDX6 behaviour", 202 Input: &srv6.LocalSID{ 203 Sid: sidToStr(sidA), 204 InstallationVrfId: 10, 205 EndFunction: &srv6.LocalSID_EndFunctionDx6{ 206 EndFunctionDx6: &srv6.LocalSID_EndDX6{ 207 NextHop: nextHop.String(), 208 OutgoingInterface: ifaceA, 209 }, 210 }, 211 }, 212 Expected: &vpp_sr.SrLocalsidAddDel{ 213 IsDel: false, 214 Localsid: sidA, 215 Behavior: vpp2106.BehaviorDX6, 216 FibTable: 10, // installationVrfId 217 EndPsp: false, 218 SwIfIndex: swIndexA, 219 NhAddr: toAddress(nextHop.String()), 220 }, 221 }, 222 { 223 Name: "addition with endDT4 behaviour", 224 Input: &srv6.LocalSID{ 225 Sid: sidToStr(sidA), 226 InstallationVrfId: 10, 227 EndFunction: &srv6.LocalSID_EndFunctionDt4{ 228 EndFunctionDt4: &srv6.LocalSID_EndDT4{ 229 VrfId: 5, 230 }, 231 }, 232 }, 233 Expected: &vpp_sr.SrLocalsidAddDel{ 234 IsDel: false, 235 Localsid: sidA, 236 Behavior: vpp2106.BehaviorDT4, 237 FibTable: 10, // installationVrfId 238 SwIfIndex: 5, 239 EndPsp: false, 240 }, 241 }, 242 { 243 Name: "addition with endDT6 behaviour", 244 Input: &srv6.LocalSID{ 245 Sid: sidToStr(sidA), 246 InstallationVrfId: 10, 247 EndFunction: &srv6.LocalSID_EndFunctionDt6{ 248 EndFunctionDt6: &srv6.LocalSID_EndDT6{ 249 VrfId: 5, 250 }, 251 }, 252 }, 253 Expected: &vpp_sr.SrLocalsidAddDel{ 254 IsDel: false, 255 Localsid: sidA, 256 Behavior: vpp2106.BehaviorDT6, 257 FibTable: 10, // installationVrfId 258 SwIfIndex: 5, 259 EndPsp: false, 260 }, 261 }, 262 { 263 Name: "addition with endAD behaviour (+ memif interface name translation)", 264 cliMode: true, 265 MockInterfaceDump: []govppapi.Message{ 266 &vpp_ifs.SwInterfaceDetails{Tag: ifaceA, InterfaceName: memif1}, 267 &vpp_ifs.SwInterfaceDetails{Tag: ifaceB, InterfaceName: memif2}, 268 }, 269 Input: &srv6.LocalSID{ 270 Sid: sidToStr(sidA), 271 InstallationVrfId: 10, 272 EndFunction: &srv6.LocalSID_EndFunctionAd{ 273 EndFunctionAd: &srv6.LocalSID_EndAD{ 274 L3ServiceAddress: nextHopIPv4.String(), 275 OutgoingInterface: ifaceA, 276 IncomingInterface: ifaceB, 277 }, 278 }, 279 }, 280 Expected: &vpp_vpe.CliInband{ 281 Cmd: fmt.Sprintf("sr localsid address %v fib-table 10 behavior end.ad nh %v oif %v iif %v", sidToStr(sidA), nextHopIPv4.String(), memif1, memif2), 282 }, 283 }, 284 { 285 Name: "addition with endAD behaviour for L2 sr-unaware service", 286 cliMode: true, 287 MockInterfaceDump: []govppapi.Message{ 288 &vpp_ifs.SwInterfaceDetails{Tag: ifaceA, InterfaceName: memif1}, 289 &vpp_ifs.SwInterfaceDetails{Tag: ifaceB, InterfaceName: memif2}, 290 }, 291 Input: &srv6.LocalSID{ 292 Sid: sidToStr(sidA), 293 InstallationVrfId: 10, 294 EndFunction: &srv6.LocalSID_EndFunctionAd{ 295 EndFunctionAd: &srv6.LocalSID_EndAD{ // missing L3ServiceAddress means it is L2 service 296 OutgoingInterface: ifaceA, 297 IncomingInterface: ifaceB, 298 }, 299 }, 300 }, 301 Expected: &vpp_vpe.CliInband{ 302 Cmd: fmt.Sprintf("sr localsid address %v fib-table 10 behavior end.ad oif %v iif %v", sidToStr(sidA), memif1, memif2), 303 }, 304 }, 305 { 306 Name: "etcd-to-vpp-internal interface name translation for endAD behaviour (local and tap kind of interfaces)", 307 cliMode: true, 308 MockInterfaceDump: []govppapi.Message{ 309 &vpp_ifs.SwInterfaceDetails{Tag: ifaceA, InterfaceName: "local0"}, 310 &vpp_ifs.SwInterfaceDetails{Tag: ifaceB, InterfaceName: "tap0"}, 311 }, 312 Input: &srv6.LocalSID{ 313 Sid: sidToStr(sidA), 314 InstallationVrfId: 10, 315 EndFunction: &srv6.LocalSID_EndFunctionAd{ 316 EndFunctionAd: &srv6.LocalSID_EndAD{ 317 L3ServiceAddress: nextHopIPv4.String(), 318 OutgoingInterface: ifaceA, 319 IncomingInterface: ifaceB, 320 }, 321 }, 322 }, 323 Expected: &vpp_vpe.CliInband{ 324 Cmd: fmt.Sprintf("sr localsid address %v fib-table 10 behavior end.ad nh %v oif %v iif %v", sidToStr(sidA), nextHopIPv4.String(), "local0", "tap0"), 325 }, 326 }, 327 { 328 Name: "etcd-to-vpp-internal interface name translation for endAD behaviour (host and vxlan kind of interfaces)", 329 cliMode: true, 330 MockInterfaceDump: []govppapi.Message{ 331 &vpp_ifs.SwInterfaceDetails{Tag: ifaceA, InterfaceName: "host0"}, 332 &vpp_ifs.SwInterfaceDetails{Tag: ifaceB, InterfaceName: "vxlan0"}, 333 }, 334 Input: &srv6.LocalSID{ 335 Sid: sidToStr(sidA), 336 InstallationVrfId: 10, 337 EndFunction: &srv6.LocalSID_EndFunctionAd{ 338 EndFunctionAd: &srv6.LocalSID_EndAD{ 339 L3ServiceAddress: nextHopIPv4.String(), 340 OutgoingInterface: ifaceA, 341 IncomingInterface: ifaceB, 342 }, 343 }, 344 }, 345 Expected: &vpp_vpe.CliInband{ 346 Cmd: fmt.Sprintf("sr localsid address %v fib-table 10 behavior end.ad nh %v oif %v iif %v", sidToStr(sidA), nextHopIPv4.String(), "host0", "vxlan0"), 347 }, 348 }, 349 { 350 Name: "etcd-to-vpp-internal interface name translation for endAD behaviour (ipsec and vmxnet3 kind of interfaces)", 351 cliMode: true, 352 MockInterfaceDump: []govppapi.Message{ 353 &vpp_ifs.SwInterfaceDetails{Tag: ifaceA, InterfaceName: "ipsec0"}, 354 &vpp_ifs.SwInterfaceDetails{Tag: ifaceB, InterfaceName: "vmxnet3-0"}, 355 }, 356 Input: &srv6.LocalSID{ 357 Sid: sidToStr(sidA), 358 InstallationVrfId: 10, 359 EndFunction: &srv6.LocalSID_EndFunctionAd{ 360 EndFunctionAd: &srv6.LocalSID_EndAD{ 361 L3ServiceAddress: nextHopIPv4.String(), 362 OutgoingInterface: ifaceA, 363 IncomingInterface: ifaceB, 364 }, 365 }, 366 }, 367 Expected: &vpp_vpe.CliInband{ 368 Cmd: fmt.Sprintf("sr localsid address %v fib-table 10 behavior end.ad nh %v oif %v iif %v", sidToStr(sidA), nextHopIPv4.String(), "ipsec0", "vmxnet3-0"), 369 }, 370 }, 371 { 372 Name: "etcd-to-vpp-internal interface name translation for endAD behaviour (loop and unknown kind of interfaces)", 373 cliMode: true, 374 MockInterfaceDump: []govppapi.Message{ 375 &vpp_ifs.SwInterfaceDetails{Tag: ifaceA, InterfaceName: "loop0"}, 376 &vpp_ifs.SwInterfaceDetails{Tag: ifaceB, InterfaceName: "unknown0"}, 377 }, 378 Input: &srv6.LocalSID{ 379 Sid: sidToStr(sidA), 380 InstallationVrfId: 10, 381 EndFunction: &srv6.LocalSID_EndFunctionAd{ 382 EndFunctionAd: &srv6.LocalSID_EndAD{ 383 L3ServiceAddress: nextHopIPv4.String(), 384 OutgoingInterface: ifaceA, 385 IncomingInterface: "unknown0", // interface name is taken from vpp internal name 386 }, 387 }, 388 }, 389 Expected: &vpp_vpe.CliInband{ 390 Cmd: fmt.Sprintf("sr localsid address %v fib-table 10 behavior end.ad nh %v oif %v iif %v", sidToStr(sidA), nextHopIPv4.String(), "loop0", "unknown0"), 391 }, 392 }, 393 { 394 Name: "fail due to missing end function", 395 ExpectFailure: true, 396 Input: &srv6.LocalSID{ 397 Sid: sidToStr(sidA), 398 InstallationVrfId: 0, 399 }, 400 }, 401 { 402 Name: "failure propagation from VPP (doing main VPP call)", 403 FailInVPP: true, 404 ExpectFailure: true, 405 Input: &srv6.LocalSID{ 406 Sid: sidToStr(sidA), 407 InstallationVrfId: 0, 408 EndFunction: &srv6.LocalSID_BaseEndFunction{ 409 BaseEndFunction: &srv6.LocalSID_End{ 410 Psp: true, 411 }, 412 }, 413 }, 414 }, 415 { 416 Name: "failure propagation from VPP (doing main VPP call) for SR-proxy (CLI using VPE binary API)", 417 FailInVPP: true, 418 ExpectFailure: true, 419 cliMode: true, 420 MockInterfaceDump: []govppapi.Message{ 421 &vpp_ifs.SwInterfaceDetails{Tag: ifaceA, InterfaceName: memif1}, 422 &vpp_ifs.SwInterfaceDetails{Tag: ifaceB, InterfaceName: memif2}, 423 }, 424 Input: &srv6.LocalSID{ 425 Sid: sidToStr(sidA), 426 InstallationVrfId: 10, 427 EndFunction: &srv6.LocalSID_EndFunctionAd{ 428 EndFunctionAd: &srv6.LocalSID_EndAD{ 429 L3ServiceAddress: nextHopIPv4.String(), 430 OutgoingInterface: ifaceA, 431 IncomingInterface: ifaceB, 432 }, 433 }, 434 }, 435 }, 436 { 437 Name: "failure propagation from VPP Dump call", 438 FailInVPPDump: true, 439 ExpectFailure: true, 440 cliMode: true, 441 Input: &srv6.LocalSID{ 442 Sid: sidToStr(sidA), 443 InstallationVrfId: 10, 444 EndFunction: &srv6.LocalSID_EndFunctionAd{ 445 EndFunctionAd: &srv6.LocalSID_EndAD{ 446 L3ServiceAddress: nextHopIPv4.String(), 447 OutgoingInterface: ifaceA, 448 IncomingInterface: ifaceB, 449 }, 450 }, 451 }, 452 }, 453 { 454 Name: "missing SR-proxy outgoing interface in VPP interface dump", 455 ExpectFailure: true, 456 cliMode: true, 457 MockInterfaceDump: []govppapi.Message{ 458 &vpp_ifs.SwInterfaceDetails{Tag: ifaceB, InterfaceName: memif2}, 459 }, 460 Input: &srv6.LocalSID{ 461 Sid: sidToStr(sidA), 462 InstallationVrfId: 10, 463 EndFunction: &srv6.LocalSID_EndFunctionAd{ 464 EndFunctionAd: &srv6.LocalSID_EndAD{ 465 L3ServiceAddress: nextHopIPv4.String(), 466 OutgoingInterface: ifaceA, 467 IncomingInterface: ifaceB, 468 }, 469 }, 470 }, 471 }, 472 { 473 Name: "missing SR-proxy incoming interface in VPP interface dump", 474 ExpectFailure: true, 475 cliMode: true, 476 MockInterfaceDump: []govppapi.Message{ 477 &vpp_ifs.SwInterfaceDetails{Tag: ifaceA, InterfaceName: memif1}, 478 }, 479 Input: &srv6.LocalSID{ 480 Sid: sidToStr(sidA), 481 InstallationVrfId: 10, 482 EndFunction: &srv6.LocalSID_EndFunctionAd{ 483 EndFunctionAd: &srv6.LocalSID_EndAD{ 484 L3ServiceAddress: nextHopIPv4.String(), 485 OutgoingInterface: ifaceA, 486 IncomingInterface: ifaceB, 487 }, 488 }, 489 }, 490 }, 491 { 492 Name: "missing interface in swIndexes (addition with endX behaviour)", 493 ExpectFailure: true, 494 Input: &srv6.LocalSID{ 495 Sid: sidToStr(sidA), 496 InstallationVrfId: 10, 497 EndFunction: &srv6.LocalSID_EndFunctionX{ 498 EndFunctionX: &srv6.LocalSID_EndX{ 499 Psp: true, 500 NextHop: nextHop.String(), 501 OutgoingInterface: ifaceBOutOfidxs, 502 }, 503 }, 504 }, 505 }, 506 { 507 Name: "invalid IP address (addition with endX behaviour)", 508 ExpectFailure: true, 509 Input: &srv6.LocalSID{ 510 InstallationVrfId: 10, 511 EndFunction: &srv6.LocalSID_EndFunctionX{ 512 EndFunctionX: &srv6.LocalSID_EndX{ 513 Psp: true, 514 NextHop: invalidIPAddress, 515 OutgoingInterface: ifaceA, 516 }, 517 }, 518 }, 519 }, 520 { 521 Name: "missing interface in swIndexes (addition with endDX2 behaviour)", 522 ExpectFailure: true, 523 Input: &srv6.LocalSID{ 524 Sid: sidToStr(sidA), 525 InstallationVrfId: 10, 526 EndFunction: &srv6.LocalSID_EndFunctionDx2{ 527 EndFunctionDx2: &srv6.LocalSID_EndDX2{ 528 VlanTag: 1, 529 OutgoingInterface: ifaceBOutOfidxs, 530 }, 531 }, 532 }, 533 }, 534 { 535 Name: "missing interface in swIndexes (addition with endDX4 behaviour)", 536 ExpectFailure: true, 537 Input: &srv6.LocalSID{ 538 Sid: sidToStr(sidA), 539 InstallationVrfId: 10, 540 EndFunction: &srv6.LocalSID_EndFunctionDx4{ 541 EndFunctionDx4: &srv6.LocalSID_EndDX4{ 542 NextHop: nextHopIPv4.String(), 543 OutgoingInterface: ifaceBOutOfidxs, 544 }, 545 }, 546 }, 547 }, 548 { 549 Name: "invalid IP address (addition with endDX4 behaviour)", 550 ExpectFailure: true, 551 Input: &srv6.LocalSID{ 552 Sid: sidToStr(sidA), 553 InstallationVrfId: 10, 554 EndFunction: &srv6.LocalSID_EndFunctionDx4{ 555 EndFunctionDx4: &srv6.LocalSID_EndDX4{ 556 NextHop: invalidIPAddress, 557 OutgoingInterface: ifaceA, 558 }, 559 }, 560 }, 561 }, 562 { 563 Name: "rejection of IPv6 addresses (addition with endDX4 behaviour)", 564 ExpectFailure: true, 565 Input: &srv6.LocalSID{ 566 Sid: sidToStr(sidA), 567 InstallationVrfId: 10, 568 EndFunction: &srv6.LocalSID_EndFunctionDx4{ 569 EndFunctionDx4: &srv6.LocalSID_EndDX4{ 570 NextHop: nextHop.String(), 571 OutgoingInterface: ifaceA, 572 }, 573 }, 574 }, 575 }, 576 { 577 Name: "missing interface in swIndexes (addition with endDX6 behaviour)", 578 ExpectFailure: true, 579 Input: &srv6.LocalSID{ 580 Sid: sidToStr(sidA), 581 InstallationVrfId: 10, 582 EndFunction: &srv6.LocalSID_EndFunctionDx6{ 583 EndFunctionDx6: &srv6.LocalSID_EndDX6{ 584 NextHop: nextHop.String(), 585 OutgoingInterface: ifaceBOutOfidxs, 586 }, 587 }, 588 }, 589 }, 590 { 591 Name: "invalid IP address (addition with endDX6 behaviour)", 592 ExpectFailure: true, 593 Input: &srv6.LocalSID{ 594 Sid: sidToStr(sidA), 595 InstallationVrfId: 10, 596 EndFunction: &srv6.LocalSID_EndFunctionDx6{ 597 EndFunctionDx6: &srv6.LocalSID_EndDX6{ 598 NextHop: invalidIPAddress, 599 OutgoingInterface: ifaceA, 600 }, 601 }, 602 }, 603 }, 604 } 605 606 // Run all cases 607 for _, td := range cases { 608 t.Run(td.Name, func(t *testing.T) { 609 ctx, vppCalls := setup(t) 610 defer teardown(ctx) 611 // prepare reply 612 if td.MockInterfaceDump != nil { 613 if td.FailInVPPDump { 614 ctx.MockVpp.MockReply(&vpp_sr.SrPolicyDelReply{}) // unexpected type of message creates error (swInterfaceDetail doesn't have way how to indicate failure) 615 } else { 616 ctx.MockVpp.MockReply(td.MockInterfaceDump...) 617 ctx.MockVpp.MockReply(&vpp_vpe.ControlPingReply{}) 618 } 619 } 620 if td.cliMode && !td.FailInVPPDump { // SR-proxy can be set only using VPP CLI (-> using VPE binary API to deliver command to VPP) 621 if td.FailInVPP { 622 ctx.MockVpp.MockReply(&vpp_vpe.CliInbandReply{Retval: 1}) 623 } else { 624 ctx.MockVpp.MockReply(&vpp_vpe.CliInbandReply{}) 625 } 626 } else { // normal SR binary API 627 if td.FailInVPP { 628 ctx.MockVpp.MockReply(&vpp_sr.SrLocalsidAddDelReply{Retval: 1}) 629 } else { 630 ctx.MockVpp.MockReply(&vpp_sr.SrLocalsidAddDelReply{}) 631 } 632 } 633 // make the call 634 err := vppCalls.AddLocalSid(td.Input) 635 // verify result 636 if td.ExpectFailure { 637 Expect(err).Should(HaveOccurred()) 638 } else { 639 Expect(err).ShouldNot(HaveOccurred()) 640 Expect(ctx.MockChannel.Msg).To(Equal(td.Expected)) 641 } 642 }) 643 } 644 } 645 646 // TestDeleteLocalSID tests all cases for method DeleteLocalSID 647 func TestDeleteLocalSID(t *testing.T) { 648 // Prepare different cases 649 cases := []struct { 650 Name string 651 Fail bool 652 Input *srv6.LocalSID 653 MockReply govppapi.Message 654 Verify func(error, govppapi.Message) 655 }{ 656 { 657 Name: "simple delete of local sid (using vrf table with id 0)", 658 Input: &srv6.LocalSID{ 659 Sid: sidToStr(sidA), 660 InstallationVrfId: 0, 661 EndFunction: &srv6.LocalSID_BaseEndFunction{ 662 BaseEndFunction: &srv6.LocalSID_End{ 663 Psp: true, 664 }, 665 }, 666 }, 667 MockReply: &vpp_sr.SrLocalsidAddDelReply{}, 668 Verify: func(err error, catchedMsg govppapi.Message) { 669 Expect(err).ShouldNot(HaveOccurred()) 670 Expect(catchedMsg).To(Equal(&vpp_sr.SrLocalsidAddDel{ 671 IsDel: true, 672 Localsid: sidA, 673 FibTable: 0, 674 })) 675 }, 676 }, 677 { 678 Name: "simple delete of local sid (using vrf table with nonzero id)", 679 Input: &srv6.LocalSID{ 680 Sid: sidToStr(sidA), 681 InstallationVrfId: 10, 682 EndFunction: &srv6.LocalSID_BaseEndFunction{ 683 BaseEndFunction: &srv6.LocalSID_End{ 684 Psp: true, 685 }, 686 }, 687 }, 688 MockReply: &vpp_sr.SrLocalsidAddDelReply{}, 689 Verify: func(err error, catchedMsg govppapi.Message) { 690 Expect(err).ShouldNot(HaveOccurred()) 691 Expect(catchedMsg).To(Equal(&vpp_sr.SrLocalsidAddDel{ 692 IsDel: true, 693 Localsid: sidA, 694 FibTable: 10, 695 })) 696 }, 697 }, 698 { 699 Name: "failure propagation from VPP", 700 Input: &srv6.LocalSID{ 701 Sid: sidToStr(sidA), 702 InstallationVrfId: 0, 703 EndFunction: &srv6.LocalSID_BaseEndFunction{ 704 BaseEndFunction: &srv6.LocalSID_End{ 705 Psp: true, 706 }, 707 }, 708 }, 709 MockReply: &vpp_sr.SrLocalsidAddDelReply{Retval: 1}, 710 Verify: func(err error, msg govppapi.Message) { 711 Expect(err).Should(HaveOccurred()) 712 }, 713 }, 714 } 715 716 // Run all cases 717 for _, td := range cases { 718 t.Run(td.Name, func(t *testing.T) { 719 ctx, vppCalls := setup(t) 720 defer teardown(ctx) 721 // prepare for case 722 ctx.MockVpp.MockReply(td.MockReply) 723 // make the call and verify 724 err := vppCalls.DeleteLocalSid(td.Input) 725 td.Verify(err, ctx.MockChannel.Msg) 726 }) 727 } 728 } 729 730 // TestSetEncapsSourceAddress tests all cases for method SetEncapsSourceAddress 731 func TestSetEncapsSourceAddress(t *testing.T) { 732 // Prepare different cases 733 cases := []struct { 734 Name string 735 Fail bool 736 Address string 737 MockReply govppapi.Message 738 Verify func(error, govppapi.Message) 739 }{ 740 { 741 Name: "simple SetEncapsSourceAddress", 742 Address: nextHop.String(), 743 MockReply: &vpp_sr.SrSetEncapSourceReply{}, 744 Verify: func(err error, catchedMsg govppapi.Message) { 745 Expect(err).ShouldNot(HaveOccurred()) 746 Expect(catchedMsg).To(Equal(&vpp_sr.SrSetEncapSource{ 747 EncapsSource: sid(nextHop.String()), 748 })) 749 }, 750 }, 751 { 752 Name: "invalid IP address", 753 Address: invalidIPAddress, 754 MockReply: &vpp_sr.SrSetEncapSourceReply{}, 755 Verify: func(err error, catchedMsg govppapi.Message) { 756 Expect(err).Should(HaveOccurred()) 757 }, 758 }, 759 { 760 Name: "failure propagation from VPP", 761 Address: nextHop.String(), 762 MockReply: &vpp_sr.SrSetEncapSourceReply{Retval: 1}, 763 Verify: func(err error, msg govppapi.Message) { 764 Expect(err).Should(HaveOccurred()) 765 }, 766 }, 767 } 768 769 // Run all cases 770 for _, td := range cases { 771 t.Run(td.Name, func(t *testing.T) { 772 ctx, vppCalls := setup(t) 773 defer teardown(ctx) 774 775 ctx.MockVpp.MockReply(td.MockReply) 776 err := vppCalls.SetEncapsSourceAddress(td.Address) 777 td.Verify(err, ctx.MockChannel.Msg) 778 }) 779 } 780 } 781 782 // TestAddPolicy tests all cases for method AddPolicy 783 func TestAddPolicy(t *testing.T) { 784 // Prepare different cases 785 cases := []struct { 786 Name string 787 Fail bool 788 Policy *srv6.Policy 789 MockReplies []govppapi.Message 790 Verify func(error, []govppapi.Message) 791 }{ 792 { 793 Name: "simple SetAddPolicy", 794 Policy: policy(sidA[:], 10, false, true, policySegmentList(1, sidA[:], sidB[:], sidC[:])), 795 MockReplies: []govppapi.Message{&vpp_sr.SrPolicyAddReply{}}, 796 Verify: func(err error, catchedMsgs []govppapi.Message) { 797 Expect(err).ShouldNot(HaveOccurred()) 798 Expect(catchedMsgs).To(HaveLen(1)) 799 Expect(catchedMsgs[0]).To(Equal(&vpp_sr.SrPolicyAdd{ 800 BsidAddr: sidA, 801 FibTable: 10, // installationVrfId 802 IsSpray: false, 803 IsEncap: true, 804 Sids: vpp_sr.Srv6SidList{ 805 Weight: 1, 806 NumSids: 3, 807 Sids: [16]ip_types.IP6Address{sidA, sidB, sidC}, 808 }, 809 })) 810 }, 811 }, 812 { 813 Name: "adding policy with multiple segment lists", 814 Policy: policy(sidA[:], 10, false, true, 815 policySegmentList(1, sidA[:], sidB[:], sidC[:]), policySegmentList(1, sidB[:], sidC[:], sidA[:])), 816 MockReplies: []govppapi.Message{&vpp_sr.SrPolicyAddReply{}, &vpp_sr.SrPolicyModReply{}}, 817 Verify: func(err error, catchedMsgs []govppapi.Message) { 818 Expect(err).ShouldNot(HaveOccurred()) 819 Expect(catchedMsgs).To(HaveLen(2)) 820 Expect(catchedMsgs[0]).To(Equal(&vpp_sr.SrPolicyAdd{ 821 BsidAddr: sidA, 822 FibTable: 10, // installationVrfId 823 IsSpray: false, 824 IsEncap: true, 825 Sids: vpp_sr.Srv6SidList{ 826 Weight: 1, 827 NumSids: 3, 828 Sids: [16]ip_types.IP6Address{ 829 sidA, sidB, sidC, 830 }, 831 }, 832 })) 833 Expect(catchedMsgs[1]).To(Equal(&vpp_sr.SrPolicyMod{ 834 BsidAddr: sidA, 835 Operation: vpp2106.AddSRList, 836 FibTable: 10, // installationVrfId 837 Sids: vpp_sr.Srv6SidList{ 838 Weight: 1, 839 NumSids: 3, 840 Sids: [16]ip_types.IP6Address{sidB, sidC, sidA}, 841 }, 842 })) 843 }, 844 }, 845 { 846 Name: "failing when adding policy with empty segment lists", 847 Policy: policy(sidA[:], 10, false, true), 848 MockReplies: []govppapi.Message{&vpp_sr.SrPolicyAddReply{}}, 849 Verify: func(err error, catchedMsgs []govppapi.Message) { 850 Expect(err).Should(HaveOccurred()) 851 }, 852 }, 853 { 854 Name: "invalid binding SID in policy", 855 Policy: &srv6.Policy{ 856 Bsid: invalidIPAddress, 857 InstallationVrfId: 10, 858 SprayBehaviour: false, 859 SrhEncapsulation: true, 860 SegmentLists: []*srv6.Policy_SegmentList{ 861 { 862 Weight: 1, 863 Segments: []string{sidToStr(sidA), invalidIPAddress, sidToStr(sidC)}, 864 }, 865 }, 866 }, 867 MockReplies: []govppapi.Message{&vpp_sr.SrPolicyAddReply{}}, 868 Verify: func(err error, catchedMsgs []govppapi.Message) { 869 Expect(err).Should(HaveOccurred()) 870 }, 871 }, 872 { 873 Name: "invalid SID (not IP address) in first segment list", 874 Policy: policy(sidA[:], 10, false, true, 875 &srv6.Policy_SegmentList{ 876 Weight: 1, 877 Segments: []string{sidToStr(sidA), invalidIPAddress, sidToStr(sidC)}, 878 }), 879 MockReplies: []govppapi.Message{&vpp_sr.SrPolicyAddReply{}}, 880 Verify: func(err error, catchedMsgs []govppapi.Message) { 881 Expect(err).Should(HaveOccurred()) 882 }, 883 }, 884 { 885 Name: "invalid SID (not IP address) in non-first segment list", 886 Policy: policy(sidA[:], 10, false, true, 887 policySegmentList(1, sidA[:], sidB[:], sidC[:]), 888 &srv6.Policy_SegmentList{ 889 Weight: 1, 890 Segments: []string{sidToStr(sidA), invalidIPAddress, sidToStr(sidC)}, 891 }), 892 MockReplies: []govppapi.Message{&vpp_sr.SrPolicyAddReply{}, &vpp_sr.SrPolicyModReply{}}, 893 Verify: func(err error, catchedMsgs []govppapi.Message) { 894 Expect(err).Should(HaveOccurred()) 895 }, 896 }, 897 { 898 Name: "failure propagation from VPP", 899 Policy: policy(sidA[:], 0, true, true, policySegmentList(1, sidA[:], sidB[:], sidC[:])), 900 MockReplies: []govppapi.Message{&vpp_sr.SrPolicyAddReply{Retval: 1}}, 901 Verify: func(err error, msgs []govppapi.Message) { 902 Expect(err).Should(HaveOccurred()) 903 }, 904 }, 905 } 906 907 // Run all cases 908 for _, td := range cases { 909 t.Run(td.Name, func(t *testing.T) { 910 ctx, vppCalls := setup(t) 911 defer teardown(ctx) 912 // prepare reply, make call and verify 913 for _, reply := range td.MockReplies { 914 ctx.MockVpp.MockReply(reply) 915 } 916 err := vppCalls.AddPolicy(td.Policy) 917 td.Verify(err, ctx.MockChannel.Msgs) 918 }) 919 } 920 } 921 922 // TestDeletePolicy tests all cases for method DeletePolicy 923 func TestDeletePolicy(t *testing.T) { 924 // Prepare different cases 925 cases := []struct { 926 Name string 927 BSID net.IP 928 MockReply govppapi.Message 929 Verify func(error, govppapi.Message) 930 }{ 931 { 932 Name: "simple delete of policy", 933 BSID: sidA[:], 934 MockReply: &vpp_sr.SrPolicyDelReply{}, 935 Verify: func(err error, catchedMsg govppapi.Message) { 936 Expect(err).ShouldNot(HaveOccurred()) 937 Expect(catchedMsg).To(Equal(&vpp_sr.SrPolicyDel{ 938 BsidAddr: sidA, 939 })) 940 }, 941 }, 942 { 943 Name: "failure propagation from VPP", 944 BSID: sidA[:], 945 MockReply: &vpp_sr.SrPolicyDelReply{Retval: 1}, 946 Verify: func(err error, msg govppapi.Message) { 947 Expect(err).Should(HaveOccurred()) 948 }, 949 }, 950 } 951 952 // Run all cases 953 for _, td := range cases { 954 t.Run(td.Name, func(t *testing.T) { 955 ctx, vppCalls := setup(t) 956 defer teardown(ctx) 957 // data and prepare case 958 policy := policy(td.BSID, 0, true, true, policySegmentList(1, sidA[:], sidB[:], sidC[:])) 959 vppCalls.AddPolicy(policy) 960 ctx.MockVpp.MockReply(td.MockReply) 961 // make the call and verify 962 err := vppCalls.DeletePolicy(td.BSID) 963 td.Verify(err, ctx.MockChannel.Msg) 964 }) 965 } 966 } 967 968 // TestAddPolicySegmentList tests all cases for method AddPolicySegment 969 func TestAddPolicySegmentList(t *testing.T) { 970 // Prepare different cases 971 cases := []struct { 972 Name string 973 Policy *srv6.Policy 974 PolicySegmentList *srv6.Policy_SegmentList 975 MockReply govppapi.Message 976 Verify func(error, govppapi.Message) 977 }{ 978 { 979 Name: "simple addition of policy segment", 980 Policy: policy(sidA[:], 10, false, true), 981 PolicySegmentList: policySegmentList(1, sidA[:], sidB[:], sidC[:]), 982 MockReply: &vpp_sr.SrPolicyModReply{}, 983 Verify: func(err error, catchedMsg govppapi.Message) { 984 Expect(err).ShouldNot(HaveOccurred()) 985 Expect(catchedMsg).To(Equal(&vpp_sr.SrPolicyMod{ 986 BsidAddr: sidA, 987 Operation: vpp2106.AddSRList, 988 FibTable: 10, // installationVrfId 989 Sids: vpp_sr.Srv6SidList{ 990 Weight: 1, 991 NumSids: 3, 992 Sids: [16]ip_types.IP6Address{sidA, sidB, sidC}, 993 }, 994 })) 995 }, 996 }, 997 { 998 Name: "invalid SID (not IP address) in segment list", 999 Policy: policy(sidA[:], 10, false, true), 1000 PolicySegmentList: &srv6.Policy_SegmentList{ 1001 Weight: 1, 1002 Segments: []string{sidToStr(sidA), invalidIPAddress, sidToStr(sidC)}, 1003 }, 1004 MockReply: &vpp_sr.SrPolicyModReply{}, 1005 Verify: func(err error, catchedMsg govppapi.Message) { 1006 Expect(err).Should(HaveOccurred()) 1007 }, 1008 }, 1009 { 1010 Name: "invalid binding SID (not IP address) in policy", 1011 Policy: &srv6.Policy{ 1012 Bsid: invalidIPAddress, 1013 InstallationVrfId: 10, 1014 SprayBehaviour: false, 1015 SrhEncapsulation: true, 1016 }, 1017 PolicySegmentList: policySegmentList(1, sidA[:], sidB[:], sidC[:]), 1018 MockReply: &vpp_sr.SrPolicyModReply{}, 1019 Verify: func(err error, catchedMsg govppapi.Message) { 1020 Expect(err).Should(HaveOccurred()) 1021 }, 1022 }, 1023 { 1024 Name: "failure propagation from VPP", 1025 Policy: policy(sidA[:], 0, true, true), 1026 PolicySegmentList: policySegmentList(1, sidA[:], sidB[:], sidC[:]), 1027 MockReply: &vpp_sr.SrPolicyModReply{Retval: 1}, 1028 Verify: func(err error, msg govppapi.Message) { 1029 Expect(err).Should(HaveOccurred()) 1030 }, 1031 }, 1032 } 1033 1034 // Run all cases 1035 for _, td := range cases { 1036 t.Run(td.Name, func(t *testing.T) { 1037 ctx, vppCalls := setup(t) 1038 defer teardown(ctx) 1039 // prepare reply, make call and verify 1040 ctx.MockVpp.MockReply(td.MockReply) 1041 err := vppCalls.AddPolicySegmentList(td.PolicySegmentList, td.Policy) 1042 td.Verify(err, ctx.MockChannel.Msg) 1043 }) 1044 } 1045 } 1046 1047 // TestDeletePolicySegmentList tests all cases for method DeletePolicySegment 1048 func TestDeletePolicySegmentList(t *testing.T) { 1049 // Prepare different cases 1050 cases := []struct { 1051 Name string 1052 Policy *srv6.Policy 1053 PolicySegmentList *srv6.Policy_SegmentList 1054 SegmentIndex uint32 1055 MockReply govppapi.Message 1056 Verify func(error, govppapi.Message) 1057 }{ 1058 { 1059 Name: "simple deletion of policy segment", 1060 Policy: policy(sidA[:], 10, false, true, policySegmentList(1, sidA[:], sidB[:], sidC[:])), 1061 PolicySegmentList: policySegmentList(1, sidA[:], sidB[:], sidC[:]), 1062 SegmentIndex: 111, 1063 MockReply: &vpp_sr.SrPolicyModReply{}, 1064 Verify: func(err error, catchedMsg govppapi.Message) { 1065 Expect(err).ShouldNot(HaveOccurred()) 1066 Expect(catchedMsg).To(Equal(&vpp_sr.SrPolicyMod{ 1067 BsidAddr: sidA, 1068 Operation: vpp2106.DeleteSRList, 1069 SlIndex: 111, 1070 FibTable: 10, // installationVrfId 1071 Sids: vpp_sr.Srv6SidList{ 1072 Weight: 1, 1073 NumSids: 3, 1074 Sids: [16]ip_types.IP6Address{sidA, sidB, sidC}, 1075 }, 1076 })) 1077 }, 1078 }, 1079 { 1080 Name: "invalid SID (not IP address) in segment list", 1081 Policy: policy(sidA[:], 10, false, true, 1082 &srv6.Policy_SegmentList{ 1083 Weight: 1, 1084 Segments: []string{sidToStr(sidA), invalidIPAddress, sidToStr(sidC)}, 1085 }), 1086 PolicySegmentList: &srv6.Policy_SegmentList{ 1087 Weight: 1, 1088 Segments: []string{sidToStr(sidA), invalidIPAddress, sidToStr(sidC)}, 1089 }, 1090 SegmentIndex: 111, 1091 MockReply: &vpp_sr.SrPolicyModReply{}, 1092 Verify: func(err error, catchedMsg govppapi.Message) { 1093 Expect(err).Should(HaveOccurred()) 1094 }, 1095 }, 1096 { 1097 Name: "failure propagation from VPP", 1098 Policy: policy(sidA[:], 0, true, true, policySegmentList(1, sidA[:], sidB[:], sidC[:])), 1099 PolicySegmentList: policySegmentList(1, sidA[:], sidB[:], sidC[:]), 1100 SegmentIndex: 111, 1101 MockReply: &vpp_sr.SrPolicyModReply{Retval: 1}, 1102 Verify: func(err error, msg govppapi.Message) { 1103 Expect(err).Should(HaveOccurred()) 1104 }, 1105 }, 1106 } 1107 1108 // Run all cases 1109 for _, td := range cases { 1110 t.Run(td.Name, func(t *testing.T) { 1111 ctx, vppCalls := setup(t) 1112 defer teardown(ctx) 1113 // prepare reply, make call and verify 1114 ctx.MockVpp.MockReply(td.MockReply) 1115 err := vppCalls.DeletePolicySegmentList(td.PolicySegmentList, td.SegmentIndex, td.Policy) 1116 td.Verify(err, ctx.MockChannel.Msg) 1117 }) 1118 } 1119 } 1120 1121 // TestAddSteering tests all cases for method AddSteering 1122 func TestAddSteering(t *testing.T) { 1123 testAddRemoveSteering(t, false) 1124 } 1125 1126 // TestRemoveSteering tests all cases for method RemoveSteering 1127 func TestRemoveSteering(t *testing.T) { 1128 testAddRemoveSteering(t, true) 1129 } 1130 1131 func testAddRemoveSteering(t *testing.T, removal bool) { 1132 action := "addition" 1133 if removal { 1134 action = "removal" 1135 } 1136 // Prepare different cases 1137 cases := []struct { 1138 Name string 1139 Steering *srv6.Steering 1140 MockReply govppapi.Message 1141 Verify func(error, govppapi.Message) 1142 }{ 1143 { 1144 Name: action + " of IPv6 L3 steering", 1145 Steering: &srv6.Steering{ 1146 PolicyRef: &srv6.Steering_PolicyBsid{ 1147 PolicyBsid: sidToStr(sidA), 1148 }, 1149 Traffic: &srv6.Steering_L3Traffic_{ 1150 L3Traffic: &srv6.Steering_L3Traffic{ 1151 InstallationVrfId: 10, 1152 PrefixAddress: "1::/64", 1153 }, 1154 }, 1155 }, 1156 MockReply: &vpp_sr.SrSteeringAddDelReply{}, 1157 Verify: func(err error, catchedMsg govppapi.Message) { 1158 Expect(err).ShouldNot(HaveOccurred()) 1159 Expect(catchedMsg).To(Equal(&vpp_sr.SrSteeringAddDel{ 1160 IsDel: removal, 1161 BsidAddr: sidA, 1162 SrPolicyIndex: uint32(0), 1163 TableID: 10, 1164 TrafficType: vpp2106.SteerTypeIPv6, 1165 Prefix: ip_types.Prefix{Address: toAddress("1::"), Len: 64}, 1166 })) 1167 }, 1168 }, 1169 { 1170 Name: action + " of IPv4 L3 steering", 1171 Steering: &srv6.Steering{ 1172 PolicyRef: &srv6.Steering_PolicyBsid{ 1173 PolicyBsid: sidToStr(sidA), 1174 }, 1175 Traffic: &srv6.Steering_L3Traffic_{ 1176 L3Traffic: &srv6.Steering_L3Traffic{ 1177 InstallationVrfId: 10, 1178 PrefixAddress: "1.2.3.4/24", 1179 }, 1180 }, 1181 }, 1182 MockReply: &vpp_sr.SrSteeringAddDelReply{}, 1183 Verify: func(err error, catchedMsg govppapi.Message) { 1184 Expect(err).ShouldNot(HaveOccurred()) 1185 Expect(catchedMsg).To(Equal(&vpp_sr.SrSteeringAddDel{ 1186 IsDel: removal, 1187 BsidAddr: sidA, 1188 SrPolicyIndex: uint32(0), 1189 TableID: 10, 1190 TrafficType: vpp2106.SteerTypeIPv4, 1191 Prefix: ip_types.Prefix{Address: toAddress("1.2.3.4"), Len: 24}, 1192 })) 1193 }, 1194 }, 1195 { 1196 Name: action + " of L2 steering", 1197 Steering: &srv6.Steering{ 1198 PolicyRef: &srv6.Steering_PolicyBsid{ 1199 PolicyBsid: sidToStr(sidA), 1200 }, 1201 Traffic: &srv6.Steering_L2Traffic_{ 1202 L2Traffic: &srv6.Steering_L2Traffic{ 1203 InterfaceName: ifaceA, 1204 }, 1205 }, 1206 }, 1207 MockReply: &vpp_sr.SrSteeringAddDelReply{}, 1208 Verify: func(err error, catchedMsg govppapi.Message) { 1209 Expect(err).ShouldNot(HaveOccurred()) 1210 Expect(catchedMsg).To(Equal(&vpp_sr.SrSteeringAddDel{ 1211 IsDel: removal, 1212 BsidAddr: sidA, 1213 SrPolicyIndex: uint32(0), 1214 TrafficType: vpp2106.SteerTypeL2, 1215 SwIfIndex: swIndexA, 1216 })) 1217 }, 1218 }, 1219 { 1220 Name: action + " of IPv6 L3 steering with Policy referencing by index", 1221 Steering: &srv6.Steering{ 1222 PolicyRef: &srv6.Steering_PolicyIndex{ 1223 PolicyIndex: 20, 1224 }, 1225 Traffic: &srv6.Steering_L3Traffic_{ 1226 L3Traffic: &srv6.Steering_L3Traffic{ 1227 InstallationVrfId: 10, 1228 PrefixAddress: "1::/64", 1229 }, 1230 }, 1231 }, 1232 MockReply: &vpp_sr.SrSteeringAddDelReply{}, 1233 Verify: func(err error, catchedMsg govppapi.Message) { 1234 Expect(err).ShouldNot(HaveOccurred()) 1235 Expect(catchedMsg).To(Equal(&vpp_sr.SrSteeringAddDel{ 1236 IsDel: removal, 1237 SrPolicyIndex: uint32(20), 1238 TableID: 10, 1239 TrafficType: vpp2106.SteerTypeIPv6, 1240 Prefix: ip_types.Prefix{Address: toAddress("1::"), Len: 64}, 1241 })) 1242 }, 1243 }, 1244 { 1245 Name: "missing policy reference ( " + action + " of IPv6 L3 steering)", 1246 Steering: &srv6.Steering{ 1247 Traffic: &srv6.Steering_L3Traffic_{ 1248 L3Traffic: &srv6.Steering_L3Traffic{ 1249 InstallationVrfId: 10, 1250 PrefixAddress: "1::/64", 1251 }, 1252 }, 1253 }, 1254 MockReply: &vpp_sr.SrSteeringAddDelReply{}, 1255 Verify: func(err error, catchedMsg govppapi.Message) { 1256 Expect(err).Should(HaveOccurred()) 1257 }, 1258 }, 1259 { 1260 Name: "missing traffic ( " + action + " of IPv6 L3 steering)", 1261 Steering: &srv6.Steering{ 1262 PolicyRef: &srv6.Steering_PolicyBsid{ 1263 PolicyBsid: sidToStr(sidA), 1264 }, 1265 }, 1266 MockReply: &vpp_sr.SrSteeringAddDelReply{}, 1267 Verify: func(err error, catchedMsg govppapi.Message) { 1268 Expect(err).Should(HaveOccurred()) 1269 }, 1270 }, 1271 { 1272 Name: "invalid prefix (" + action + " of IPv4 L3 steering)", 1273 Steering: &srv6.Steering{ 1274 PolicyRef: &srv6.Steering_PolicyBsid{ 1275 PolicyBsid: sidToStr(sidA), 1276 }, 1277 Traffic: &srv6.Steering_L3Traffic_{ 1278 L3Traffic: &srv6.Steering_L3Traffic{ 1279 InstallationVrfId: 10, 1280 PrefixAddress: invalidIPAddress, 1281 }, 1282 }, 1283 }, 1284 MockReply: &vpp_sr.SrSteeringAddDelReply{}, 1285 Verify: func(err error, catchedMsg govppapi.Message) { 1286 Expect(err).Should(HaveOccurred()) 1287 }, 1288 }, 1289 { 1290 Name: "interface without index (" + action + " of L2 steering)", 1291 Steering: &srv6.Steering{ 1292 PolicyRef: &srv6.Steering_PolicyBsid{ 1293 PolicyBsid: sidToStr(sidA), 1294 }, 1295 Traffic: &srv6.Steering_L2Traffic_{ 1296 L2Traffic: &srv6.Steering_L2Traffic{ 1297 InterfaceName: ifaceBOutOfidxs, 1298 }, 1299 }, 1300 }, 1301 MockReply: &vpp_sr.SrSteeringAddDelReply{}, 1302 Verify: func(err error, catchedMsg govppapi.Message) { 1303 Expect(err).Should(HaveOccurred()) 1304 }, 1305 }, 1306 { 1307 Name: "invalid BSID (not IP address) as policy reference", 1308 Steering: &srv6.Steering{ 1309 PolicyRef: &srv6.Steering_PolicyBsid{ 1310 PolicyBsid: invalidIPAddress, 1311 }, 1312 Traffic: &srv6.Steering_L3Traffic_{ 1313 L3Traffic: &srv6.Steering_L3Traffic{ 1314 InstallationVrfId: 10, 1315 PrefixAddress: "1::/64", 1316 }, 1317 }, 1318 }, 1319 MockReply: &vpp_sr.SrSteeringAddDelReply{}, 1320 Verify: func(err error, catchedMsg govppapi.Message) { 1321 Expect(err).Should(HaveOccurred()) 1322 }, 1323 }, 1324 { 1325 Name: "failure propagation from VPP", 1326 Steering: &srv6.Steering{ 1327 PolicyRef: &srv6.Steering_PolicyBsid{ 1328 PolicyBsid: sidToStr(sidA), 1329 }, 1330 Traffic: &srv6.Steering_L3Traffic_{ 1331 L3Traffic: &srv6.Steering_L3Traffic{ 1332 InstallationVrfId: 10, 1333 PrefixAddress: "1::/64", 1334 }, 1335 }, 1336 }, 1337 MockReply: &vpp_sr.SrSteeringAddDelReply{Retval: 1}, 1338 Verify: func(err error, msg govppapi.Message) { 1339 Expect(err).Should(HaveOccurred()) 1340 }, 1341 }, 1342 } 1343 1344 // Run all cases 1345 for _, td := range cases { 1346 t.Run(td.Name, func(t *testing.T) { 1347 ctx, vppCalls := setup(t) 1348 defer teardown(ctx) 1349 // prepare reply, make call and verify 1350 ctx.MockVpp.MockReply(td.MockReply) 1351 var err error 1352 if removal { 1353 err = vppCalls.RemoveSteering(td.Steering) 1354 } else { 1355 err = vppCalls.AddSteering(td.Steering) 1356 } 1357 td.Verify(err, ctx.MockChannel.Msg) 1358 }) 1359 } 1360 } 1361 1362 // RetrievePolicyIndexInfo tests all cases for method RetrievePolicyIndexInfo 1363 func TestRetrievePolicyIndexInfo(t *testing.T) { 1364 correctCLIOutput := ` 1365 [4].- BSID: a:: 1366 1367 Behavior: SRH insertion 1368 1369 Type: Spray 1370 1371 FIB table: 0 1372 1373 Segment Lists: 1374 1375 [2].- < a::, b::, c::, > weight: 1 1376 [3].- < b::, b::, c::, > weight: 1 1377 [4].- < c::, b::, c::, > weight: 1 1378 1379 ----------- 1380 ` 1381 correctPolicyIndex := uint32(4) 1382 segmentListABC := policySegmentList(1, sidA[:], sidB[:], sidC[:]) 1383 segmentListBBC := policySegmentList(1, sidB[:], sidB[:], sidC[:]) 1384 notExistingSegmentListCCC := policySegmentList(1, sidC[:], sidC[:], sidC[:]) 1385 1386 // Prepare different cases 1387 cases := []struct { 1388 Name string 1389 Policy *srv6.Policy 1390 MockReply govppapi.Message 1391 ExpectedPolicyIndex uint32 1392 ExpectedSegmentListIndexes map[*srv6.Policy_SegmentList]uint32 1393 ExpectingFailure bool 1394 }{ 1395 { 1396 Name: "basic successful index retrieval", 1397 Policy: policy(sidA[:], 10, false, true, segmentListABC, segmentListBBC), 1398 MockReply: &vpp_vpe.CliInbandReply{ 1399 Reply: correctCLIOutput, 1400 Retval: 0, 1401 }, 1402 ExpectedPolicyIndex: correctPolicyIndex, 1403 ExpectedSegmentListIndexes: map[*srv6.Policy_SegmentList]uint32{segmentListABC: uint32(2), segmentListBBC: uint32(3)}, 1404 }, 1405 { 1406 Name: "failure propagation from VPP", 1407 Policy: policy(sidA[:], 10, false, true, segmentListABC, segmentListBBC), 1408 MockReply: &vpp_vpe.CliInbandReply{Retval: 1}, 1409 ExpectingFailure: true, 1410 }, 1411 { 1412 Name: "searching for not existing policy ", 1413 Policy: policy(sidC[:], 10, false, true, segmentListABC, segmentListBBC), 1414 MockReply: &vpp_vpe.CliInbandReply{ 1415 Reply: correctCLIOutput, 1416 Retval: 0, 1417 }, 1418 ExpectingFailure: true, 1419 }, 1420 { 1421 Name: "searching for not existing policy segment list", 1422 Policy: policy(sidA[:], 10, false, true, notExistingSegmentListCCC), 1423 MockReply: &vpp_vpe.CliInbandReply{ 1424 Reply: correctCLIOutput, 1425 Retval: 0, 1426 }, 1427 ExpectingFailure: true, 1428 }, 1429 } 1430 // Run all cases 1431 for _, td := range cases { 1432 t.Run(td.Name, func(t *testing.T) { 1433 ctx, vppCalls := setup(t) 1434 defer teardown(ctx) 1435 // prepare reply, make call and verify 1436 ctx.MockVpp.MockReply(td.MockReply) 1437 resultPolicyIndex, resultSlIndexes, err := vppCalls.RetrievePolicyIndexInfo(td.Policy) 1438 Expect(ctx.MockChannel.Msg).To(Equal(&vpp_vpe.CliInband{ 1439 Cmd: "sh sr policies", 1440 })) 1441 if td.ExpectingFailure { 1442 Expect(err).Should(HaveOccurred()) 1443 } else { 1444 Expect(err).ShouldNot(HaveOccurred()) 1445 Expect(resultPolicyIndex).To(Equal(td.ExpectedPolicyIndex)) 1446 Expect(resultSlIndexes).To(Equal(td.ExpectedSegmentListIndexes)) 1447 } 1448 }) 1449 } 1450 } 1451 1452 func setup(t *testing.T) (*vppmock.TestCtx, vppcalls.SRv6VppAPI) { 1453 ctx := vppmock.SetupTestCtx(t) 1454 log := logrus.NewLogger("test") 1455 swIfIndex := ifaceidx.NewIfaceIndex(log, "test") 1456 swIfIndex.Put(ifaceA, &ifaceidx.IfaceMetadata{SwIfIndex: swIndexA}) 1457 vppCalls := vpp2106.NewSRv6VppHandler(ctx.MockVPPClient, swIfIndex, log) 1458 return ctx, vppCalls 1459 } 1460 1461 func teardown(ctx *vppmock.TestCtx) { 1462 ctx.TeardownTestCtx() 1463 } 1464 1465 func sid(str string) ip_types.IP6Address { 1466 bsid, err := parseIPv6(str) 1467 if err != nil { 1468 panic(fmt.Sprintf("can't parse %q into SRv6 BSID (IPv6 address)", str)) 1469 } 1470 var ip ip_types.IP6Address 1471 copy(ip[:], bsid) 1472 return ip 1473 } 1474 1475 // parseIPv6 parses string <str> to IPv6 address (including IPv4 address converted to IPv6 address) 1476 func parseIPv6(str string) (net.IP, error) { 1477 ip := net.ParseIP(str) 1478 if ip == nil { 1479 return nil, fmt.Errorf(" %q is not ip address", str) 1480 } 1481 ipv6 := ip.To16() 1482 if ipv6 == nil { 1483 return nil, fmt.Errorf(" %q is not ipv6 address", str) 1484 } 1485 return ipv6, nil 1486 } 1487 1488 func policy(bsid srv6.SID, installationVrfId uint32, sprayBehaviour bool, srhEncapsulation bool, segmentLists ...*srv6.Policy_SegmentList) *srv6.Policy { 1489 return &srv6.Policy{ 1490 Bsid: bsid.String(), 1491 InstallationVrfId: installationVrfId, 1492 SprayBehaviour: sprayBehaviour, 1493 SrhEncapsulation: srhEncapsulation, 1494 SegmentLists: segmentLists, 1495 } 1496 } 1497 1498 func policySegmentList(weight uint32, sids ...srv6.SID) *srv6.Policy_SegmentList { 1499 segments := make([]string, len(sids)) 1500 for i, sid := range sids { 1501 segments[i] = sid.String() 1502 } 1503 1504 return &srv6.Policy_SegmentList{ 1505 Weight: weight, 1506 Segments: segments, 1507 } 1508 } 1509 1510 func sidToStr(sid ip_types.IP6Address) string { 1511 return srv6.SID(sid[:]).String() 1512 } 1513 1514 func toAddress(ip interface{}) (addr ip_types.Address) { 1515 switch ip := ip.(type) { 1516 case string: 1517 addr, _ = vpp2106.IPToAddress(ip) 1518 case net.IP: 1519 addr, _ = vpp2106.IPToAddress(ip.String()) 1520 default: 1521 panic(fmt.Sprintf("cannot convert to ip_types.Address from type %T", ip)) 1522 } 1523 return 1524 }