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  }