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