go.ligato.io/vpp-agent/v3@v3.5.0/tests/integration/vpp/110_srv6_test.go (about) 1 // Copyright (c) 2019 Pantheon.tech 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 vpp 16 17 import ( 18 "fmt" 19 "net" 20 "testing" 21 22 . "github.com/onsi/gomega" 23 "go.ligato.io/cn-infra/v2/logging/logrus" 24 "google.golang.org/protobuf/proto" 25 26 netalloc_mock "go.ligato.io/vpp-agent/v3/plugins/netalloc/mock" 27 "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/ifaceidx" 28 ifplugin_vppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/vppcalls" 29 l3plugin_vppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/vppcalls" 30 "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/vrfidx" 31 srv6_vppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/srplugin/vppcalls" 32 vpp_l3 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l3" 33 srv6 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/srv6" 34 35 _ "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin" 36 _ "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin" 37 _ "go.ligato.io/vpp-agent/v3/plugins/vpp/srplugin" 38 ) 39 40 var ( 41 sidA = sid("A::") 42 nextHop = net.ParseIP("B::").To16() 43 nextHop2 = net.ParseIP("C::").To16() 44 nextHopIPv4 = net.ParseIP("1.2.3.4").To4() 45 nextHop2IPv4 = net.ParseIP("1.2.3.5").To4() 46 vrfTables = []*vpp_l3.VrfTable{ 47 { 48 Id: 11, 49 Protocol: vpp_l3.VrfTable_IPV6, 50 Label: "testIpv6Table1", 51 }, 52 { 53 Id: 12, 54 Protocol: vpp_l3.VrfTable_IPV6, 55 Label: "testIpv6Table2", 56 }, 57 { 58 Id: 13, 59 Protocol: vpp_l3.VrfTable_IPV4, 60 Label: "testIpv4Table1", 61 }, 62 { 63 Id: 14, 64 Protocol: vpp_l3.VrfTable_IPV4, 65 Label: "testIpv4Table2", 66 }, 67 } 68 ) 69 70 //TODO add CRUD tests for SR-proxy (there is no binary API for it -> dump for SR-proxy needs 1. CLI localsid dump 71 // and 2. CLI fib table dump because CLI localsid dump does not include installation vrf for SR-proxy localsid) 72 73 // TestLocalsidCRUD tests CRUD operations for Localsids 74 func TestLocalsidCRUD(t *testing.T) { 75 ctx := setupVPP(t) 76 defer ctx.teardownVPP() 77 78 // create interfaces (for referencing from localsids) 79 ih := ifplugin_vppcalls.CompatibleInterfaceVppHandler(ctx.vppClient, logrus.NewLogger("test")) 80 const ifName = "loop1" 81 ifIdx, err := ih.AddLoopbackInterface(ifName) 82 Expect(err).To(BeNil(), fmt.Sprintf("fixture setup failed in creating of interface %v: %v", ifName, err)) 83 t.Logf("interface created %v", ifIdx) 84 const ifName2 = "loop2" 85 ifIdx2, err := ih.AddLoopbackInterface(ifName2) 86 Expect(err).To(BeNil(), fmt.Sprintf("fixture setup failed in creating of interface %v: %v", ifName2, err)) 87 t.Logf("interface created %v", ifIdx2) 88 ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test-idx"), "test-idx") 89 ifIndexes.Put(ifName, &ifaceidx.IfaceMetadata{SwIfIndex: ifIdx}) 90 ifIndexes.Put(ifName2, &ifaceidx.IfaceMetadata{SwIfIndex: ifIdx2}) 91 92 // create vrf tables (for referencing from localsids) 93 vrfIndexes := vrfidx.NewVRFIndex(logrus.NewLogger("test-vrf"), "test-vrf") 94 vrfIndexes.Put("vrf1-ipv4", &vrfidx.VRFMetadata{Index: 0, Protocol: vpp_l3.VrfTable_IPV4}) 95 vrfIndexes.Put("vrf1-ipv6", &vrfidx.VRFMetadata{Index: 0, Protocol: vpp_l3.VrfTable_IPV6}) 96 l3h := l3plugin_vppcalls.CompatibleL3VppHandler(ctx.vppClient, ifIndexes, vrfIndexes, 97 netalloc_mock.NewMockNetAlloc(), logrus.NewLogger("test-l3")) 98 for _, vrfTable := range vrfTables[:4] { 99 Expect(l3h.AddVrfTable(vrfTable)).Should(Succeed(), fmt.Sprintf("fixture setup failed "+ 100 "in creating of vrf table with name %v due to: %v", vrfTable.Label, err)) 101 } 102 103 // SRv6 handler 104 srh := srv6_vppcalls.CompatibleSRv6Handler(ctx.vppClient, ifIndexes, logrus.NewLogger("test")) 105 106 tests := []struct { 107 name string 108 input *srv6.LocalSID 109 expectedDump *srv6.LocalSID 110 updatedInput *srv6.LocalSID 111 updatedExpectedDump *srv6.LocalSID 112 }{ 113 { 114 name: "base end", 115 input: &srv6.LocalSID{ 116 Sid: sidA.String(), 117 InstallationVrfId: 0, 118 EndFunction: &srv6.LocalSID_BaseEndFunction{ 119 BaseEndFunction: &srv6.LocalSID_End{ 120 Psp: true, 121 }, 122 }, 123 }, 124 updatedInput: &srv6.LocalSID{ 125 Sid: sidA.String(), 126 InstallationVrfId: 0, 127 EndFunction: &srv6.LocalSID_BaseEndFunction{ 128 BaseEndFunction: &srv6.LocalSID_End{ 129 Psp: false, 130 }, 131 }, 132 }, 133 }, 134 { 135 name: "end.X", 136 input: &srv6.LocalSID{ 137 Sid: sidA.String(), 138 InstallationVrfId: 0, 139 EndFunction: &srv6.LocalSID_EndFunctionX{ 140 EndFunctionX: &srv6.LocalSID_EndX{ 141 Psp: true, 142 NextHop: nextHop.String(), 143 OutgoingInterface: ifName, 144 }, 145 }, 146 }, 147 updatedInput: &srv6.LocalSID{ 148 Sid: sidA.String(), 149 InstallationVrfId: 0, 150 EndFunction: &srv6.LocalSID_EndFunctionX{ 151 EndFunctionX: &srv6.LocalSID_EndX{ 152 Psp: true, 153 NextHop: nextHop2.String(), // updated 154 OutgoingInterface: ifName, 155 }, 156 }, 157 }, 158 }, 159 { 160 name: "end.T", 161 input: &srv6.LocalSID{ 162 Sid: sidA.String(), 163 InstallationVrfId: 0, 164 EndFunction: &srv6.LocalSID_EndFunctionT{ 165 EndFunctionT: &srv6.LocalSID_EndT{ 166 Psp: true, 167 VrfId: vrfTables[0].Id, 168 }, 169 }, 170 }, 171 expectedDump: &srv6.LocalSID{ 172 Sid: sidA.String(), 173 InstallationVrfId: 0, 174 EndFunction: &srv6.LocalSID_EndFunctionT{ 175 EndFunctionT: &srv6.LocalSID_EndT{ 176 Psp: true, 177 VrfId: 1, // bug in VPP, it should return client Table ID but it returns vpp-inner Table ID 178 }, 179 }, 180 }, 181 updatedInput: &srv6.LocalSID{ 182 Sid: sidA.String(), 183 InstallationVrfId: 0, 184 EndFunction: &srv6.LocalSID_EndFunctionT{ 185 EndFunctionT: &srv6.LocalSID_EndT{ 186 Psp: true, 187 VrfId: vrfTables[1].Id, // updated 188 }, 189 }, 190 }, 191 updatedExpectedDump: &srv6.LocalSID{ 192 Sid: sidA.String(), 193 InstallationVrfId: 0, 194 EndFunction: &srv6.LocalSID_EndFunctionT{ 195 EndFunctionT: &srv6.LocalSID_EndT{ 196 Psp: true, 197 VrfId: 2, // bug in VPP, it should return client Table ID but it returns vpp-inner Table ID 198 }, 199 }, 200 }, 201 }, 202 { 203 name: "end.DT4", 204 input: &srv6.LocalSID{ 205 Sid: sidA.String(), 206 InstallationVrfId: 0, 207 EndFunction: &srv6.LocalSID_EndFunctionDt4{ 208 EndFunctionDt4: &srv6.LocalSID_EndDT4{ 209 VrfId: vrfTables[2].Id, 210 }, 211 }, 212 }, 213 expectedDump: &srv6.LocalSID{ 214 Sid: sidA.String(), 215 InstallationVrfId: 0, 216 EndFunction: &srv6.LocalSID_EndFunctionDt4{ 217 EndFunctionDt4: &srv6.LocalSID_EndDT4{ 218 VrfId: 1, // bug in VPP, it should return client Table ID but it returns vpp-inner Table ID 219 }, 220 }, 221 }, 222 updatedInput: &srv6.LocalSID{ 223 Sid: sidA.String(), 224 InstallationVrfId: 0, 225 EndFunction: &srv6.LocalSID_EndFunctionDt4{ 226 EndFunctionDt4: &srv6.LocalSID_EndDT4{ 227 VrfId: vrfTables[3].Id, // updated 228 }, 229 }, 230 }, 231 updatedExpectedDump: &srv6.LocalSID{ 232 Sid: sidA.String(), 233 InstallationVrfId: 0, 234 EndFunction: &srv6.LocalSID_EndFunctionDt4{ 235 EndFunctionDt4: &srv6.LocalSID_EndDT4{ 236 VrfId: 2, // bug in VPP, it should return client Table ID but it returns vpp-inner Table ID 237 }, 238 }, 239 }, 240 }, 241 { 242 name: "end.DT6", 243 input: &srv6.LocalSID{ 244 Sid: sidA.String(), 245 InstallationVrfId: 0, 246 EndFunction: &srv6.LocalSID_EndFunctionDt6{ 247 EndFunctionDt6: &srv6.LocalSID_EndDT6{ 248 VrfId: vrfTables[0].Id, 249 }, 250 }, 251 }, 252 expectedDump: &srv6.LocalSID{ 253 Sid: sidA.String(), 254 InstallationVrfId: 0, 255 EndFunction: &srv6.LocalSID_EndFunctionDt6{ 256 EndFunctionDt6: &srv6.LocalSID_EndDT6{ 257 VrfId: 1, // bug in VPP, it should return client Table ID but it returns vpp-inner Table ID 258 }, 259 }, 260 }, 261 updatedInput: &srv6.LocalSID{ 262 Sid: sidA.String(), 263 InstallationVrfId: 0, 264 EndFunction: &srv6.LocalSID_EndFunctionDt6{ 265 EndFunctionDt6: &srv6.LocalSID_EndDT6{ 266 VrfId: vrfTables[1].Id, // updated 267 }, 268 }, 269 }, 270 updatedExpectedDump: &srv6.LocalSID{ 271 Sid: sidA.String(), 272 InstallationVrfId: 0, 273 EndFunction: &srv6.LocalSID_EndFunctionDt6{ 274 EndFunctionDt6: &srv6.LocalSID_EndDT6{ 275 VrfId: 2, // bug in VPP, it should return client Table ID but it returns vpp-inner Table ID 276 }, 277 }, 278 }, 279 }, 280 { 281 name: "end.DX2", 282 input: &srv6.LocalSID{ 283 Sid: sidA.String(), 284 InstallationVrfId: 0, 285 EndFunction: &srv6.LocalSID_EndFunctionDx2{ 286 EndFunctionDx2: &srv6.LocalSID_EndDX2{ 287 VlanTag: 0, 288 OutgoingInterface: ifName, 289 }, 290 }, 291 }, 292 updatedInput: &srv6.LocalSID{ 293 Sid: sidA.String(), 294 InstallationVrfId: 0, 295 EndFunction: &srv6.LocalSID_EndFunctionDx2{ 296 EndFunctionDx2: &srv6.LocalSID_EndDX2{ 297 VlanTag: 0, 298 OutgoingInterface: ifName2, 299 }, 300 }, 301 }, 302 }, 303 { 304 name: "end.DX4", 305 input: &srv6.LocalSID{ 306 Sid: sidA.String(), 307 InstallationVrfId: 0, 308 EndFunction: &srv6.LocalSID_EndFunctionDx4{ 309 EndFunctionDx4: &srv6.LocalSID_EndDX4{ 310 NextHop: nextHopIPv4.String(), 311 OutgoingInterface: ifName, 312 }, 313 }, 314 }, 315 updatedInput: &srv6.LocalSID{ 316 Sid: sidA.String(), 317 InstallationVrfId: 0, 318 EndFunction: &srv6.LocalSID_EndFunctionDx4{ 319 EndFunctionDx4: &srv6.LocalSID_EndDX4{ 320 NextHop: nextHop2IPv4.String(), // updated 321 OutgoingInterface: ifName, 322 }, 323 }, 324 }, 325 }, 326 { 327 name: "end.DX6", 328 input: &srv6.LocalSID{ 329 Sid: sidA.String(), 330 InstallationVrfId: 0, 331 EndFunction: &srv6.LocalSID_EndFunctionDx6{ 332 EndFunctionDx6: &srv6.LocalSID_EndDX6{ 333 NextHop: nextHop.String(), 334 OutgoingInterface: ifName, 335 }, 336 }, 337 }, 338 updatedInput: &srv6.LocalSID{ 339 Sid: sidA.String(), 340 InstallationVrfId: 0, 341 EndFunction: &srv6.LocalSID_EndFunctionDx6{ 342 EndFunctionDx6: &srv6.LocalSID_EndDX6{ 343 NextHop: nextHop2.String(), // updated 344 OutgoingInterface: ifName, 345 }, 346 }, 347 }, 348 }, 349 { 350 name: "nondefault installation vrf table", 351 input: &srv6.LocalSID{ 352 Sid: sidA.String(), 353 InstallationVrfId: vrfTables[0].Id, 354 EndFunction: &srv6.LocalSID_BaseEndFunction{ 355 BaseEndFunction: &srv6.LocalSID_End{ 356 Psp: true, 357 }, 358 }, 359 }, 360 }, 361 } 362 363 for _, test := range tests { 364 t.Run(test.name, func(t *testing.T) { 365 // FIXME: fix expected VRF value for different VPP versions... 366 // a fix in VPP was merged into stable branch for 19.08 only... 367 // https://gerrit.fd.io/r/gitweb?p=vpp.git;a=commit;h=4362672562f5b379361f147cbb7a9b72c3332c30 368 // this causes VPP 19.08 fail even though it actually is only versions it works okay in.. 369 t.Skipf("FIXME: fix expected VRF value for different VPP versions") 370 if ctx.versionInfo.Release() == "20.05" { 371 // FIXME: following error occurs in VPP 20.05: 372 // can't properly handle end function of dumped localsid &{[0 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0] true 0 0 0 {ADDRESS_IP4 {[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]}} 0} due to: localsid with unknown or unsupported behavior (0) 373 t.Skip("skipping for VPP 20.05, FIX NEEDED!") 374 } 375 376 // Create 377 Expect(srh.AddLocalSid(test.input)).Should(Succeed()) 378 379 // Read 380 localsids, err := srh.DumpLocalSids() 381 t.Logf("received this localsids from dump: %v", localsids) 382 Expect(err).ShouldNot(HaveOccurred()) 383 expected := test.input 384 if test.expectedDump != nil { 385 expected = test.expectedDump 386 } 387 Expect(localsids).To(HaveLen(1)) 388 Expect(proto.Equal(localsids[0], expected)).To(BeTrue()) 389 390 // Update (for localsids it means delete + create) 391 if test.updatedInput != nil { 392 Expect(srh.DeleteLocalSid(test.input)).Should(Succeed()) 393 Expect(srh.AddLocalSid(test.updatedInput)).Should(Succeed()) 394 localsids, err = srh.DumpLocalSids() 395 t.Logf("received this localsids from dump: %v", localsids) 396 Expect(err).ShouldNot(HaveOccurred()) 397 expected := test.updatedInput 398 if test.updatedExpectedDump != nil { 399 expected = test.updatedExpectedDump 400 } 401 Expect(localsids).To(HaveLen(1)) 402 Expect(proto.Equal(localsids[0], expected)).To(BeTrue()) 403 } 404 // Delete 405 if test.updatedInput != nil { 406 Expect(srh.DeleteLocalSid(test.updatedInput)).Should(Succeed()) 407 } else { 408 Expect(srh.DeleteLocalSid(test.input)).Should(Succeed()) 409 } 410 }) 411 } 412 } 413 414 // sid creates segment ID(=net.IP) from string 415 func sid(str string) net.IP { 416 sid, err := parseIPv6(str) 417 if err != nil { 418 panic(fmt.Sprintf("can't parse %q into SRv6 SID (IPv6 address)", str)) 419 } 420 return sid 421 } 422 423 // parseIPv6 parses string <str> to IPv6 address (including IPv4 address converted to IPv6 address) 424 func parseIPv6(str string) (net.IP, error) { 425 ip := net.ParseIP(str) 426 if ip == nil { 427 return nil, fmt.Errorf(" %q is not ip address", str) 428 } 429 ipv6 := ip.To16() 430 if ipv6 == nil { 431 return nil, fmt.Errorf(" %q is not ipv6 address", str) 432 } 433 return ipv6, nil 434 }