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 }