go.ligato.io/vpp-agent/v3@v3.5.0/tests/e2e/012_linux_interfaces_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  	"go.ligato.io/vpp-agent/v3/plugins/netalloc/utils"
    25  	"go.ligato.io/vpp-agent/v3/proto/ligato/kvscheduler"
    26  	linux_interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces"
    27  	linux_namespace "go.ligato.io/vpp-agent/v3/proto/ligato/linux/namespace"
    28  	netalloc_api "go.ligato.io/vpp-agent/v3/proto/ligato/netalloc"
    29  	. "go.ligato.io/vpp-agent/v3/tests/e2e/e2etest"
    30  )
    31  
    32  // Test dummy interfaces (additional loopbacks).
    33  func TestDummyInterface(t *testing.T) {
    34  	ctx := Setup(t)
    35  	defer ctx.Teardown()
    36  
    37  	const (
    38  		dummy1Hostname = "lo1"
    39  		dummy2Hostname = "lo2"
    40  		ipAddr1        = "192.168.7.7"
    41  		ipAddr2        = "10.7.7.7"
    42  		ipAddr3        = "10.8.8.8"
    43  		netMask        = "/24"
    44  		msName         = "microservice1"
    45  	)
    46  
    47  	dummyIf1 := &linux_interfaces.Interface{
    48  		Name:        "dummy1",
    49  		Type:        linux_interfaces.Interface_DUMMY,
    50  		Enabled:     true,
    51  		IpAddresses: []string{ipAddr1 + netMask, ipAddr2 + netMask},
    52  		HostIfName:  dummy1Hostname,
    53  		Namespace: &linux_namespace.NetNamespace{
    54  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
    55  			Reference: MsNamePrefix + msName,
    56  		},
    57  	}
    58  	dummyIf2 := &linux_interfaces.Interface{
    59  		Name:        "dummy2",
    60  		Type:        linux_interfaces.Interface_DUMMY,
    61  		Enabled:     true,
    62  		IpAddresses: []string{ipAddr3 + netMask},
    63  		HostIfName:  dummy2Hostname,
    64  		Namespace: &linux_namespace.NetNamespace{
    65  			Type:      linux_namespace.NetNamespace_MICROSERVICE,
    66  			Reference: MsNamePrefix + msName,
    67  		},
    68  	}
    69  
    70  	ctx.StartMicroservice(msName)
    71  	req := ctx.GenericClient().ChangeRequest()
    72  	err := req.Update(
    73  		dummyIf1,
    74  		dummyIf2,
    75  	).Send(context.Background())
    76  	ctx.Expect(err).ToNot(HaveOccurred())
    77  
    78  	ctx.Eventually(ctx.GetValueStateClb(dummyIf1)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
    79  	ctx.Expect(ctx.GetValueState(dummyIf2)).To(Equal(kvscheduler.ValueState_CONFIGURED))
    80  	ctx.Expect(ctx.PingFromMs(msName, ipAddr1)).To(Succeed())
    81  	ctx.Expect(ctx.PingFromMs(msName, ipAddr2)).To(Succeed())
    82  	ctx.Expect(ctx.PingFromMs(msName, ipAddr3)).To(Succeed())
    83  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
    84  
    85  	// Delete dummy2
    86  	req = ctx.GenericClient().ChangeRequest()
    87  	err = req.Delete(
    88  		dummyIf2,
    89  	).Send(context.Background())
    90  	ctx.Expect(err).ToNot(HaveOccurred())
    91  
    92  	ctx.Expect(ctx.GetValueState(dummyIf1)).To(Equal(kvscheduler.ValueState_CONFIGURED))
    93  	ctx.Expect(ctx.GetValueState(dummyIf2)).ToNot(Equal(kvscheduler.ValueState_CONFIGURED))
    94  	ctx.Expect(ctx.PingFromMs(msName, ipAddr1)).To(Succeed())
    95  	ctx.Expect(ctx.PingFromMs(msName, ipAddr2)).To(Succeed())
    96  	ctx.Expect(ctx.PingFromMs(msName, ipAddr3)).ToNot(Succeed())
    97  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
    98  
    99  	// restart microservice
   100  	ctx.StopMicroservice(msName)
   101  	ctx.Eventually(ctx.GetValueStateClb(dummyIf1)).Should(Equal(kvscheduler.ValueState_PENDING))
   102  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   103  	ctx.StartMicroservice(msName)
   104  	ctx.Eventually(ctx.GetValueStateClb(dummyIf1)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   105  	ctx.Expect(ctx.PingFromMs(msName, ipAddr1)).To(Succeed())
   106  	ctx.Expect(ctx.PingFromMs(msName, ipAddr2)).To(Succeed())
   107  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   108  
   109  	// Disable dummy1
   110  	dummyIf1.Enabled = false
   111  	req = ctx.GenericClient().ChangeRequest()
   112  	err = req.Update(
   113  		dummyIf1,
   114  	).Send(context.Background())
   115  	ctx.Expect(err).ToNot(HaveOccurred())
   116  }
   117  
   118  // Test interfaces created externally but with IP addresses assigned by the agent.
   119  func TestExistingInterface(t *testing.T) {
   120  	ctx := Setup(t)
   121  	defer ctx.Teardown()
   122  
   123  	const (
   124  		ifaceHostName = "loop1"
   125  		ifaceName     = "existing-loop1"
   126  		ipAddr1       = "192.168.7.7"
   127  		ipAddr2       = "10.7.7.7"
   128  		ipAddr3       = "172.16.7.7"
   129  		netMask       = "/24"
   130  	)
   131  
   132  	existingIface := &linux_interfaces.Interface{
   133  		Name:        ifaceName,
   134  		Type:        linux_interfaces.Interface_EXISTING,
   135  		Enabled:     true,
   136  		IpAddresses: []string{ipAddr1 + netMask, ipAddr2 + netMask},
   137  		HostIfName:  ifaceHostName,
   138  	}
   139  
   140  	ifHandler := ctx.Agent.LinuxInterfaceHandler()
   141  
   142  	hasIP := func(ifName, ipAddr string) bool {
   143  		addrs, err := ifHandler.GetAddressList(ifName)
   144  		ctx.Expect(err).ToNot(HaveOccurred())
   145  		for _, addr := range addrs {
   146  			if addr.IP.String() == ipAddr {
   147  				return true
   148  			}
   149  		}
   150  		return false
   151  	}
   152  
   153  	addrKey := func(addr string) string {
   154  		return linux_interfaces.InterfaceAddressKey(
   155  			ifaceName, addr, netalloc_api.IPAddressSource_STATIC)
   156  	}
   157  
   158  	req := ctx.GenericClient().ChangeRequest()
   159  	err := req.Update(
   160  		existingIface,
   161  	).Send(context.Background())
   162  	ctx.Expect(err).ToNot(HaveOccurred())
   163  
   164  	// referenced interface does not exist yet
   165  	ctx.Expect(ctx.GetValueState(existingIface)).To(Equal(kvscheduler.ValueState_PENDING))
   166  
   167  	// create referenced host interface using linuxcalls
   168  	err = ifHandler.AddDummyInterface(ifaceHostName)
   169  	ctx.Expect(err).ToNot(HaveOccurred())
   170  	err = ifHandler.SetInterfaceUp(ifaceHostName)
   171  	ctx.Expect(err).ToNot(HaveOccurred())
   172  
   173  	ctx.Eventually(ctx.GetValueStateClb(existingIface)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   174  	ctx.Eventually(ctx.GetDerivedValueStateClb(existingIface, addrKey(ipAddr1+netMask))).
   175  		Should(Equal(kvscheduler.ValueState_CONFIGURED))
   176  	ctx.Eventually(ctx.GetDerivedValueStateClb(existingIface, addrKey(ipAddr2+netMask))).
   177  		Should(Equal(kvscheduler.ValueState_CONFIGURED))
   178  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   179  
   180  	// check that the IP addresses have been configured
   181  	ctx.Expect(hasIP(ifaceHostName, ipAddr1)).To(BeTrue())
   182  	ctx.Expect(hasIP(ifaceHostName, ipAddr2)).To(BeTrue())
   183  
   184  	// add third IP address externally, it should get removed by resync
   185  	ipAddr, _, err := utils.ParseIPAddr(ipAddr3+netMask, nil)
   186  	ctx.Expect(err).ToNot(HaveOccurred())
   187  	err = ifHandler.AddInterfaceIP(ifaceHostName, ipAddr)
   188  	ctx.Expect(err).ToNot(HaveOccurred())
   189  
   190  	// resync should remove the address that was added externally
   191  	ctx.Expect(ctx.AgentInSync()).To(BeFalse())
   192  	ctx.Expect(hasIP(ifaceHostName, ipAddr1)).To(BeTrue())
   193  	ctx.Expect(hasIP(ifaceHostName, ipAddr2)).To(BeTrue())
   194  	ctx.Expect(hasIP(ifaceHostName, ipAddr3)).To(BeFalse())
   195  
   196  	// remove the EXISTING interface (IP addresses should be unassigned)
   197  	req = ctx.GenericClient().ChangeRequest()
   198  	err = req.Delete(
   199  		existingIface,
   200  	).Send(context.Background())
   201  	ctx.Expect(err).ToNot(HaveOccurred())
   202  	ctx.Expect(ctx.GetValueState(existingIface)).ToNot(Equal(kvscheduler.ValueState_CONFIGURED))
   203  	ctx.Expect(hasIP(ifaceHostName, ipAddr1)).To(BeFalse())
   204  	ctx.Expect(hasIP(ifaceHostName, ipAddr2)).To(BeFalse())
   205  	ctx.Expect(hasIP(ifaceHostName, ipAddr3)).To(BeFalse())
   206  
   207  	// cleanup
   208  	err = ifHandler.DeleteInterface(ifaceHostName)
   209  	ctx.Expect(err).ToNot(HaveOccurred())
   210  }
   211  
   212  // Test interfaces created externally including the IP address assignments.
   213  func TestExistingLinkOnlyInterface(t *testing.T) {
   214  	ctx := Setup(t)
   215  	defer ctx.Teardown()
   216  
   217  	SetDefaultConsistentlyDuration(3 * time.Second)
   218  	SetDefaultConsistentlyPollingInterval(time.Second)
   219  
   220  	const (
   221  		ifaceHostName = "loop1"
   222  		ifaceName     = "existing-loop1"
   223  		ipAddr1       = "192.168.7.7"
   224  		ipAddr2       = "10.7.7.7"
   225  		ipAddr3       = "172.16.7.7"
   226  		netMask       = "/24"
   227  	)
   228  
   229  	existingIface := &linux_interfaces.Interface{
   230  		Name:        ifaceName,
   231  		Type:        linux_interfaces.Interface_EXISTING,
   232  		Enabled:     true,
   233  		IpAddresses: []string{ipAddr1 + netMask, ipAddr2 + netMask, ipAddr3 + netMask},
   234  		HostIfName:  ifaceHostName,
   235  		LinkOnly:    true, // <- agent does not configure IP addresses (they are also "existing")
   236  	}
   237  
   238  	ifHandler := ctx.Agent.LinuxInterfaceHandler()
   239  
   240  	hasIP := func(ifName, ipAddr string) bool {
   241  		addrs, err := ifHandler.GetAddressList(ifName)
   242  		ctx.Expect(err).ToNot(HaveOccurred())
   243  		for _, addr := range addrs {
   244  			if addr.IP.String() == ipAddr {
   245  				return true
   246  			}
   247  		}
   248  		return false
   249  	}
   250  
   251  	addrKey := func(addr string) string {
   252  		return linux_interfaces.InterfaceAddressKey(
   253  			ifaceName, addr, netalloc_api.IPAddressSource_EXISTING)
   254  	}
   255  
   256  	req := ctx.GenericClient().ChangeRequest()
   257  	err := req.Update(
   258  		existingIface,
   259  	).Send(context.Background())
   260  	ctx.Expect(err).ToNot(HaveOccurred())
   261  
   262  	// the referenced interface does not exist yet
   263  	ctx.Expect(ctx.GetValueState(existingIface)).To(Equal(kvscheduler.ValueState_PENDING))
   264  
   265  	// create referenced host interface using linuxcalls (without IPs for now)
   266  	err = ifHandler.AddDummyInterface(ifaceHostName)
   267  	ctx.Expect(err).ToNot(HaveOccurred())
   268  	err = ifHandler.SetInterfaceUp(ifaceHostName)
   269  	ctx.Expect(err).ToNot(HaveOccurred())
   270  
   271  	ctx.Eventually(ctx.GetValueStateClb(existingIface)).Should(Equal(kvscheduler.ValueState_CONFIGURED))
   272  	ctx.Consistently(ctx.GetDerivedValueStateClb(existingIface, addrKey(ipAddr1+netMask))).
   273  		Should(Equal(kvscheduler.ValueState_PENDING))
   274  	ctx.Consistently(ctx.GetDerivedValueStateClb(existingIface, addrKey(ipAddr2+netMask))).
   275  		Should(Equal(kvscheduler.ValueState_PENDING))
   276  	ctx.Consistently(ctx.GetDerivedValueStateClb(existingIface, addrKey(ipAddr3+netMask))).
   277  		Should(Equal(kvscheduler.ValueState_PENDING))
   278  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   279  
   280  	// add IP addresses using linuxcalls (except ipAddr3)
   281  	ctx.Expect(hasIP(ifaceHostName, ipAddr1)).To(BeFalse())
   282  	ctx.Expect(hasIP(ifaceHostName, ipAddr2)).To(BeFalse())
   283  	ctx.Expect(hasIP(ifaceHostName, ipAddr3)).To(BeFalse())
   284  	ipAddr, _, err := utils.ParseIPAddr(ipAddr1+netMask, nil)
   285  	ctx.Expect(err).ToNot(HaveOccurred())
   286  	err = ifHandler.AddInterfaceIP(ifaceHostName, ipAddr)
   287  	ctx.Expect(err).ToNot(HaveOccurred())
   288  	ipAddr, _, err = utils.ParseIPAddr(ipAddr2+netMask, nil)
   289  	ctx.Expect(err).ToNot(HaveOccurred())
   290  	err = ifHandler.AddInterfaceIP(ifaceHostName, ipAddr)
   291  	ctx.Expect(err).ToNot(HaveOccurred())
   292  
   293  	// ipAddr1 and ipAddr2 should be eventually marked as configured
   294  	ctx.Eventually(ctx.GetDerivedValueStateClb(existingIface, addrKey(ipAddr1+netMask))).
   295  		Should(Equal(kvscheduler.ValueState_CONFIGURED))
   296  	ctx.Eventually(ctx.GetDerivedValueStateClb(existingIface, addrKey(ipAddr2+netMask))).
   297  		Should(Equal(kvscheduler.ValueState_CONFIGURED))
   298  	ctx.Consistently(ctx.GetDerivedValueStateClb(existingIface, addrKey(ipAddr3+netMask))).
   299  		Should(Equal(kvscheduler.ValueState_PENDING))
   300  	ctx.Expect(ctx.AgentInSync()).To(BeTrue())
   301  
   302  	// remove one IP address
   303  	ipAddr, _, err = utils.ParseIPAddr(ipAddr1+netMask, nil)
   304  	ctx.Expect(err).ToNot(HaveOccurred())
   305  	err = ifHandler.DelInterfaceIP(ifaceHostName, ipAddr)
   306  	ctx.Expect(err).ToNot(HaveOccurred())
   307  	ctx.Eventually(ctx.GetDerivedValueStateClb(existingIface, addrKey(ipAddr1+netMask))).
   308  		Should(Equal(kvscheduler.ValueState_PENDING))
   309  	ctx.Consistently(ctx.GetDerivedValueStateClb(existingIface, addrKey(ipAddr2+netMask))).
   310  		Should(Equal(kvscheduler.ValueState_CONFIGURED))
   311  	ctx.Consistently(ctx.GetDerivedValueStateClb(existingIface, addrKey(ipAddr3+netMask))).
   312  		Should(Equal(kvscheduler.ValueState_PENDING))
   313  
   314  	// remove the EXISTING interface (the actual interface should be left untouched including IPs)
   315  	req = ctx.GenericClient().ChangeRequest()
   316  	err = req.Delete(
   317  		existingIface,
   318  	).Send(context.Background())
   319  	ctx.Expect(err).ToNot(HaveOccurred())
   320  	ctx.Expect(ctx.GetValueState(existingIface)).ToNot(Equal(kvscheduler.ValueState_CONFIGURED))
   321  	ctx.Expect(hasIP(ifaceHostName, ipAddr1)).To(BeFalse())
   322  	ctx.Expect(hasIP(ifaceHostName, ipAddr2)).To(BeTrue())
   323  	ctx.Expect(hasIP(ifaceHostName, ipAddr3)).To(BeFalse())
   324  
   325  	// cleanup
   326  	err = ifHandler.DeleteInterface(ifaceHostName)
   327  	ctx.Expect(err).ToNot(HaveOccurred())
   328  }