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  }