go.ligato.io/vpp-agent/v3@v3.5.0/tests/e2e/080_vrf_test.go (about)

     1  // Copyright (c) 2020 Pantheon.tech
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at:
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package e2e
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  	"time"
    21  
    22  	. "github.com/onsi/gomega"
    23  
    24  	kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    25  	vrf "go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin/descriptor"
    26  	"go.ligato.io/vpp-agent/v3/plugins/netalloc/utils"
    27  	"go.ligato.io/vpp-agent/v3/proto/ligato/kvscheduler"
    28  	linux_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces"
    29  	linux_l3 "go.ligato.io/vpp-agent/v3/proto/ligato/linux/l3"
    30  	linux_namespace "go.ligato.io/vpp-agent/v3/proto/ligato/linux/namespace"
    31  	netalloc_api "go.ligato.io/vpp-agent/v3/proto/ligato/netalloc"
    32  	vpp_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces"
    33  	vpp_l3 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l3"
    34  	. "go.ligato.io/vpp-agent/v3/tests/e2e/e2etest"
    35  )
    36  
    37  // +----------------------------------------------------------------------+
    38  // | VPP                                                                  |
    39  // | +-------------------------------+  +-------------------------------+ |
    40  // | | VRF 1                         |  | VRF 2                         | |
    41  // | |        +-------------------+  |  |        +-------------------+  | |
    42  // | |        |  192.168.1.1/24   |  |  |        |  192.168.1.1./24  |  | |
    43  // | |        +---------+---------+  |  |        +----------+--------+  | |
    44  // | +------------------|------------+  +-------------------|-----------+ |
    45  // +--------------------|-----------------------------------|-------------+
    46  // Linux                | (TAP)                             | (TAP)
    47  // +--------------------|-----------+  +--------------------|-----------+
    48  // | VRF_1              |           |  | VRF_2              |           |
    49  // |         +---------+---------+  |  |          +---------+--------+  |
    50  // |         |  192.168.1.2/24   |  |  |          |  192.168.1.2/24  |  |
    51  // |         +-------------------+  |  |          +------------------+  |
    52  // +--------------------------------+  +--------------------------------+
    53  func TestVRFsWithSameSubnets(t *testing.T) {
    54  	if !SupportsLinuxVRF() {
    55  		t.Skip("Linux VRFs are not supported")
    56  	}
    57  
    58  	ctx := Setup(t)
    59  	defer ctx.Teardown()
    60  
    61  	const (
    62  		vrf1ID               = 1
    63  		vrf1Mtu       uint32 = 1500
    64  		vrf2ID               = 2
    65  		vrf1Label            = "vrf-1"
    66  		vrf2Label            = "vrf-2"
    67  		vrfVppIP             = "192.168.1.1"
    68  		vrfLinuxIP           = "192.168.1.2"
    69  		vrfSubnetMask        = "/24"
    70  		tapNameSuffix        = "-tap"
    71  		msName               = "microservice1"
    72  	)
    73  
    74  	// TAP interfaces
    75  	vrf1VppTap := &vpp_interfaces.Interface{
    76  		Name:        vrf1Label + tapNameSuffix,
    77  		Type:        vpp_interfaces.Interface_TAP,
    78  		Enabled:     true,
    79  		Vrf:         vrf1ID,
    80  		IpAddresses: []string{vrfVppIP + vrfSubnetMask},
    81  		Link: &vpp_interfaces.Interface_Tap{
    82  			Tap: &vpp_interfaces.TapLink{
    83  				Version:        2,
    84  				ToMicroservice: MsNamePrefix + msName,
    85  			},
    86  		},
    87  	}
    88  	vrf1LinuxTap := &linux_interfaces.Interface{
    89  		Name:               vrf1Label + tapNameSuffix,
    90  		Type:               linux_interfaces.Interface_TAP_TO_VPP,
    91  		Enabled:            true,
    92  		VrfMasterInterface: vrf1Label,
    93  		IpAddresses:        []string{vrfLinuxIP + vrfSubnetMask},
    94  		Link: &linux_interfaces.Interface_Tap{
    95  			Tap: &linux_interfaces.TapLink{
    96  				VppTapIfName: vrf1Label + tapNameSuffix,
    97  			},
    98  		},
    99  		Namespace: &linux_namespace.NetNamespace{
   100  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   101  			Reference: MsNamePrefix + msName,
   102  		},
   103  	}
   104  	vrf2VppTap := &vpp_interfaces.Interface{
   105  		Name:        vrf2Label + tapNameSuffix,
   106  		Type:        vpp_interfaces.Interface_TAP,
   107  		Enabled:     true,
   108  		Vrf:         vrf2ID,
   109  		IpAddresses: []string{vrfVppIP + vrfSubnetMask},
   110  		Link: &vpp_interfaces.Interface_Tap{
   111  			Tap: &vpp_interfaces.TapLink{
   112  				Version:        2,
   113  				ToMicroservice: MsNamePrefix + msName,
   114  			},
   115  		},
   116  	}
   117  	vrf2LinuxTap := &linux_interfaces.Interface{
   118  		Name:               vrf2Label + tapNameSuffix,
   119  		Type:               linux_interfaces.Interface_TAP_TO_VPP,
   120  		VrfMasterInterface: vrf2Label,
   121  		Enabled:            true,
   122  		IpAddresses:        []string{vrfLinuxIP + vrfSubnetMask},
   123  		Link: &linux_interfaces.Interface_Tap{
   124  			Tap: &linux_interfaces.TapLink{
   125  				VppTapIfName: vrf2Label + tapNameSuffix,
   126  			},
   127  		},
   128  		Namespace: &linux_namespace.NetNamespace{
   129  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   130  			Reference: MsNamePrefix + msName,
   131  		},
   132  	}
   133  
   134  	// VRFs
   135  	vppVrf1 := &vpp_l3.VrfTable{
   136  		Id:       vrf1ID,
   137  		Label:    vrf1Label,
   138  		Protocol: vpp_l3.VrfTable_IPV4,
   139  	}
   140  	vppVrf2 := &vpp_l3.VrfTable{
   141  		Id:       vrf2ID,
   142  		Label:    vrf2Label,
   143  		Protocol: vpp_l3.VrfTable_IPV4,
   144  	}
   145  	linuxVrf1 := &linux_interfaces.Interface{
   146  		Name:    vrf1Label,
   147  		Type:    linux_interfaces.Interface_VRF_DEVICE,
   148  		Enabled: true,
   149  		Link: &linux_interfaces.Interface_VrfDev{
   150  			VrfDev: &linux_interfaces.VrfDevLink{
   151  				RoutingTable: vrf1ID,
   152  			},
   153  		},
   154  		Namespace: &linux_namespace.NetNamespace{
   155  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   156  			Reference: MsNamePrefix + msName,
   157  		},
   158  	}
   159  	linuxVrf1Updated := &linux_interfaces.Interface{
   160  		Name:    vrf1Label,
   161  		Type:    linux_interfaces.Interface_VRF_DEVICE,
   162  		Enabled: true,
   163  		Link: &linux_interfaces.Interface_VrfDev{
   164  			VrfDev: &linux_interfaces.VrfDevLink{
   165  				RoutingTable: vrf1ID,
   166  			},
   167  		},
   168  		Mtu: vrf1Mtu,
   169  		Namespace: &linux_namespace.NetNamespace{
   170  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   171  			Reference: MsNamePrefix + msName,
   172  		},
   173  	}
   174  	linuxVrf2 := &linux_interfaces.Interface{
   175  		Name:    vrf2Label,
   176  		Type:    linux_interfaces.Interface_VRF_DEVICE,
   177  		Enabled: true,
   178  		Link: &linux_interfaces.Interface_VrfDev{
   179  			VrfDev: &linux_interfaces.VrfDevLink{
   180  				RoutingTable: vrf2ID,
   181  			},
   182  		},
   183  		Namespace: &linux_namespace.NetNamespace{
   184  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   185  			Reference: MsNamePrefix + msName,
   186  		},
   187  	}
   188  
   189  	ctx.StartMicroservice(msName)
   190  
   191  	// configure everything in one resync
   192  	err := ctx.GenericClient().ResyncConfig(
   193  		vppVrf1, vppVrf2,
   194  		linuxVrf1, linuxVrf2,
   195  		vrf1VppTap, vrf1LinuxTap,
   196  		vrf2VppTap, vrf2LinuxTap,
   197  	)
   198  	ctx.Expect(err).ToNot(HaveOccurred())
   199  
   200  	ctx.Eventually(ctx.GetValueStateClb(vrf1LinuxTap)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   201  	ctx.Expect(ctx.GetValueState(vrf1VppTap)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   202  	ctx.Expect(ctx.GetValueState(vrf2LinuxTap)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   203  	ctx.Expect(ctx.GetValueState(vrf2VppTap)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   204  	ctx.Expect(ctx.GetValueState(linuxVrf1)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   205  	ctx.Expect(ctx.GetValueState(linuxVrf2)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   206  	ctx.Expect(ctx.GetValueState(vppVrf1)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   207  	ctx.Expect(ctx.GetValueState(vppVrf2)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   208  
   209  	// vrf mtu check
   210  	linuxVrf1Msg := ctx.GetValue(linuxVrf1, kvs.SBView).ProtoReflect()
   211  	linuxVrf1Desc := linuxVrf1Msg.Descriptor().Fields().ByTextName("mtu")
   212  	linuxVrf1Mtu := linuxVrf1Msg.Get(linuxVrf1Desc).Uint()
   213  	ctx.Expect(int(linuxVrf1Mtu)).To(SatisfyAny(Equal(vrf.DefaultVrfDevMTU), Equal(vrf.DefaultVrfDevLegacyMTU)))
   214  	linuxVrf2Msg := ctx.GetValue(linuxVrf2, kvs.SBView).ProtoReflect()
   215  	linuxVrf2Desc := linuxVrf2Msg.Descriptor().Fields().ByTextName("mtu")
   216  	linuxVrf2Mtu := linuxVrf2Msg.Get(linuxVrf2Desc).Uint()
   217  	ctx.Expect(int(linuxVrf2Mtu)).To(SatisfyAny(Equal(vrf.DefaultVrfDevMTU), Equal(vrf.DefaultVrfDevLegacyMTU)))
   218  
   219  	// try to ping in both VRFs
   220  	ctx.Expect(ctx.PingFromMs(msName, vrfVppIP, PingWithSourceInterface(vrf1Label+tapNameSuffix))).To(Succeed())
   221  	ctx.Expect(ctx.PingFromMs(msName, vrfVppIP, PingWithSourceInterface(vrf2Label+tapNameSuffix))).To(Succeed())
   222  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   223  
   224  	// restart microservice
   225  	ctx.StopMicroservice(msName)
   226  	ctx.Eventually(ctx.GetValueStateClb(vrf1LinuxTap)).Should(Equal(kvscheduler.ValueState_PENDING))
   227  	ctx.Eventually(ctx.GetValueStateClb(vrf2LinuxTap)).Should(Equal(kvscheduler.ValueState_PENDING))
   228  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   229  
   230  	ctx.StartMicroservice(msName)
   231  	ctx.Eventually(ctx.GetValueStateClb(vrf1LinuxTap)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   232  	ctx.Eventually(ctx.GetValueStateClb(vrf2LinuxTap)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   233  	ctx.Expect(ctx.PingFromMs(msName, vrfVppIP, PingWithSourceInterface(vrf1Label+tapNameSuffix))).To(Succeed())
   234  	ctx.Expect(ctx.PingFromMs(msName, vrfVppIP, PingWithSourceInterface(vrf2Label+tapNameSuffix))).To(Succeed())
   235  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   236  
   237  	// re-create Linux VRF1
   238  	err = ctx.GenericClient().ChangeRequest().
   239  		Delete(linuxVrf1).Send(context.Background())
   240  	ctx.Expect(err).ToNot(HaveOccurred())
   241  	ctx.Expect(ctx.PingFromMs(msName, vrfVppIP, PingWithSourceInterface(vrf1Label+tapNameSuffix))).ToNot(Succeed())
   242  	ctx.Expect(ctx.PingFromMs(msName, vrfVppIP, PingWithSourceInterface(vrf2Label+tapNameSuffix))).To(Succeed())
   243  
   244  	err = ctx.GenericClient().ChangeRequest().Update(
   245  		linuxVrf1Updated,
   246  	).Send(context.Background())
   247  	ctx.Expect(err).ToNot(HaveOccurred())
   248  
   249  	// vrf 1 mtu re-check
   250  	linuxVrf1Msg = ctx.GetValue(linuxVrf1, kvs.SBView).ProtoReflect()
   251  	linuxVrf1Desc = linuxVrf1Msg.Descriptor().Fields().ByTextName("mtu")
   252  	linuxVrf1Mtu = linuxVrf1Msg.Get(linuxVrf1Desc).Uint()
   253  	ctx.Expect(uint32(linuxVrf1Mtu)).To(Equal(vrf1Mtu))
   254  
   255  	ctx.Eventually(ctx.PingFromMsClb(msName, vrfVppIP, PingWithSourceInterface(vrf1Label+tapNameSuffix))).Should(Succeed())
   256  	ctx.Expect(ctx.PingFromMs(msName, vrfVppIP, PingWithSourceInterface(vrf2Label+tapNameSuffix))).To(Succeed())
   257  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   258  }
   259  
   260  // +--------------------------------------------------------------------------------+
   261  // | VPP                           inter-VRF RT:                                    |
   262  // | +-------------------------------+  .2.0/24   +-------------------------------+ |
   263  // | | VRF 1                         | ---------> | VRF 2                         | |
   264  // | |        +-------------------+  |            |        +-------------------+  | |
   265  // | |        |  192.168.1.1/24   |  |  .1.0/24   |        |  192.168.2.1./24  |  | |
   266  // | |        +---------+---------+  | <--------- |        +----------+--------+  | |
   267  // | +------------------|------------+            +-------------------|-----------+ |
   268  // +--------------------|---------------------------------------------|-------------+
   269  // Linux                | (TAP)                                       | (TAP)
   270  // +--------------------|----------+            +---------------------|---------+
   271  // | VRF_1              |          |            | VRF_2               |         |
   272  // |        +-----------+-------+  |            |         +-----------+------+  |
   273  // |        |  192.168.1.2/24   |  |            |         |  192.168.2.2/24  |  |
   274  // |        +-------------------+  |            |         +------------------+  |
   275  // |                         ^     |            |                         ^     |
   276  // |                         |     |            |                         |     |
   277  // |    RT: 192.168.2.0/24 --+     |            |    RT: 192.168.1.0/24 --+     |
   278  // +-------------------------------+            +-------------------------------+
   279  func TestVRFRoutes(t *testing.T) {
   280  	if !SupportsLinuxVRF() {
   281  		t.Skip("Linux VRFs are not supported")
   282  	}
   283  
   284  	ctx := Setup(t)
   285  	defer ctx.Teardown()
   286  
   287  	const (
   288  		vrf1ID        = 1
   289  		vrf2ID        = 2
   290  		vrf1Label     = "vrf-1"
   291  		vrf2Label     = "vrf-2"
   292  		vrfSubnetMask = "/24"
   293  		vrf1Subnet    = "192.168.1.0" + vrfSubnetMask
   294  		vrf1VppIP     = "192.168.1.1"
   295  		vrf1LinuxIP   = "192.168.1.2"
   296  		vrf2Subnet    = "192.168.2.0" + vrfSubnetMask
   297  		vrf2VppIP     = "192.168.2.1"
   298  		vrf2LinuxIP   = "192.168.2.2"
   299  		tapNameSuffix = "-tap"
   300  		msName        = "microservice1"
   301  	)
   302  
   303  	// TAP interfaces
   304  	vrf1VppTap := &vpp_interfaces.Interface{
   305  		Name:        vrf1Label + tapNameSuffix,
   306  		Type:        vpp_interfaces.Interface_TAP,
   307  		Enabled:     true,
   308  		Vrf:         vrf1ID,
   309  		IpAddresses: []string{vrf1VppIP + vrfSubnetMask},
   310  		Link: &vpp_interfaces.Interface_Tap{
   311  			Tap: &vpp_interfaces.TapLink{
   312  				Version:        2,
   313  				ToMicroservice: MsNamePrefix + msName,
   314  			},
   315  		},
   316  	}
   317  	vrf1LinuxTap := &linux_interfaces.Interface{
   318  		Name:               vrf1Label + tapNameSuffix,
   319  		Type:               linux_interfaces.Interface_TAP_TO_VPP,
   320  		Enabled:            true,
   321  		VrfMasterInterface: vrf1Label,
   322  		IpAddresses:        []string{vrf1LinuxIP + vrfSubnetMask},
   323  		Link: &linux_interfaces.Interface_Tap{
   324  			Tap: &linux_interfaces.TapLink{
   325  				VppTapIfName: vrf1Label + tapNameSuffix,
   326  			},
   327  		},
   328  		Namespace: &linux_namespace.NetNamespace{
   329  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   330  			Reference: MsNamePrefix + msName,
   331  		},
   332  	}
   333  	vrf2VppTap := &vpp_interfaces.Interface{
   334  		Name:        vrf2Label + tapNameSuffix,
   335  		Type:        vpp_interfaces.Interface_TAP,
   336  		Enabled:     true,
   337  		Vrf:         vrf2ID,
   338  		IpAddresses: []string{vrf2VppIP + vrfSubnetMask},
   339  		Link: &vpp_interfaces.Interface_Tap{
   340  			Tap: &vpp_interfaces.TapLink{
   341  				Version:        2,
   342  				ToMicroservice: MsNamePrefix + msName,
   343  			},
   344  		},
   345  	}
   346  	vrf2LinuxTap := &linux_interfaces.Interface{
   347  		Name:               vrf2Label + tapNameSuffix,
   348  		Type:               linux_interfaces.Interface_TAP_TO_VPP,
   349  		VrfMasterInterface: vrf2Label,
   350  		Enabled:            true,
   351  		IpAddresses:        []string{vrf2LinuxIP + vrfSubnetMask},
   352  		Link: &linux_interfaces.Interface_Tap{
   353  			Tap: &linux_interfaces.TapLink{
   354  				VppTapIfName: vrf2Label + tapNameSuffix,
   355  			},
   356  		},
   357  		Namespace: &linux_namespace.NetNamespace{
   358  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   359  			Reference: MsNamePrefix + msName,
   360  		},
   361  	}
   362  
   363  	// VRFs
   364  	vppVrf1 := &vpp_l3.VrfTable{
   365  		Id:       vrf1ID,
   366  		Label:    vrf1Label,
   367  		Protocol: vpp_l3.VrfTable_IPV4,
   368  	}
   369  	vppVrf2 := &vpp_l3.VrfTable{
   370  		Id:       vrf2ID,
   371  		Label:    vrf2Label,
   372  		Protocol: vpp_l3.VrfTable_IPV4,
   373  	}
   374  	linuxVrf1 := &linux_interfaces.Interface{
   375  		Name:    vrf1Label,
   376  		Type:    linux_interfaces.Interface_VRF_DEVICE,
   377  		Enabled: true,
   378  		Link: &linux_interfaces.Interface_VrfDev{
   379  			VrfDev: &linux_interfaces.VrfDevLink{
   380  				RoutingTable: vrf1ID,
   381  			},
   382  		},
   383  		Namespace: &linux_namespace.NetNamespace{
   384  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   385  			Reference: MsNamePrefix + msName,
   386  		},
   387  	}
   388  	linuxVrf2 := &linux_interfaces.Interface{
   389  		Name:    vrf2Label,
   390  		Type:    linux_interfaces.Interface_VRF_DEVICE,
   391  		Enabled: true,
   392  		Link: &linux_interfaces.Interface_VrfDev{
   393  			VrfDev: &linux_interfaces.VrfDevLink{
   394  				RoutingTable: vrf2ID,
   395  			},
   396  		},
   397  		Namespace: &linux_namespace.NetNamespace{
   398  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
   399  			Reference: MsNamePrefix + msName,
   400  		},
   401  	}
   402  
   403  	// Routes
   404  	vrf1VppRoute := &vpp_l3.Route{
   405  		Type:        vpp_l3.Route_INTER_VRF,
   406  		VrfId:       vrf1ID,
   407  		DstNetwork:  vrf2Subnet,
   408  		NextHopAddr: vrf2LinuxIP,
   409  		ViaVrfId:    vrf2ID,
   410  	}
   411  	vrf2VppRoute := &vpp_l3.Route{
   412  		Type:        vpp_l3.Route_INTER_VRF,
   413  		VrfId:       vrf2ID,
   414  		DstNetwork:  vrf1Subnet,
   415  		NextHopAddr: vrf1LinuxIP,
   416  		ViaVrfId:    vrf1ID,
   417  	}
   418  	vrf1LinuxRoute := &linux_l3.Route{
   419  		OutgoingInterface: vrf1Label + tapNameSuffix,
   420  		Scope:             linux_l3.Route_GLOBAL,
   421  		DstNetwork:        vrf2Subnet,
   422  		GwAddr:            vrf1VppIP,
   423  	}
   424  	vrf2LinuxRoute := &linux_l3.Route{
   425  		OutgoingInterface: vrf2Label + tapNameSuffix,
   426  		Scope:             linux_l3.Route_GLOBAL,
   427  		DstNetwork:        vrf1Subnet,
   428  		GwAddr:            vrf2VppIP,
   429  	}
   430  
   431  	ctx.StartMicroservice(msName)
   432  
   433  	// configure everything in one resync
   434  	err := ctx.GenericClient().ResyncConfig(
   435  		vppVrf1, vppVrf2,
   436  		linuxVrf1, linuxVrf2,
   437  		vrf1VppTap, vrf1LinuxTap,
   438  		vrf2VppTap, vrf2LinuxTap,
   439  		vrf1VppRoute, vrf2VppRoute,
   440  		vrf1LinuxRoute, vrf2LinuxRoute,
   441  	)
   442  	ctx.Expect(err).ToNot(HaveOccurred())
   443  
   444  	ctx.Eventually(ctx.GetValueStateClb(vrf1LinuxTap)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   445  	ctx.Expect(ctx.GetValueState(vrf1VppTap)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   446  	ctx.Expect(ctx.GetValueState(vrf2LinuxTap)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   447  	ctx.Expect(ctx.GetValueState(vrf2VppTap)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   448  	ctx.Expect(ctx.GetValueState(vrf1VppRoute)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   449  	ctx.Expect(ctx.GetValueState(vrf2VppRoute)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   450  	ctx.Expect(ctx.GetValueState(vrf1LinuxRoute)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   451  	ctx.Expect(ctx.GetValueState(vrf2LinuxRoute)).To(Equal(kvscheduler.ValueState_CONFIGURED))
   452  
   453  	// try to ping across VRFs
   454  	ctx.Expect(ctx.PingFromMs(msName, vrf2LinuxIP, PingWithSourceInterface(vrf1Label+tapNameSuffix))).To(Succeed())
   455  	ctx.Expect(ctx.PingFromMs(msName, vrf1LinuxIP, PingWithSourceInterface(vrf2Label+tapNameSuffix))).To(Succeed())
   456  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   457  
   458  	// restart microservice
   459  	ctx.StopMicroservice(msName)
   460  	ctx.Eventually(ctx.GetValueStateClb(vrf1LinuxTap)).Should(Equal(kvscheduler.ValueState_PENDING))
   461  	ctx.Eventually(ctx.GetValueStateClb(vrf2LinuxTap)).Should(Equal(kvscheduler.ValueState_PENDING))
   462  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   463  
   464  	ctx.StartMicroservice(msName)
   465  	ctx.Eventually(ctx.GetValueStateClb(vrf1LinuxTap)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   466  	ctx.Eventually(ctx.GetValueStateClb(vrf2LinuxTap)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   467  	ctx.Expect(ctx.PingFromMs(msName, vrf2LinuxIP, PingWithSourceInterface(vrf1Label+tapNameSuffix))).To(Succeed())
   468  	ctx.Expect(ctx.PingFromMs(msName, vrf1LinuxIP, PingWithSourceInterface(vrf2Label+tapNameSuffix))).To(Succeed())
   469  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   470  
   471  	// re-create Linux VRF1
   472  	err = ctx.GenericClient().ChangeRequest().
   473  		Delete(linuxVrf1).Send(context.Background())
   474  	ctx.Expect(err).ToNot(HaveOccurred())
   475  	ctx.Expect(ctx.PingFromMs(msName, vrf2LinuxIP, PingWithSourceInterface(vrf1Label+tapNameSuffix))).ToNot(Succeed())
   476  	ctx.Expect(ctx.PingFromMs(msName, vrf1LinuxIP, PingWithSourceInterface(vrf2Label+tapNameSuffix))).ToNot(Succeed())
   477  
   478  	err = ctx.GenericClient().ChangeRequest().Update(
   479  		linuxVrf1,
   480  	).Send(context.Background())
   481  	ctx.Expect(err).ToNot(HaveOccurred())
   482  	ctx.Eventually(ctx.PingFromMsClb(msName, vrf2LinuxIP, PingWithSourceInterface(vrf1Label+tapNameSuffix))).Should(Succeed())
   483  	ctx.Expect(ctx.PingFromMs(msName, vrf1LinuxIP, PingWithSourceInterface(vrf2Label+tapNameSuffix))).To(Succeed())
   484  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   485  }
   486  
   487  // Test VRF created externally (i.e. not by the agent).
   488  func TestExistingLinuxVRF(t *testing.T) {
   489  	if !SupportsLinuxVRF() {
   490  		t.Skip("Linux VRFs are not supported")
   491  	}
   492  
   493  	ctx := Setup(t)
   494  	defer ctx.Teardown()
   495  
   496  	SetDefaultConsistentlyDuration(3 * time.Second)
   497  	SetDefaultConsistentlyPollingInterval(time.Second)
   498  
   499  	const (
   500  		vrfName           = "existing-vrf"
   501  		vrfHostName       = "vrf"
   502  		vrfRT             = 10
   503  		vrfIface1Name     = "existing-dummy1"
   504  		vrfIface1HostName = "dummy1"
   505  		vrfIface2Name     = "dummy2"
   506  		ipAddr1           = "192.168.7.7"
   507  		ipAddr2           = "10.7.7.7"
   508  		ipAddr3           = "172.16.7.7"
   509  		netMask           = "/24"
   510  	)
   511  
   512  	existingVrf := &linux_interfaces.Interface{
   513  		Name:       vrfName,
   514  		Type:       linux_interfaces.Interface_EXISTING,
   515  		Enabled:    true,
   516  		HostIfName: vrfHostName,
   517  		LinkOnly:   true,
   518  	}
   519  
   520  	existingIface1 := &linux_interfaces.Interface{
   521  		Name:               vrfIface1Name,
   522  		Type:               linux_interfaces.Interface_EXISTING,
   523  		Enabled:            true,
   524  		LinkOnly:           true, // wait for IP addresses, do not configure them
   525  		IpAddresses:        []string{ipAddr1 + netMask, ipAddr2 + netMask},
   526  		HostIfName:         vrfIface1HostName,
   527  		VrfMasterInterface: vrfName,
   528  	}
   529  
   530  	iface2 := &linux_interfaces.Interface{
   531  		Name:               vrfIface2Name,
   532  		Type:               linux_interfaces.Interface_DUMMY,
   533  		Enabled:            true,
   534  		IpAddresses:        []string{ipAddr3 + netMask},
   535  		VrfMasterInterface: vrfName,
   536  	}
   537  
   538  	ipAddr1Key := linux_interfaces.InterfaceAddressKey(
   539  		vrfIface1Name, ipAddr1+netMask, netalloc_api.IPAddressSource_EXISTING)
   540  	ipAddr2Key := linux_interfaces.InterfaceAddressKey(
   541  		vrfIface1Name, ipAddr2+netMask, netalloc_api.IPAddressSource_EXISTING)
   542  	ipAddr3Key := linux_interfaces.InterfaceAddressKey(
   543  		vrfIface2Name, ipAddr3+netMask, netalloc_api.IPAddressSource_STATIC)
   544  	iface1InVrfKey := linux_interfaces.InterfaceVrfKey(vrfIface1Name, vrfName)
   545  	iface2InVrfKey := linux_interfaces.InterfaceVrfKey(vrfIface2Name, vrfName)
   546  
   547  	// configure everything in one resync
   548  	err := ctx.GenericClient().ResyncConfig(
   549  		existingVrf,
   550  		existingIface1,
   551  		iface2,
   552  	)
   553  	ctx.Expect(err).ToNot(HaveOccurred())
   554  
   555  	// the referenced VRF with interface does not exist yet
   556  	ctx.Expect(ctx.GetValueState(existingVrf)).To(Equal(kvscheduler.ValueState_PENDING))
   557  	ctx.Expect(ctx.GetValueState(existingIface1)).To(Equal(kvscheduler.ValueState_PENDING))
   558  	ctx.Expect(ctx.GetValueState(iface2)).To(Equal(kvscheduler.ValueState_CONFIGURED)) // created but not in VRF yet
   559  	ctx.Expect(ctx.GetDerivedValueState(iface2, iface2InVrfKey)).To(Equal(kvscheduler.ValueState_PENDING))
   560  
   561  	ifHandler := ctx.Agent.LinuxInterfaceHandler()
   562  
   563  	// create referenced VRF using netlink (without the interface inside it for now)
   564  	err = ifHandler.AddVRFDevice(vrfHostName, vrfRT)
   565  	ctx.Expect(err).To(BeNil())
   566  	err = ifHandler.SetInterfaceUp(vrfHostName)
   567  	ctx.Expect(err).To(BeNil())
   568  
   569  	ctx.Eventually(ctx.GetValueStateClb(existingVrf)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   570  	ctx.Expect(ctx.GetValueMetadata(existingVrf, kvs.CachedView)).To(
   571  		HaveKeyWithValue(BeEquivalentTo("VrfDevRT"), BeEquivalentTo(vrfRT)))
   572  	ctx.Eventually(ctx.GetDerivedValueStateClb(iface2, iface2InVrfKey)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   573  	ctx.Expect(ctx.GetValueMetadata(iface2, kvs.CachedView)).To(
   574  		HaveKeyWithValue(BeEquivalentTo("VrfMasterIf"), BeEquivalentTo(vrfName)))
   575  	ctx.Eventually(ctx.GetDerivedValueStateClb(iface2, ipAddr3Key)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   576  	ctx.Consistently(ctx.GetValueStateClb(existingIface1)).Should(Equal(kvscheduler.ValueState_PENDING))
   577  
   578  	// re-check metadata after resync
   579  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   580  	ctx.Expect(ctx.GetValueMetadata(existingVrf, kvs.CachedView)).To(
   581  		HaveKeyWithValue(BeEquivalentTo("VrfDevRT"), BeEquivalentTo(vrfRT)))
   582  	ctx.Expect(ctx.GetValueMetadata(iface2, kvs.CachedView)).To(
   583  		HaveKeyWithValue(BeEquivalentTo("VrfMasterIf"), BeEquivalentTo(vrfName)))
   584  
   585  	// create vrfIface1 but do not put it into VRF yet
   586  	err = ifHandler.AddDummyInterface(vrfIface1HostName)
   587  	ctx.Expect(err).To(BeNil())
   588  	err = ifHandler.SetInterfaceUp(vrfIface1HostName)
   589  	ctx.Expect(err).To(BeNil())
   590  
   591  	ctx.Eventually(ctx.GetValueStateClb(existingIface1)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   592  	ctx.Expect(ctx.GetValueMetadata(existingIface1, kvs.CachedView)).To(
   593  		HaveKeyWithValue(BeEquivalentTo("VrfMasterIf"), BeEquivalentTo(vrfName)))
   594  	ctx.Expect(ctx.GetDerivedValueState(existingIface1, iface1InVrfKey)).To(Equal(kvscheduler.ValueState_PENDING))
   595  
   596  	// put interface into VRF (without IPs for now)
   597  	err = ifHandler.PutInterfaceIntoVRF(vrfIface1HostName, vrfHostName)
   598  	ctx.Expect(err).To(BeNil())
   599  
   600  	ctx.Eventually(ctx.GetDerivedValueStateClb(existingIface1, iface1InVrfKey)).
   601  		Should(Equal(kvscheduler.ValueState_CONFIGURED))
   602  	ctx.Consistently(ctx.GetDerivedValueStateClb(existingIface1, ipAddr1Key)).
   603  		Should(Equal(kvscheduler.ValueState_PENDING))
   604  	ctx.Consistently(ctx.GetDerivedValueStateClb(existingIface1, ipAddr2Key)).
   605  		Should(Equal(kvscheduler.ValueState_PENDING))
   606  
   607  	// re-check metadata after resync
   608  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   609  	ctx.Expect(ctx.GetValueMetadata(existingVrf, kvs.CachedView)).To(
   610  		HaveKeyWithValue(BeEquivalentTo("VrfDevRT"), BeEquivalentTo(vrfRT)))
   611  	ctx.Expect(ctx.GetValueMetadata(existingIface1, kvs.CachedView)).To(
   612  		HaveKeyWithValue(BeEquivalentTo("VrfMasterIf"), BeEquivalentTo(vrfName)))
   613  	ctx.Expect(ctx.GetValueMetadata(iface2, kvs.CachedView)).To(
   614  		HaveKeyWithValue(BeEquivalentTo("VrfMasterIf"), BeEquivalentTo(vrfName)))
   615  
   616  	// add ipAddr1
   617  	ipAddr, _, err := utils.ParseIPAddr(ipAddr1+netMask, nil)
   618  	ctx.Expect(err).ToNot(HaveOccurred())
   619  	err = ifHandler.AddInterfaceIP(vrfIface1HostName, ipAddr)
   620  	ctx.Expect(err).ToNot(HaveOccurred())
   621  
   622  	ctx.Eventually(ctx.GetDerivedValueStateClb(existingIface1, ipAddr1Key)).
   623  		Should(Equal(kvscheduler.ValueState_CONFIGURED))
   624  	ctx.Consistently(ctx.GetDerivedValueStateClb(existingIface1, ipAddr2Key)).
   625  		Should(Equal(kvscheduler.ValueState_PENDING))
   626  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   627  
   628  	// add ipAddr2
   629  	ipAddr, _, err = utils.ParseIPAddr(ipAddr2+netMask, nil)
   630  	ctx.Expect(err).ToNot(HaveOccurred())
   631  	err = ifHandler.AddInterfaceIP(vrfIface1HostName, ipAddr)
   632  	ctx.Expect(err).ToNot(HaveOccurred())
   633  
   634  	ctx.Eventually(ctx.GetDerivedValueStateClb(existingIface1, ipAddr1Key)).
   635  		Should(Equal(kvscheduler.ValueState_CONFIGURED))
   636  	ctx.Eventually(ctx.GetDerivedValueStateClb(existingIface1, ipAddr2Key)).
   637  		Should(Equal(kvscheduler.ValueState_CONFIGURED))
   638  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   639  
   640  	// cleanup
   641  	req := ctx.GenericClient().ChangeRequest()
   642  	err = req.Delete(
   643  		existingVrf,
   644  		existingIface1,
   645  		iface2,
   646  	).Send(context.Background())
   647  	ctx.Expect(err).ToNot(HaveOccurred())
   648  	err = ifHandler.DeleteInterface(vrfIface1HostName)
   649  	ctx.Expect(err).ToNot(HaveOccurred())
   650  	err = ifHandler.DeleteInterface(vrfHostName)
   651  	ctx.Expect(err).ToNot(HaveOccurred())
   652  }