diff --git a/plugins/vpp/l3plugin/descriptor/proxy_arp.go b/plugins/vpp/l3plugin/descriptor/proxy_arp.go index 939737d1c2..184115cb59 100644 --- a/plugins/vpp/l3plugin/descriptor/proxy_arp.go +++ b/plugins/vpp/l3plugin/descriptor/proxy_arp.go @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Cisco and/or its affiliates. +// Copyright (c) 2020 Cisco and/or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -32,6 +32,21 @@ import ( const ( // ProxyArpDescriptorName is the name of the descriptor. ProxyArpDescriptorName = "vpp-proxy-arp" + + // Dependency labels: + vrfTableProxyARPDep = "vrf-table-exists" +) + +// Validation errors: +var ( + // ErrMissingIP returned when one of IP fields in ProxyARP range is not set. + ErrMissingIP = errors.New("missing IP address") + // ErrIPWithMask returned when one of IP fields in ProxyARP range is set with a subnet mask. + ErrIPWithMask = errors.New("only one IP must be defined (e.g. \"192.0.2.1\"), not a subnet") + // ErrInvalidIP returned when one of IP fields in ProxyARP range can not be parsed. + ErrInvalidIP = errors.New("invalid IP address") + // ErrIPv6NotSupported returned when one of IP fields in ProxyARP range is defined as IPv6. + ErrIPv6NotSupported = errors.New("IP address must be IPv4, not IPv6") ) // ProxyArpDescriptor teaches KVScheduler how to configure VPP proxy ARPs. @@ -57,19 +72,73 @@ func NewProxyArpDescriptor(scheduler kvs.KVScheduler, ValueTypeName: l3.ModelProxyARP.ProtoName(), KeySelector: l3.ModelProxyARP.IsKeyValid, ValueComparator: ctx.EquivalentProxyArps, + Validate: ctx.Validate, Create: ctx.Create, Update: ctx.Update, Delete: ctx.Delete, Retrieve: ctx.Retrieve, + Dependencies: ctx.Dependencies, DerivedValues: ctx.DerivedValues, RetrieveDependencies: []string{ifdescriptor.InterfaceDescriptorName}, } return adapter.NewProxyARPDescriptor(typedDescr) } -// DerivedValues derives l3.ProxyARP_Interface for every interface.. +// Validate validates ProxyARP setup. +func (d *ProxyArpDescriptor) Validate(key string, proxyArp *l3.ProxyARP) error { + for _, r := range proxyArp.Ranges { + if r.FirstIpAddr == "" { + return kvs.NewInvalidValueError(ErrMissingIP, "ranges.first_ip_addr") + } + if r.LastIpAddr == "" { + return kvs.NewInvalidValueError(ErrMissingIP, "ranges.last_ip_addr") + } + + if strings.Contains(r.FirstIpAddr, "/") { + return kvs.NewInvalidValueError(ErrIPWithMask, "ranges.first_ip_addr") + } + if strings.Contains(r.LastIpAddr, "/") { + return kvs.NewInvalidValueError(ErrIPWithMask, "ranges.last_ip_addr") + } + + firstIP := net.ParseIP(r.FirstIpAddr) + if firstIP == nil { + return kvs.NewInvalidValueError(ErrInvalidIP, "ranges.first_ip_addr") + } + lastIP := net.ParseIP(r.LastIpAddr) + if lastIP == nil { + return kvs.NewInvalidValueError(ErrInvalidIP, "ranges.last_ip_addr") + } + + if firstIP.To4() == nil { + return kvs.NewInvalidValueError(ErrIPv6NotSupported, "ranges.first_ip_addr") + } + if lastIP.To4() == nil { + return kvs.NewInvalidValueError(ErrIPv6NotSupported, "ranges.last_ip_addr") + } + } + return nil +} + +// Dependencies lists dependencies for a VPP Proxy ARP. +func (d *ProxyArpDescriptor) Dependencies(key string, proxyArp *l3.ProxyARP) []kvs.Dependency { + var dependencies []kvs.Dependency + + for _, r := range proxyArp.Ranges { + if r.VrfId == 0 { + continue + } + dependencies = append(dependencies, kvs.Dependency{ + Label: vrfTableProxyARPDep, + Key: l3.VrfTableKey(r.VrfId, l3.VrfTable_IPV4), + }) + } + + return dependencies +} + +// DerivedValues derives l3.ProxyARP_Interface for every interface. func (d *ProxyArpDescriptor) DerivedValues(key string, proxyArp *l3.ProxyARP) (derValues []kvs.KeyValuePair) { - // IP addresses for _, iface := range proxyArp.Interfaces { derValues = append(derValues, kvs.KeyValuePair{ Key: l3.ProxyARPInterfaceKey(iface.Name), @@ -90,16 +159,12 @@ func (d *ProxyArpDescriptor) EquivalentProxyArps(key string, oldValue, newValue // Create adds VPP Proxy ARP. func (d *ProxyArpDescriptor) Create(key string, value *l3.ProxyARP) (metadata interface{}, err error) { - for _, proxyArpRange := range value.Ranges { - // Prune addresses - firstIP := pruneIP(proxyArpRange.FirstIpAddr) - lastIP := pruneIP(proxyArpRange.LastIpAddr) - // Convert to byte representation - bFirstIP := net.ParseIP(firstIP).To4() - bLastIP := net.ParseIP(lastIP).To4() - // Call VPP API to configure IP range for proxy ARP - if err := d.proxyArpHandler.AddProxyArpRange(bFirstIP, bLastIP); err != nil { - return nil, errors.Errorf("failed to add proxy ARP address range %s - %s: %v", firstIP, lastIP, err) + for _, r := range value.Ranges { + firstIP := net.ParseIP(r.FirstIpAddr).To4() + lastIP := net.ParseIP(r.LastIpAddr).To4() + + if err := d.proxyArpHandler.AddProxyArpRange(firstIP, lastIP, r.VrfId); err != nil { + return nil, errors.Errorf("failed to add proxy ARP address range %s - %s (VRF: %d): %v", firstIP, lastIP, r.VrfId, err) } } return nil, nil @@ -108,30 +173,22 @@ func (d *ProxyArpDescriptor) Create(key string, value *l3.ProxyARP) (metadata in // Update modifies VPP Proxy ARP. func (d *ProxyArpDescriptor) Update(key string, oldValue, newValue *l3.ProxyARP, oldMetadata interface{}) (newMetadata interface{}, err error) { toAdd, toDelete := calculateRngDiff(newValue.Ranges, oldValue.Ranges) - // Remove old ranges - for _, proxyArpRange := range toDelete { - // Prune addresses - firstIP := pruneIP(proxyArpRange.FirstIpAddr) - lastIP := pruneIP(proxyArpRange.LastIpAddr) - // Convert to byte representation - bFirstIP := net.ParseIP(firstIP).To4() - bLastIP := net.ParseIP(lastIP).To4() - // Call VPP API to configure IP range for proxy ARP - if err := d.proxyArpHandler.DeleteProxyArpRange(bFirstIP, bLastIP); err != nil { - return nil, errors.Errorf("failed to delete proxy ARP address range %s - %s: %v", firstIP, lastIP, err) - } - } - // Add new ranges - for _, proxyArpRange := range toAdd { - // Prune addresses - firstIP := pruneIP(proxyArpRange.FirstIpAddr) - lastIP := pruneIP(proxyArpRange.LastIpAddr) - // Convert to byte representation - bFirstIP := net.ParseIP(firstIP).To4() - bLastIP := net.ParseIP(lastIP).To4() - // Call VPP API to configure IP range for proxy ARP - if err := d.proxyArpHandler.AddProxyArpRange(bFirstIP, bLastIP); err != nil { - return nil, errors.Errorf("failed to add proxy ARP address range %s - %s: %v", firstIP, lastIP, err) + + for _, r := range toDelete { + firstIP := net.ParseIP(r.FirstIpAddr).To4() + lastIP := net.ParseIP(r.LastIpAddr).To4() + + if err := d.proxyArpHandler.DeleteProxyArpRange(firstIP, lastIP, r.VrfId); err != nil { + return nil, errors.Errorf("failed to delete proxy ARP address range %s - %s (VRF: %d): %v", firstIP, lastIP, r.VrfId, err) + } + } + + for _, r := range toAdd { + firstIP := net.ParseIP(r.FirstIpAddr).To4() + lastIP := net.ParseIP(r.LastIpAddr).To4() + + if err := d.proxyArpHandler.AddProxyArpRange(firstIP, lastIP, r.VrfId); err != nil { + return nil, errors.Errorf("failed to add proxy ARP address range %s - %s (VRF: %d): %v", firstIP, lastIP, r.VrfId, err) } } @@ -140,16 +197,12 @@ func (d *ProxyArpDescriptor) Update(key string, oldValue, newValue *l3.ProxyARP, // Delete deletes VPP Proxy ARP. func (d *ProxyArpDescriptor) Delete(key string, value *l3.ProxyARP, metadata interface{}) error { - for _, proxyArpRange := range value.Ranges { - // Prune addresses - firstIP := pruneIP(proxyArpRange.FirstIpAddr) - lastIP := pruneIP(proxyArpRange.LastIpAddr) - // Convert to byte representation - bFirstIP := net.ParseIP(firstIP).To4() - bLastIP := net.ParseIP(lastIP).To4() - // Call VPP API to configure IP range for proxy ARP - if err := d.proxyArpHandler.DeleteProxyArpRange(bFirstIP, bLastIP); err != nil { - return errors.Errorf("failed to delete proxy ARP address range %s - %s: %v", firstIP, lastIP, err) + for _, r := range value.Ranges { + firstIP := net.ParseIP(r.FirstIpAddr).To4() + lastIP := net.ParseIP(r.LastIpAddr).To4() + + if err := d.proxyArpHandler.DeleteProxyArpRange(firstIP, lastIP, r.VrfId); err != nil { + return errors.Errorf("failed to delete proxy ARP address range %s - %s (VRF: %d): %v", firstIP, lastIP, r.VrfId, err) } } return nil @@ -186,23 +239,14 @@ func (d *ProxyArpDescriptor) Retrieve(correlate []adapter.ProxyARPKVWithMetadata return retrieved, nil } -// Remove IP mask if set -func pruneIP(ip string) string { - ipParts := strings.Split(ip, "/") - switch len(ipParts) { - case 1, 2: - return ipParts[0] - } - return ip -} - -// Calculate difference between old and new ranges +// calculateRngDiff calculates difference between old and new ranges. func calculateRngDiff(newRngs, oldRngs []*l3.ProxyARP_Range) (toAdd, toDelete []*l3.ProxyARP_Range) { - // Find missing ranges + // Find missing ranges. for _, newRng := range newRngs { var found bool for _, oldRng := range oldRngs { - if newRng.FirstIpAddr == oldRng.FirstIpAddr && + if newRng.VrfId == oldRng.VrfId && + newRng.FirstIpAddr == oldRng.FirstIpAddr && newRng.LastIpAddr == oldRng.LastIpAddr { found = true break @@ -212,11 +256,12 @@ func calculateRngDiff(newRngs, oldRngs []*l3.ProxyARP_Range) (toAdd, toDelete [] toAdd = append(toAdd, newRng) } } - // Find obsolete interfaces + // Find obsolete ranges. for _, oldRng := range oldRngs { var found bool for _, newRng := range newRngs { - if oldRng.FirstIpAddr == newRng.FirstIpAddr && + if oldRng.VrfId == newRng.VrfId && + oldRng.FirstIpAddr == newRng.FirstIpAddr && oldRng.LastIpAddr == newRng.LastIpAddr { found = true break diff --git a/plugins/vpp/l3plugin/vppcalls/l3_vppcalls.go b/plugins/vpp/l3plugin/vppcalls/l3_vppcalls.go index 10b351c536..a02a587bff 100644 --- a/plugins/vpp/l3plugin/vppcalls/l3_vppcalls.go +++ b/plugins/vpp/l3plugin/vppcalls/l3_vppcalls.go @@ -122,9 +122,9 @@ type ProxyArpVppAPI interface { // DisableProxyArpInterface disables interface for proxy ARP DisableProxyArpInterface(ifName string) error // AddProxyArpRange adds new IP range for proxy ARP - AddProxyArpRange(firstIP, lastIP []byte) error + AddProxyArpRange(firstIP, lastIP []byte, vrfID uint32) error // DeleteProxyArpRange removes proxy ARP IP range - DeleteProxyArpRange(firstIP, lastIP []byte) error + DeleteProxyArpRange(firstIP, lastIP []byte, vrfID uint32) error } // ProxyArpVppRead provides read methods for proxy ARPs diff --git a/plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_dump.go b/plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_dump.go index 2654f03d1e..fa02a26c2e 100644 --- a/plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_dump.go +++ b/plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_dump.go @@ -41,6 +41,7 @@ func (h *ProxyArpVppHandler) DumpProxyArpRanges() (pArpRngs []*vppcalls.ProxyArp Range: &l3.ProxyARP_Range{ FirstIpAddr: net.IP(proxyArpDetails.Proxy.Low[:]).To4().String(), LastIpAddr: net.IP(proxyArpDetails.Proxy.Hi[:]).To4().String(), + VrfId: proxyArpDetails.Proxy.TableID, }, }) } diff --git a/plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_vppcalls.go b/plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_vppcalls.go index 15497b55ec..2770f251c8 100644 --- a/plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_vppcalls.go +++ b/plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_vppcalls.go @@ -15,6 +15,9 @@ package vpp1904 import ( + "fmt" + "net" + "github.com/pkg/errors" "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp1904/ip" ) @@ -30,13 +33,13 @@ func (h *ProxyArpVppHandler) DisableProxyArpInterface(ifName string) error { } // AddProxyArpRange implements proxy arp handler. -func (h *ProxyArpVppHandler) AddProxyArpRange(firstIP, lastIP []byte) error { - return h.vppAddDelProxyArpRange(firstIP, lastIP, true) +func (h *ProxyArpVppHandler) AddProxyArpRange(firstIP, lastIP []byte, vrfID uint32) error { + return h.vppAddDelProxyArpRange(firstIP, lastIP, vrfID, true) } // DeleteProxyArpRange implements proxy arp handler. -func (h *ProxyArpVppHandler) DeleteProxyArpRange(firstIP, lastIP []byte) error { - return h.vppAddDelProxyArpRange(firstIP, lastIP, false) +func (h *ProxyArpVppHandler) DeleteProxyArpRange(firstIP, lastIP []byte, vrfID uint32) error { + return h.vppAddDelProxyArpRange(firstIP, lastIP, vrfID, false) } // vppAddDelProxyArpInterface adds or removes proxy ARP interface entry according to provided input @@ -61,10 +64,24 @@ func (h *ProxyArpVppHandler) vppAddDelProxyArpInterface(ifName string, enable bo return nil } -// vppAddDelProxyArpRange adds or removes proxy ARP range according to provided input -func (h *ProxyArpVppHandler) vppAddDelProxyArpRange(firstIP, lastIP []byte, isAdd bool) error { +// vppAddDelProxyArpRange adds or removes proxy ARP range according to provided input. +func (h *ProxyArpVppHandler) vppAddDelProxyArpRange(firstIP, lastIP []byte, vrf uint32, isAdd bool) error { + validateIPBytes := func(b []byte) error { + ip := net.IP(b) + if ip.To4() == nil { + return fmt.Errorf("IP bytes %v are not valid IPv4 address", b) + } + return nil + } + if err := validateIPBytes(firstIP); err != nil { + return fmt.Errorf("bad first IP: %v", err) + } + if err := validateIPBytes(lastIP); err != nil { + return fmt.Errorf("bad last IP: %v", err) + } + proxy := ip.ProxyArp{ - TableID: 0, // TODO: add support for VRF + TableID: vrf, } copy(proxy.Low[:], firstIP) copy(proxy.Hi[:], lastIP) @@ -79,7 +96,7 @@ func (h *ProxyArpVppHandler) vppAddDelProxyArpRange(firstIP, lastIP []byte, isAd return err } - h.log.Debugf("proxy arp range: %v - %v added: %v", req.Proxy.Low, req.Proxy.Hi, isAdd) + h.log.Debugf("proxy arp range: %v - %v (vrf: %d) added: %v", proxy.Low, proxy.Hi, proxy.TableID, isAdd) return nil } diff --git a/plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_vppcalls_test.go b/plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_vppcalls_test.go index 34e17fb330..aaed0da332 100644 --- a/plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_vppcalls_test.go +++ b/plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_vppcalls_test.go @@ -29,7 +29,7 @@ import ( // Test enable/disable proxy arp func TestProxyArp(t *testing.T) { - ctx, ifIndexes, _, pArpHandler := pArpTestSetup(t) + ctx, ifIndexes, pArpHandler := pArpTestSetup(t) defer ctx.TeardownTestCtx() ifIndexes.Put("if1", &ifaceidx.IfaceMetadata{SwIfIndex: 1}) @@ -47,29 +47,83 @@ func TestProxyArp(t *testing.T) { Expect(err).NotTo(BeNil()) } -// Test add/delete ip range for proxy arp func TestProxyArpRange(t *testing.T) { - ctx, _, _, pArpHandler := pArpTestSetup(t) + ctx, _, pArpHandler := pArpTestSetup(t) defer ctx.TeardownTestCtx() - ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{}) - err := pArpHandler.AddProxyArpRange([]byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}) - Expect(err).To(Succeed()) + t.Run("Add: success case", func(t *testing.T) { + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) - ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{}) - err = pArpHandler.DeleteProxyArpRange([]byte{192, 168, 10, 23}, []byte{192, 168, 10, 27}) - Expect(err).To(Succeed()) + Expect(pArpHandler.AddProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).To(Succeed()) + }) + + testAddProxyARPRangeError := func(firstIP, lastIP []byte, vrf uint32) { + t.Helper() + + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) + Expect(pArpHandler.AddProxyArpRange(firstIP, lastIP, vrf)).ToNot(Succeed()) + + //Get mocked reply, since VPP call should not happen before. + Expect( + ctx.MockVPPClient.SendRequest(&ip.ProxyArpAddDel{}).ReceiveReply(&ip.ProxyArpAddDelReply{}), + ).To(Succeed()) + } + t.Run("Add: error cases", func(t *testing.T) { + // Bad first IP address. + testAddProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 10, 30}, 0) + // Bad last IP address. + testAddProxyARPRangeError([]byte{192, 168, 10, 20}, []byte{192, 168, 30}, 0) + // Bad both IP addresses. + testAddProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 30}, 0) + }) + + t.Run("Delete: success case", func(t *testing.T) { + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) + + Expect(pArpHandler.DeleteProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).To(Succeed()) + }) + + testDelProxyARPRangeError := func(firstIP, lastIP []byte, vrf uint32) { + t.Helper() + + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) + Expect(pArpHandler.DeleteProxyArpRange(firstIP, lastIP, vrf)).ToNot(Succeed()) + + //Get mocked reply, since VPP call should not happen before. + Expect( + ctx.MockVPPClient.SendRequest(&ip.ProxyArpAddDel{}).ReceiveReply(&ip.ProxyArpAddDelReply{}), + ).To(Succeed()) + } + t.Run("Delete: error cases", func(t *testing.T) { + // Bad first IP address. + testDelProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 10, 30}, 0) + // Bad last IP address. + testDelProxyARPRangeError([]byte{192, 168, 10, 20}, []byte{192, 168, 30}, 0) + // Bad both IP addresses. + testDelProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 30}, 0) + }) + + // Test retval in "add" scenario. + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 1}) + Expect(pArpHandler.AddProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).ToNot(Succeed()) + // Test retval in "delete" scenario. ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 1}) - err = pArpHandler.AddProxyArpRange([]byte{192, 168, 10, 23}, []byte{192, 168, 10, 27}) - Expect(err).To(Not(BeNil())) + Expect(pArpHandler.DeleteProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).ToNot(Succeed()) } -func pArpTestSetup(t *testing.T) (*vppmock.TestCtx, ifaceidx.IfaceMetadataIndexRW, vppcalls.ArpVppAPI, vppcalls.ProxyArpVppAPI) { +func pArpTestSetup(t *testing.T) (*vppmock.TestCtx, ifaceidx.IfaceMetadataIndexRW, vppcalls.ProxyArpVppAPI) { ctx := vppmock.SetupTestCtx(t) log := logrus.NewLogger("test-log") ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test"), "test") - arpHandler := vpp1904.NewArpVppHandler(ctx.MockChannel, ifIndexes, log) pArpHandler := vpp1904.NewProxyArpVppHandler(ctx.MockChannel, ifIndexes, log) - return ctx, ifIndexes, arpHandler, pArpHandler + return ctx, ifIndexes, pArpHandler } diff --git a/plugins/vpp/l3plugin/vppcalls/vpp1908/proxyarp_dump.go b/plugins/vpp/l3plugin/vppcalls/vpp1908/proxyarp_dump.go index 7fb2202eb3..453d90ebe2 100644 --- a/plugins/vpp/l3plugin/vppcalls/vpp1908/proxyarp_dump.go +++ b/plugins/vpp/l3plugin/vppcalls/vpp1908/proxyarp_dump.go @@ -41,6 +41,7 @@ func (h *ProxyArpVppHandler) DumpProxyArpRanges() (pArpRngs []*vppcalls.ProxyArp Range: &l3.ProxyARP_Range{ FirstIpAddr: net.IP(proxyArpDetails.Proxy.Low[:]).To4().String(), LastIpAddr: net.IP(proxyArpDetails.Proxy.Hi[:]).To4().String(), + VrfId: proxyArpDetails.Proxy.TableID, }, }) } diff --git a/plugins/vpp/l3plugin/vppcalls/vpp1908/proxyarp_vppcalls.go b/plugins/vpp/l3plugin/vppcalls/vpp1908/proxyarp_vppcalls.go index 6506a83abd..30fdbcb9e4 100644 --- a/plugins/vpp/l3plugin/vppcalls/vpp1908/proxyarp_vppcalls.go +++ b/plugins/vpp/l3plugin/vppcalls/vpp1908/proxyarp_vppcalls.go @@ -15,6 +15,9 @@ package vpp1908 import ( + "fmt" + "net" + "github.com/pkg/errors" "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp1908/ip" ) @@ -30,13 +33,13 @@ func (h *ProxyArpVppHandler) DisableProxyArpInterface(ifName string) error { } // AddProxyArpRange implements proxy arp handler. -func (h *ProxyArpVppHandler) AddProxyArpRange(firstIP, lastIP []byte) error { - return h.vppAddDelProxyArpRange(firstIP, lastIP, true) +func (h *ProxyArpVppHandler) AddProxyArpRange(firstIP, lastIP []byte, vrfID uint32) error { + return h.vppAddDelProxyArpRange(firstIP, lastIP, vrfID, true) } // DeleteProxyArpRange implements proxy arp handler. -func (h *ProxyArpVppHandler) DeleteProxyArpRange(firstIP, lastIP []byte) error { - return h.vppAddDelProxyArpRange(firstIP, lastIP, false) +func (h *ProxyArpVppHandler) DeleteProxyArpRange(firstIP, lastIP []byte, vrfID uint32) error { + return h.vppAddDelProxyArpRange(firstIP, lastIP, vrfID, false) } // vppAddDelProxyArpInterface adds or removes proxy ARP interface entry according to provided input @@ -61,10 +64,24 @@ func (h *ProxyArpVppHandler) vppAddDelProxyArpInterface(ifName string, enable bo return nil } -// vppAddDelProxyArpRange adds or removes proxy ARP range according to provided input -func (h *ProxyArpVppHandler) vppAddDelProxyArpRange(firstIP, lastIP []byte, isAdd bool) error { +// vppAddDelProxyArpRange adds or removes proxy ARP range according to provided input. +func (h *ProxyArpVppHandler) vppAddDelProxyArpRange(firstIP, lastIP []byte, vrfID uint32, isAdd bool) error { + validateIPBytes := func(b []byte) error { + ip := net.IP(b) + if ip.To4() == nil { + return fmt.Errorf("IP bytes %v are not valid IPv4 address", b) + } + return nil + } + if err := validateIPBytes(firstIP); err != nil { + return fmt.Errorf("bad first IP: %v", err) + } + if err := validateIPBytes(lastIP); err != nil { + return fmt.Errorf("bad last IP: %v", err) + } + proxy := ip.ProxyArp{ - TableID: 0, // TODO: add support for VRF + TableID: vrfID, } copy(proxy.Low[:], firstIP) copy(proxy.Hi[:], lastIP) @@ -79,7 +96,7 @@ func (h *ProxyArpVppHandler) vppAddDelProxyArpRange(firstIP, lastIP []byte, isAd return err } - h.log.Debugf("proxy arp range: %v - %v added: %v", req.Proxy.Low, req.Proxy.Hi, isAdd) + h.log.Debugf("proxy arp range: %v - %v (vrf: %d) added: %v", proxy.Low, proxy.Hi, proxy.TableID, isAdd) return nil } diff --git a/plugins/vpp/l3plugin/vppcalls/vpp1908/proxyarp_vppcalls_test.go b/plugins/vpp/l3plugin/vppcalls/vpp1908/proxyarp_vppcalls_test.go index 6ae40f0d62..a71cb6bd76 100644 --- a/plugins/vpp/l3plugin/vppcalls/vpp1908/proxyarp_vppcalls_test.go +++ b/plugins/vpp/l3plugin/vppcalls/vpp1908/proxyarp_vppcalls_test.go @@ -29,7 +29,7 @@ import ( // Test enable/disable proxy arp func TestProxyArp(t *testing.T) { - ctx, ifIndexes, _, pArpHandler := pArpTestSetup(t) + ctx, ifIndexes, pArpHandler := pArpTestSetup(t) defer ctx.TeardownTestCtx() ifIndexes.Put("if1", &ifaceidx.IfaceMetadata{SwIfIndex: 1}) @@ -47,29 +47,83 @@ func TestProxyArp(t *testing.T) { Expect(err).NotTo(BeNil()) } -// Test add/delete ip range for proxy arp func TestProxyArpRange(t *testing.T) { - ctx, _, _, pArpHandler := pArpTestSetup(t) + ctx, _, pArpHandler := pArpTestSetup(t) defer ctx.TeardownTestCtx() - ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{}) - err := pArpHandler.AddProxyArpRange([]byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}) - Expect(err).To(Succeed()) + t.Run("Add: success case", func(t *testing.T) { + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) - ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{}) - err = pArpHandler.DeleteProxyArpRange([]byte{192, 168, 10, 23}, []byte{192, 168, 10, 27}) - Expect(err).To(Succeed()) + Expect(pArpHandler.AddProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).To(Succeed()) + }) + + testAddProxyARPRangeError := func(firstIP, lastIP []byte, vrf uint32) { + t.Helper() + + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) + Expect(pArpHandler.AddProxyArpRange(firstIP, lastIP, vrf)).ToNot(Succeed()) + + //Get mocked reply, since VPP call should not happen before. + Expect( + ctx.MockVPPClient.SendRequest(&ip.ProxyArpAddDel{}).ReceiveReply(&ip.ProxyArpAddDelReply{}), + ).To(Succeed()) + } + t.Run("Add: error cases", func(t *testing.T) { + // Bad first IP address. + testAddProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 10, 30}, 0) + // Bad last IP address. + testAddProxyARPRangeError([]byte{192, 168, 10, 20}, []byte{192, 168, 30}, 0) + // Bad both IP addresses. + testAddProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 30}, 0) + }) + + t.Run("Delete: success case", func(t *testing.T) { + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) + + Expect(pArpHandler.DeleteProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).To(Succeed()) + }) + + testDelProxyARPRangeError := func(firstIP, lastIP []byte, vrf uint32) { + t.Helper() + + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) + Expect(pArpHandler.DeleteProxyArpRange(firstIP, lastIP, vrf)).ToNot(Succeed()) + + //Get mocked reply, since VPP call should not happen before. + Expect( + ctx.MockVPPClient.SendRequest(&ip.ProxyArpAddDel{}).ReceiveReply(&ip.ProxyArpAddDelReply{}), + ).To(Succeed()) + } + t.Run("Delete: error cases", func(t *testing.T) { + // Bad first IP address. + testDelProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 10, 30}, 0) + // Bad last IP address. + testDelProxyARPRangeError([]byte{192, 168, 10, 20}, []byte{192, 168, 30}, 0) + // Bad both IP addresses. + testDelProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 30}, 0) + }) + + // Test retval in "add" scenario. + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 1}) + Expect(pArpHandler.AddProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).ToNot(Succeed()) + // Test retval in "delete" scenario. ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 1}) - err = pArpHandler.AddProxyArpRange([]byte{192, 168, 10, 23}, []byte{192, 168, 10, 27}) - Expect(err).To(Not(BeNil())) + Expect(pArpHandler.DeleteProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).ToNot(Succeed()) } -func pArpTestSetup(t *testing.T) (*vppmock.TestCtx, ifaceidx.IfaceMetadataIndexRW, vppcalls.ArpVppAPI, vppcalls.ProxyArpVppAPI) { +func pArpTestSetup(t *testing.T) (*vppmock.TestCtx, ifaceidx.IfaceMetadataIndexRW, vppcalls.ProxyArpVppAPI) { ctx := vppmock.SetupTestCtx(t) log := logrus.NewLogger("test-log") ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test"), "test") - arpHandler := vpp1908.NewArpVppHandler(ctx.MockChannel, ifIndexes, log) pArpHandler := vpp1908.NewProxyArpVppHandler(ctx.MockChannel, ifIndexes, log) - return ctx, ifIndexes, arpHandler, pArpHandler + return ctx, ifIndexes, pArpHandler } diff --git a/plugins/vpp/l3plugin/vppcalls/vpp2001/proxyarp_dump.go b/plugins/vpp/l3plugin/vppcalls/vpp2001/proxyarp_dump.go index daaeebfa4b..69325f4181 100644 --- a/plugins/vpp/l3plugin/vppcalls/vpp2001/proxyarp_dump.go +++ b/plugins/vpp/l3plugin/vppcalls/vpp2001/proxyarp_dump.go @@ -41,6 +41,7 @@ func (h *ProxyArpVppHandler) DumpProxyArpRanges() (pArpRngs []*vppcalls.ProxyArp Range: &l3.ProxyARP_Range{ FirstIpAddr: net.IP(proxyArpDetails.Proxy.Low[:]).To4().String(), LastIpAddr: net.IP(proxyArpDetails.Proxy.Hi[:]).To4().String(), + VrfId: proxyArpDetails.Proxy.TableID, }, }) } diff --git a/plugins/vpp/l3plugin/vppcalls/vpp2001/proxyarp_vppcalls.go b/plugins/vpp/l3plugin/vppcalls/vpp2001/proxyarp_vppcalls.go index 9e47c454da..e59b15efd9 100644 --- a/plugins/vpp/l3plugin/vppcalls/vpp2001/proxyarp_vppcalls.go +++ b/plugins/vpp/l3plugin/vppcalls/vpp2001/proxyarp_vppcalls.go @@ -15,6 +15,9 @@ package vpp2001 import ( + "fmt" + "net" + "github.com/pkg/errors" vpp_arp "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2001/arp" @@ -32,13 +35,13 @@ func (h *ProxyArpVppHandler) DisableProxyArpInterface(ifName string) error { } // AddProxyArpRange implements proxy arp handler. -func (h *ProxyArpVppHandler) AddProxyArpRange(firstIP, lastIP []byte) error { - return h.vppAddDelProxyArpRange(firstIP, lastIP, true) +func (h *ProxyArpVppHandler) AddProxyArpRange(firstIP, lastIP []byte, vrfID uint32) error { + return h.vppAddDelProxyArpRange(firstIP, lastIP, vrfID, true) } // DeleteProxyArpRange implements proxy arp handler. -func (h *ProxyArpVppHandler) DeleteProxyArpRange(firstIP, lastIP []byte) error { - return h.vppAddDelProxyArpRange(firstIP, lastIP, false) +func (h *ProxyArpVppHandler) DeleteProxyArpRange(firstIP, lastIP []byte, vrfID uint32) error { + return h.vppAddDelProxyArpRange(firstIP, lastIP, vrfID, false) } // vppAddDelProxyArpInterface adds or removes proxy ARP interface entry according to provided input @@ -63,10 +66,24 @@ func (h *ProxyArpVppHandler) vppAddDelProxyArpInterface(ifName string, enable bo return nil } -// vppAddDelProxyArpRange adds or removes proxy ARP range according to provided input -func (h *ProxyArpVppHandler) vppAddDelProxyArpRange(firstIP, lastIP []byte, isAdd bool) error { +// vppAddDelProxyArpRange adds or removes proxy ARP range according to provided input. +func (h *ProxyArpVppHandler) vppAddDelProxyArpRange(firstIP, lastIP []byte, vrf uint32, isAdd bool) error { + validateIPBytes := func(b []byte) error { + ip := net.IP(b) + if ip.To4() == nil { + return fmt.Errorf("IP bytes %v are not valid IPv4 address", b) + } + return nil + } + if err := validateIPBytes(firstIP); err != nil { + return fmt.Errorf("bad first IP: %v", err) + } + if err := validateIPBytes(lastIP); err != nil { + return fmt.Errorf("bad last IP: %v", err) + } + proxy := vpp_arp.ProxyArp{ - TableID: 0, // TODO: add support for VRF + TableID: vrf, } copy(proxy.Low[:], firstIP) copy(proxy.Hi[:], lastIP) @@ -81,7 +98,7 @@ func (h *ProxyArpVppHandler) vppAddDelProxyArpRange(firstIP, lastIP []byte, isAd return err } - h.log.Debugf("proxy arp range: %v - %v added: %v", req.Proxy.Low, req.Proxy.Hi, isAdd) + h.log.Debugf("proxy arp range: %v - %v (vrf: %d) added: %v", proxy.Low, proxy.Hi, proxy.TableID, isAdd) return nil } diff --git a/plugins/vpp/l3plugin/vppcalls/vpp2001/proxyarp_vppcalls_test.go b/plugins/vpp/l3plugin/vppcalls/vpp2001/proxyarp_vppcalls_test.go index dcb85176b0..13b1903db2 100644 --- a/plugins/vpp/l3plugin/vppcalls/vpp2001/proxyarp_vppcalls_test.go +++ b/plugins/vpp/l3plugin/vppcalls/vpp2001/proxyarp_vppcalls_test.go @@ -20,6 +20,7 @@ import ( . "github.com/onsi/gomega" "go.ligato.io/cn-infra/v2/logging/logrus" + "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp1904/ip" vpp_arp "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2001/arp" "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/ifaceidx" "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/vppcalls" @@ -29,7 +30,7 @@ import ( // Test enable/disable proxy arp func TestProxyArp(t *testing.T) { - ctx, ifIndexes, _, pArpHandler := pArpTestSetup(t) + ctx, ifIndexes, pArpHandler := pArpTestSetup(t) defer ctx.TeardownTestCtx() ifIndexes.Put("if1", &ifaceidx.IfaceMetadata{SwIfIndex: 1}) @@ -47,29 +48,83 @@ func TestProxyArp(t *testing.T) { Expect(err).NotTo(BeNil()) } -// Test add/delete ip range for proxy arp func TestProxyArpRange(t *testing.T) { - ctx, _, _, pArpHandler := pArpTestSetup(t) + ctx, _, pArpHandler := pArpTestSetup(t) defer ctx.TeardownTestCtx() - ctx.MockVpp.MockReply(&vpp_arp.ProxyArpAddDelReply{}) - err := pArpHandler.AddProxyArpRange([]byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}) - Expect(err).To(Succeed()) + t.Run("Add: success case", func(t *testing.T) { + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) - ctx.MockVpp.MockReply(&vpp_arp.ProxyArpAddDelReply{}) - err = pArpHandler.DeleteProxyArpRange([]byte{192, 168, 10, 23}, []byte{192, 168, 10, 27}) - Expect(err).To(Succeed()) + Expect(pArpHandler.AddProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).To(Succeed()) + }) + + testAddProxyARPRangeError := func(firstIP, lastIP []byte, vrf uint32) { + t.Helper() + + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) + Expect(pArpHandler.AddProxyArpRange(firstIP, lastIP, vrf)).ToNot(Succeed()) + + //Get mocked reply, since VPP call should not happen before. + Expect( + ctx.MockVPPClient.SendRequest(&ip.ProxyArpAddDel{}).ReceiveReply(&ip.ProxyArpAddDelReply{}), + ).To(Succeed()) + } + t.Run("Add: error cases", func(t *testing.T) { + // Bad first IP address. + testAddProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 10, 30}, 0) + // Bad last IP address. + testAddProxyARPRangeError([]byte{192, 168, 10, 20}, []byte{192, 168, 30}, 0) + // Bad both IP addresses. + testAddProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 30}, 0) + }) + + t.Run("Delete: success case", func(t *testing.T) { + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) + + Expect(pArpHandler.DeleteProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).To(Succeed()) + }) + + testDelProxyARPRangeError := func(firstIP, lastIP []byte, vrf uint32) { + t.Helper() + + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) + Expect(pArpHandler.DeleteProxyArpRange(firstIP, lastIP, vrf)).ToNot(Succeed()) + + //Get mocked reply, since VPP call should not happen before. + Expect( + ctx.MockVPPClient.SendRequest(&ip.ProxyArpAddDel{}).ReceiveReply(&ip.ProxyArpAddDelReply{}), + ).To(Succeed()) + } + t.Run("Delete: error cases", func(t *testing.T) { + // Bad first IP address. + testDelProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 10, 30}, 0) + // Bad last IP address. + testDelProxyARPRangeError([]byte{192, 168, 10, 20}, []byte{192, 168, 30}, 0) + // Bad both IP addresses. + testDelProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 30}, 0) + }) + + // Test retval in "add" scenario. + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 1}) + Expect(pArpHandler.AddProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).ToNot(Succeed()) - ctx.MockVpp.MockReply(&vpp_arp.ProxyArpAddDelReply{Retval: 1}) - err = pArpHandler.AddProxyArpRange([]byte{192, 168, 10, 23}, []byte{192, 168, 10, 27}) - Expect(err).To(Not(BeNil())) + // Test retval in "delete" scenario. + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 1}) + Expect(pArpHandler.DeleteProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).ToNot(Succeed()) } -func pArpTestSetup(t *testing.T) (*vppmock.TestCtx, ifaceidx.IfaceMetadataIndexRW, vppcalls.ArpVppAPI, vppcalls.ProxyArpVppAPI) { +func pArpTestSetup(t *testing.T) (*vppmock.TestCtx, ifaceidx.IfaceMetadataIndexRW, vppcalls.ProxyArpVppAPI) { ctx := vppmock.SetupTestCtx(t) log := logrus.NewLogger("test-log") ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test"), "test") - arpHandler := vpp2001.NewArpVppHandler(ctx.MockChannel, ifIndexes, log) pArpHandler := vpp2001.NewProxyArpVppHandler(ctx.MockChannel, ifIndexes, log) - return ctx, ifIndexes, arpHandler, pArpHandler + return ctx, ifIndexes, pArpHandler } diff --git a/plugins/vpp/l3plugin/vppcalls/vpp2005/proxyarp_dump.go b/plugins/vpp/l3plugin/vppcalls/vpp2005/proxyarp_dump.go index 45b447ef19..8d8ef67984 100644 --- a/plugins/vpp/l3plugin/vppcalls/vpp2005/proxyarp_dump.go +++ b/plugins/vpp/l3plugin/vppcalls/vpp2005/proxyarp_dump.go @@ -41,6 +41,7 @@ func (h *ProxyArpVppHandler) DumpProxyArpRanges() (pArpRngs []*vppcalls.ProxyArp Range: &l3.ProxyARP_Range{ FirstIpAddr: net.IP(proxyArpDetails.Proxy.Low[:]).To4().String(), LastIpAddr: net.IP(proxyArpDetails.Proxy.Hi[:]).To4().String(), + VrfId: proxyArpDetails.Proxy.TableID, }, }) } diff --git a/plugins/vpp/l3plugin/vppcalls/vpp2005/proxyarp_vppcalls.go b/plugins/vpp/l3plugin/vppcalls/vpp2005/proxyarp_vppcalls.go index bf5fc5ecb3..f56cb4a7b8 100644 --- a/plugins/vpp/l3plugin/vppcalls/vpp2005/proxyarp_vppcalls.go +++ b/plugins/vpp/l3plugin/vppcalls/vpp2005/proxyarp_vppcalls.go @@ -15,6 +15,9 @@ package vpp2005 import ( + "fmt" + "net" + "github.com/pkg/errors" vpp_arp "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2005/arp" @@ -32,13 +35,13 @@ func (h *ProxyArpVppHandler) DisableProxyArpInterface(ifName string) error { } // AddProxyArpRange implements proxy arp handler. -func (h *ProxyArpVppHandler) AddProxyArpRange(firstIP, lastIP []byte) error { - return h.vppAddDelProxyArpRange(firstIP, lastIP, true) +func (h *ProxyArpVppHandler) AddProxyArpRange(firstIP, lastIP []byte, vrfID uint32) error { + return h.vppAddDelProxyArpRange(firstIP, lastIP, vrfID, true) } // DeleteProxyArpRange implements proxy arp handler. -func (h *ProxyArpVppHandler) DeleteProxyArpRange(firstIP, lastIP []byte) error { - return h.vppAddDelProxyArpRange(firstIP, lastIP, false) +func (h *ProxyArpVppHandler) DeleteProxyArpRange(firstIP, lastIP []byte, vrfID uint32) error { + return h.vppAddDelProxyArpRange(firstIP, lastIP, vrfID, false) } // vppAddDelProxyArpInterface adds or removes proxy ARP interface entry according to provided input @@ -63,10 +66,24 @@ func (h *ProxyArpVppHandler) vppAddDelProxyArpInterface(ifName string, enable bo return nil } -// vppAddDelProxyArpRange adds or removes proxy ARP range according to provided input -func (h *ProxyArpVppHandler) vppAddDelProxyArpRange(firstIP, lastIP []byte, isAdd bool) error { +// vppAddDelProxyArpRange adds or removes proxy ARP range according to provided input. +func (h *ProxyArpVppHandler) vppAddDelProxyArpRange(firstIP, lastIP []byte, vrfID uint32, isAdd bool) error { + validateIPBytes := func(b []byte) error { + ip := net.IP(b) + if ip.To4() == nil { + return fmt.Errorf("IP bytes %v are not valid IPv4 address", b) + } + return nil + } + if err := validateIPBytes(firstIP); err != nil { + return fmt.Errorf("bad first IP: %v", err) + } + if err := validateIPBytes(lastIP); err != nil { + return fmt.Errorf("bad last IP: %v", err) + } + proxy := vpp_arp.ProxyArp{ - TableID: 0, // TODO: add support for VRF + TableID: vrfID, } copy(proxy.Low[:], firstIP) copy(proxy.Hi[:], lastIP) @@ -81,7 +98,7 @@ func (h *ProxyArpVppHandler) vppAddDelProxyArpRange(firstIP, lastIP []byte, isAd return err } - h.log.Debugf("proxy arp range: %v - %v added: %v", req.Proxy.Low, req.Proxy.Hi, isAdd) + h.log.Debugf("proxy arp range: %v - %v (vrf: %d) added: %v", proxy.Low, proxy.Hi, proxy.TableID, isAdd) return nil } diff --git a/plugins/vpp/l3plugin/vppcalls/vpp2005/proxyarp_vppcalls_test.go b/plugins/vpp/l3plugin/vppcalls/vpp2005/proxyarp_vppcalls_test.go index 1fdb773563..a5a61202eb 100644 --- a/plugins/vpp/l3plugin/vppcalls/vpp2005/proxyarp_vppcalls_test.go +++ b/plugins/vpp/l3plugin/vppcalls/vpp2005/proxyarp_vppcalls_test.go @@ -20,6 +20,7 @@ import ( . "github.com/onsi/gomega" "go.ligato.io/cn-infra/v2/logging/logrus" + "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp1904/ip" vpp_arp "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2005/arp" "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/ifaceidx" "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/vppcalls" @@ -29,7 +30,7 @@ import ( // Test enable/disable proxy arp func TestProxyArp(t *testing.T) { - ctx, ifIndexes, _, pArpHandler := pArpTestSetup(t) + ctx, ifIndexes, pArpHandler := pArpTestSetup(t) defer ctx.TeardownTestCtx() ifIndexes.Put("if1", &ifaceidx.IfaceMetadata{SwIfIndex: 1}) @@ -47,29 +48,83 @@ func TestProxyArp(t *testing.T) { Expect(err).NotTo(BeNil()) } -// Test add/delete ip range for proxy arp func TestProxyArpRange(t *testing.T) { - ctx, _, _, pArpHandler := pArpTestSetup(t) + ctx, _, pArpHandler := pArpTestSetup(t) defer ctx.TeardownTestCtx() - ctx.MockVpp.MockReply(&vpp_arp.ProxyArpAddDelReply{}) - err := pArpHandler.AddProxyArpRange([]byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}) - Expect(err).To(Succeed()) + t.Run("Add: success case", func(t *testing.T) { + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) - ctx.MockVpp.MockReply(&vpp_arp.ProxyArpAddDelReply{}) - err = pArpHandler.DeleteProxyArpRange([]byte{192, 168, 10, 23}, []byte{192, 168, 10, 27}) - Expect(err).To(Succeed()) + Expect(pArpHandler.AddProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).To(Succeed()) + }) + + testAddProxyARPRangeError := func(firstIP, lastIP []byte, vrf uint32) { + t.Helper() + + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) + Expect(pArpHandler.AddProxyArpRange(firstIP, lastIP, vrf)).ToNot(Succeed()) + + //Get mocked reply, since VPP call should not happen before. + Expect( + ctx.MockVPPClient.SendRequest(&ip.ProxyArpAddDel{}).ReceiveReply(&ip.ProxyArpAddDelReply{}), + ).To(Succeed()) + } + t.Run("Add: error cases", func(t *testing.T) { + // Bad first IP address. + testAddProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 10, 30}, 0) + // Bad last IP address. + testAddProxyARPRangeError([]byte{192, 168, 10, 20}, []byte{192, 168, 30}, 0) + // Bad both IP addresses. + testAddProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 30}, 0) + }) + + t.Run("Delete: success case", func(t *testing.T) { + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) + + Expect(pArpHandler.DeleteProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).To(Succeed()) + }) + + testDelProxyARPRangeError := func(firstIP, lastIP []byte, vrf uint32) { + t.Helper() + + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 0}) + Expect(pArpHandler.DeleteProxyArpRange(firstIP, lastIP, vrf)).ToNot(Succeed()) + + //Get mocked reply, since VPP call should not happen before. + Expect( + ctx.MockVPPClient.SendRequest(&ip.ProxyArpAddDel{}).ReceiveReply(&ip.ProxyArpAddDelReply{}), + ).To(Succeed()) + } + t.Run("Delete: error cases", func(t *testing.T) { + // Bad first IP address. + testDelProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 10, 30}, 0) + // Bad last IP address. + testDelProxyARPRangeError([]byte{192, 168, 10, 20}, []byte{192, 168, 30}, 0) + // Bad both IP addresses. + testDelProxyARPRangeError([]byte{192, 168, 20}, []byte{192, 168, 30}, 0) + }) + + // Test retval in "add" scenario. + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 1}) + Expect(pArpHandler.AddProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).ToNot(Succeed()) - ctx.MockVpp.MockReply(&vpp_arp.ProxyArpAddDelReply{Retval: 1}) - err = pArpHandler.AddProxyArpRange([]byte{192, 168, 10, 23}, []byte{192, 168, 10, 27}) - Expect(err).To(Not(BeNil())) + // Test retval in "delete" scenario. + ctx.MockVpp.MockReply(&ip.ProxyArpAddDelReply{Retval: 1}) + Expect(pArpHandler.DeleteProxyArpRange( + []byte{192, 168, 10, 20}, []byte{192, 168, 10, 30}, 0, + )).ToNot(Succeed()) } -func pArpTestSetup(t *testing.T) (*vppmock.TestCtx, ifaceidx.IfaceMetadataIndexRW, vppcalls.ArpVppAPI, vppcalls.ProxyArpVppAPI) { +func pArpTestSetup(t *testing.T) (*vppmock.TestCtx, ifaceidx.IfaceMetadataIndexRW, vppcalls.ProxyArpVppAPI) { ctx := vppmock.SetupTestCtx(t) log := logrus.NewLogger("test-log") ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test"), "test") - arpHandler := vpp2005.NewArpVppHandler(ctx.MockChannel, ifIndexes, log) pArpHandler := vpp2005.NewProxyArpVppHandler(ctx.MockChannel, ifIndexes, log) - return ctx, ifIndexes, arpHandler, pArpHandler + return ctx, ifIndexes, pArpHandler } diff --git a/proto/ligato/vpp/l3/l3.pb.go b/proto/ligato/vpp/l3/l3.pb.go index 6b2b9b5800..28711aac14 100644 --- a/proto/ligato/vpp/l3/l3.pb.go +++ b/proto/ligato/vpp/l3/l3.pb.go @@ -140,6 +140,7 @@ func (m *ProxyARP_Interface) GetName() string { type ProxyARP_Range struct { FirstIpAddr string `protobuf:"bytes,1,opt,name=first_ip_addr,json=firstIpAddr,proto3" json:"first_ip_addr,omitempty"` LastIpAddr string `protobuf:"bytes,2,opt,name=last_ip_addr,json=lastIpAddr,proto3" json:"last_ip_addr,omitempty"` + VrfId uint32 `protobuf:"varint,3,opt,name=vrf_id,json=vrfId,proto3" json:"vrf_id,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -184,6 +185,13 @@ func (m *ProxyARP_Range) GetLastIpAddr() string { return "" } +func (m *ProxyARP_Range) GetVrfId() uint32 { + if m != nil { + return m.VrfId + } + return 0 +} + type IPScanNeighbor struct { Mode IPScanNeighbor_Mode `protobuf:"varint,1,opt,name=mode,proto3,enum=ligato.vpp.l3.IPScanNeighbor_Mode" json:"mode,omitempty"` ScanInterval uint32 `protobuf:"varint,2,opt,name=scan_interval,json=scanInterval,proto3" json:"scan_interval,omitempty"` @@ -378,38 +386,39 @@ func init() { func init() { proto.RegisterFile("ligato/vpp/l3/l3.proto", fileDescriptor_eb46f906a6f7c0e7) } var fileDescriptor_eb46f906a6f7c0e7 = []byte{ - // 524 bytes of a gzipped FileDescriptorProto + // 533 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x93, 0xdf, 0x8a, 0x9b, 0x40, - 0x14, 0xc6, 0x6b, 0x62, 0xb2, 0xf1, 0xe4, 0xcf, 0xa6, 0x03, 0x2d, 0x12, 0x08, 0x4d, 0xdd, 0x42, - 0x97, 0x42, 0x15, 0xe2, 0x36, 0x37, 0xa5, 0x17, 0x49, 0x53, 0x58, 0xa1, 0xdb, 0x8a, 0x49, 0xf7, - 0xa2, 0x37, 0x32, 0xab, 0x93, 0x44, 0x50, 0x67, 0x98, 0x71, 0xc5, 0x7d, 0xae, 0xbe, 0x4b, 0x9f, - 0xa4, 0x0f, 0x50, 0x1c, 0x75, 0x9b, 0x2c, 0xf4, 0xee, 0xf0, 0xcd, 0xef, 0xf3, 0x3b, 0x9e, 0x99, - 0x03, 0x2f, 0xe3, 0x68, 0x8f, 0x33, 0x6a, 0xe5, 0x8c, 0x59, 0xb1, 0x6d, 0xc5, 0xb6, 0xc9, 0x38, - 0xcd, 0x28, 0x1a, 0x56, 0xba, 0x99, 0x33, 0x66, 0xc6, 0xb6, 0xf1, 0x47, 0x81, 0x9e, 0xcb, 0x69, - 0xf1, 0xb0, 0xf4, 0x5c, 0xb4, 0x04, 0x88, 0xd2, 0x8c, 0xf0, 0x1d, 0x0e, 0x88, 0xd0, 0x95, 0x59, - 0xfb, 0xb2, 0x3f, 0x7f, 0x6d, 0x9e, 0x18, 0xcc, 0x06, 0x36, 0x9d, 0x86, 0xf4, 0x8e, 0x4c, 0xe8, - 0x03, 0x74, 0x39, 0x4e, 0xf7, 0x44, 0xe8, 0x2d, 0x69, 0x9f, 0xfe, 0xcf, 0xee, 0x95, 0x94, 0x57, - 0xc3, 0x93, 0x57, 0xa0, 0x3d, 0x7e, 0x0f, 0x21, 0x50, 0x53, 0x9c, 0x10, 0x5d, 0x99, 0x29, 0x97, - 0x9a, 0x27, 0xeb, 0xc9, 0x0d, 0x74, 0xa4, 0x03, 0x19, 0x30, 0xdc, 0x45, 0x5c, 0x64, 0x7e, 0xc4, - 0x7c, 0x1c, 0x86, 0xbc, 0xa6, 0xfa, 0x52, 0x74, 0xd8, 0x32, 0x0c, 0x39, 0x9a, 0xc1, 0x20, 0xc6, - 0x47, 0x48, 0x4b, 0x22, 0x50, 0x6a, 0x15, 0x61, 0xfc, 0x6a, 0xc1, 0xc8, 0x71, 0x37, 0x01, 0x4e, - 0xbf, 0x91, 0x68, 0x7f, 0xb8, 0xa3, 0x1c, 0x2d, 0x40, 0x4d, 0x68, 0x58, 0xa5, 0x8e, 0xe6, 0xc6, - 0x93, 0xbe, 0x4f, 0x61, 0xf3, 0x86, 0x86, 0xc4, 0x93, 0x3c, 0xba, 0x80, 0xa1, 0x08, 0x70, 0xea, - 0xcb, 0x21, 0xe4, 0x38, 0x96, 0x69, 0x43, 0x6f, 0x50, 0x8a, 0x4e, 0xad, 0x95, 0x5d, 0x27, 0xb8, - 0xf0, 0x19, 0xa7, 0x81, 0x9f, 0x45, 0x09, 0xd1, 0xdb, 0x12, 0xea, 0x27, 0xb8, 0x70, 0x39, 0x0d, - 0xb6, 0x51, 0x42, 0xd0, 0x14, 0xa0, 0x64, 0xee, 0x59, 0x88, 0x33, 0xa2, 0xab, 0x12, 0xd0, 0x12, - 0x5c, 0xfc, 0x90, 0x02, 0x7a, 0x03, 0xa3, 0x26, 0xc7, 0x0f, 0x49, 0x8c, 0x1f, 0xf4, 0xce, 0x49, - 0xd0, 0xba, 0xd4, 0xd0, 0x5b, 0x38, 0x17, 0x19, 0x8e, 0x89, 0x9f, 0x1d, 0x38, 0x11, 0x07, 0x1a, - 0x87, 0x7a, 0x57, 0x62, 0x23, 0x29, 0x6f, 0x1b, 0xd5, 0x98, 0x83, 0x5a, 0xfe, 0x04, 0x1a, 0x40, - 0x6f, 0xed, 0x6c, 0x96, 0xab, 0xaf, 0x5f, 0xd6, 0xe3, 0x67, 0xa8, 0x07, 0xaa, 0xe3, 0xde, 0x5e, - 0x8d, 0x95, 0xba, 0x5a, 0x8c, 0x5b, 0x65, 0xb5, 0xfa, 0xbe, 0xbd, 0x1e, 0xb7, 0x8d, 0xdf, 0x0a, - 0x68, 0xeb, 0xeb, 0xcf, 0xae, 0xbc, 0x44, 0xf4, 0x0e, 0x9e, 0x0b, 0x7a, 0xcf, 0x03, 0xd2, 0xcc, - 0x99, 0x08, 0x51, 0xdf, 0xc6, 0x79, 0x75, 0x50, 0x0d, 0x9b, 0x08, 0x81, 0x26, 0xa0, 0xf1, 0xc2, - 0xcf, 0xf9, 0xce, 0x8f, 0xc2, 0x7a, 0x40, 0x67, 0xbc, 0xb8, 0xe5, 0x3b, 0x27, 0x44, 0x9f, 0xe0, - 0x4c, 0x10, 0x9e, 0x13, 0x2e, 0x74, 0x55, 0xbe, 0x99, 0x8b, 0x27, 0xb3, 0x7f, 0x8c, 0x94, 0xd5, - 0x46, 0xb2, 0x5e, 0xe3, 0x99, 0xac, 0x00, 0xfe, 0xc9, 0xe8, 0x05, 0x74, 0xeb, 0x14, 0x45, 0xa6, - 0x74, 0x72, 0x99, 0x31, 0x05, 0x38, 0x6a, 0xb2, 0x7a, 0x0f, 0x5a, 0xd4, 0xb4, 0xb7, 0x5a, 0xfc, - 0xbc, 0xda, 0xd3, 0x26, 0x35, 0x92, 0x4b, 0xf3, 0x1e, 0xef, 0x49, 0x9a, 0x59, 0xb9, 0x6d, 0xc9, - 0xbd, 0xb1, 0x4e, 0xd6, 0xe9, 0x63, 0xce, 0x98, 0x1f, 0xdb, 0x77, 0x5d, 0x79, 0x66, 0xff, 0x0d, - 0x00, 0x00, 0xff, 0xff, 0xad, 0x6b, 0xa6, 0xb1, 0x6d, 0x03, 0x00, 0x00, + 0x14, 0xc6, 0x6b, 0x62, 0xb2, 0xf1, 0xe4, 0xcf, 0xa6, 0x03, 0x2d, 0x12, 0x58, 0x9a, 0xba, 0x85, + 0x86, 0x42, 0x15, 0xe2, 0x36, 0x37, 0xa5, 0x17, 0x49, 0x53, 0x58, 0xa1, 0x7f, 0xc4, 0xa4, 0x7b, + 0xd1, 0x1b, 0x99, 0x75, 0x26, 0x89, 0xa0, 0x8e, 0xcc, 0xb8, 0xe2, 0x3e, 0x43, 0x1f, 0xa7, 0xef, + 0xd2, 0xe7, 0x29, 0x8e, 0xba, 0x4d, 0x16, 0xf6, 0xee, 0xf0, 0xf9, 0xfb, 0x3c, 0x67, 0xce, 0x37, + 0x03, 0x2f, 0xa3, 0x70, 0x8f, 0x33, 0x66, 0xe5, 0x69, 0x6a, 0x45, 0xb6, 0x15, 0xd9, 0x66, 0xca, + 0x59, 0xc6, 0xd0, 0xb0, 0xd2, 0xcd, 0x3c, 0x4d, 0xcd, 0xc8, 0x36, 0x7e, 0xb7, 0xa0, 0xe7, 0x72, + 0x56, 0xdc, 0x2f, 0x3d, 0x17, 0x2d, 0x01, 0xc2, 0x24, 0xa3, 0x7c, 0x87, 0x03, 0x2a, 0x74, 0x65, + 0xda, 0x9e, 0xf5, 0xe7, 0xaf, 0xcd, 0x13, 0x83, 0xd9, 0xc0, 0xa6, 0xd3, 0x90, 0xde, 0x91, 0x09, + 0x7d, 0x80, 0x2e, 0xc7, 0xc9, 0x9e, 0x0a, 0xbd, 0x25, 0xed, 0x17, 0x4f, 0xd9, 0xbd, 0x92, 0xf2, + 0x6a, 0x78, 0xf2, 0x0a, 0xb4, 0x87, 0xff, 0x21, 0x04, 0x6a, 0x82, 0x63, 0xaa, 0x2b, 0x53, 0x65, + 0xa6, 0x79, 0xb2, 0x9e, 0x10, 0xe8, 0x48, 0x07, 0x32, 0x60, 0xb8, 0x0b, 0xb9, 0xc8, 0xfc, 0x30, + 0xf5, 0x31, 0x21, 0xbc, 0xa6, 0xfa, 0x52, 0x74, 0xd2, 0x25, 0x21, 0x1c, 0x4d, 0x61, 0x10, 0xe1, + 0x23, 0xa4, 0x25, 0x11, 0x28, 0xb5, 0x9a, 0x78, 0x01, 0xdd, 0x9c, 0xef, 0xfc, 0x90, 0xe8, 0xed, + 0xa9, 0x32, 0x1b, 0x7a, 0x9d, 0x9c, 0xef, 0x1c, 0x62, 0xfc, 0x69, 0xc1, 0xc8, 0x71, 0x37, 0x01, + 0x4e, 0xbe, 0xd3, 0x70, 0x7f, 0xb8, 0x65, 0x1c, 0x2d, 0x40, 0x8d, 0x19, 0xa9, 0x86, 0x19, 0xcd, + 0x8d, 0x47, 0xc7, 0x39, 0x85, 0xcd, 0x6f, 0x8c, 0x50, 0x4f, 0xf2, 0xe8, 0x12, 0x86, 0x22, 0xc0, + 0x89, 0x2f, 0x77, 0x93, 0xe3, 0x48, 0x0e, 0x31, 0xf4, 0x06, 0xa5, 0xe8, 0xd4, 0x5a, 0x79, 0x98, + 0x18, 0x17, 0x7e, 0xca, 0x59, 0xe0, 0x67, 0x61, 0x4c, 0xeb, 0x69, 0xfa, 0x31, 0x2e, 0x5c, 0xce, + 0x82, 0x6d, 0x18, 0x53, 0x74, 0x01, 0x50, 0x32, 0x77, 0x29, 0xc1, 0x19, 0xd5, 0x55, 0x09, 0x68, + 0x31, 0x2e, 0x7e, 0x4a, 0x01, 0xbd, 0x81, 0x51, 0xd3, 0xc7, 0x27, 0x34, 0xc2, 0xf7, 0x7a, 0xe7, + 0xa4, 0xd1, 0xba, 0xd4, 0xd0, 0x5b, 0x38, 0x17, 0x19, 0x8e, 0xa8, 0x9f, 0x1d, 0x38, 0x15, 0x07, + 0x16, 0x11, 0xbd, 0x2b, 0xb1, 0x91, 0x94, 0xb7, 0x8d, 0x6a, 0xcc, 0x41, 0x2d, 0x0f, 0x81, 0x06, + 0xd0, 0x5b, 0x3b, 0x9b, 0xe5, 0xea, 0xeb, 0x97, 0xf5, 0xf8, 0x19, 0xea, 0x81, 0xea, 0xb8, 0x37, + 0x57, 0x63, 0xa5, 0xae, 0x16, 0xe3, 0x56, 0x59, 0xad, 0x7e, 0x6c, 0xaf, 0xc7, 0x6d, 0xe3, 0xaf, + 0x02, 0xda, 0xfa, 0xfa, 0xb3, 0x2b, 0xb3, 0x45, 0xef, 0xe0, 0xb9, 0x60, 0x77, 0x3c, 0xa0, 0xcd, + 0xfa, 0xa9, 0x10, 0x75, 0x48, 0xe7, 0xd5, 0x87, 0x2a, 0x03, 0x2a, 0x04, 0x9a, 0x80, 0xc6, 0x0b, + 0xbf, 0x4e, 0xa2, 0x5a, 0xd0, 0x19, 0x2f, 0x6e, 0xca, 0x2c, 0xd0, 0x27, 0x38, 0x13, 0x94, 0xe7, + 0x94, 0x0b, 0x5d, 0x95, 0x57, 0xe9, 0xf2, 0xd1, 0xee, 0x1f, 0x5a, 0xca, 0x6a, 0x23, 0x59, 0xaf, + 0xf1, 0x4c, 0x56, 0x00, 0xff, 0xe5, 0xa3, 0xbc, 0x95, 0xa3, 0xbc, 0xcb, 0xdd, 0x1e, 0x0d, 0x59, + 0x5d, 0x13, 0x2d, 0x6c, 0xc6, 0x5b, 0x2d, 0x7e, 0x5d, 0xed, 0x59, 0xd3, 0x35, 0x94, 0x6f, 0xe9, + 0x3d, 0xde, 0xd3, 0x24, 0xb3, 0x72, 0xdb, 0x92, 0xcf, 0xc9, 0x3a, 0x79, 0x65, 0x1f, 0xf3, 0x34, + 0xf5, 0x23, 0xfb, 0xb6, 0x2b, 0xbf, 0xd9, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x09, 0xdd, 0xc0, + 0x18, 0x84, 0x03, 0x00, 0x00, } diff --git a/proto/ligato/vpp/l3/l3.proto b/proto/ligato/vpp/l3/l3.proto index 12de27a7ae..a212272399 100644 --- a/proto/ligato/vpp/l3/l3.proto +++ b/proto/ligato/vpp/l3/l3.proto @@ -13,6 +13,7 @@ message ProxyARP { message Range { string first_ip_addr = 1; string last_ip_addr = 2; + uint32 vrf_id = 3; } repeated Range ranges = 2; } diff --git a/tests/integration/vpp/031_proxy_arp_test.go b/tests/integration/vpp/031_proxy_arp_test.go new file mode 100644 index 0000000000..48746ff72c --- /dev/null +++ b/tests/integration/vpp/031_proxy_arp_test.go @@ -0,0 +1,136 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package vpp + +import ( + "net" + "testing" + + . "github.com/onsi/gomega" + + "go.ligato.io/cn-infra/v2/logging/logrus" + + netalloc_mock "go.ligato.io/vpp-agent/v3/plugins/netalloc/mock" + "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/ifaceidx" + l3plugin_vppcalls "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/vppcalls" + "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/vrfidx" + vpp_l3 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l3" + + _ "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin" +) + +func TestProxyARPRange(t *testing.T) { + ctx := setupVPP(t) + defer ctx.teardownVPP() + + ifIndexes := ifaceidx.NewIfaceIndex(logrus.NewLogger("test-if"), "test-if") + vrfIndexes := vrfidx.NewVRFIndex(logrus.NewLogger("test-vrf"), "test-vrf") + vrfIndexes.Put("vrf1-ipv4", &vrfidx.VRFMetadata{Index: 0, Protocol: vpp_l3.VrfTable_IPV4}) + vrfIndexes.Put("vrf1-ipv6", &vrfidx.VRFMetadata{Index: 0, Protocol: vpp_l3.VrfTable_IPV6}) + + h := l3plugin_vppcalls.CompatibleL3VppHandler(ctx.vppClient, ifIndexes, vrfIndexes, + netalloc_mock.NewMockNetAlloc(), logrus.NewLogger("test")) + + tests := []struct { + name string + proxyARPRange *vpp_l3.ProxyARP_Range + addMustFail bool + }{ + { + name: "base test of proxy ARP range", + proxyARPRange: &vpp_l3.ProxyARP_Range{ + FirstIpAddr: "192.168.1.1", + LastIpAddr: "192.168.1.10", + VrfId: 0, + }, + addMustFail: false, + }, + { + name: "Without first IP address", + proxyARPRange: &vpp_l3.ProxyARP_Range{ + LastIpAddr: "192.168.1.10", + VrfId: 0, + }, + addMustFail: true, + }, + { + name: "Without last IP address", + proxyARPRange: &vpp_l3.ProxyARP_Range{ + FirstIpAddr: "192.168.1.1", + VrfId: 0, + }, + addMustFail: true, + }, + { + name: "Without both IP addresses", + proxyARPRange: &vpp_l3.ProxyARP_Range{ + VrfId: 0, + }, + addMustFail: true, + }, + { + name: "No such FIB / VRF", + proxyARPRange: &vpp_l3.ProxyARP_Range{ + FirstIpAddr: "192.168.1.1", + LastIpAddr: "192.168.1.10", + VrfId: 2, + }, + addMustFail: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + initialRanges, err := h.DumpProxyArpRanges() + Expect(err).ToNot(HaveOccurred(), "dumping proxy ARP ranges failed") + Expect(initialRanges).To(HaveLen(0), "expected no proxy ARP ranges in the beginning") + err = h.AddProxyArpRange( + net.ParseIP(test.proxyARPRange.FirstIpAddr).To4(), + net.ParseIP(test.proxyARPRange.LastIpAddr).To4(), + test.proxyARPRange.VrfId, + ) + if test.addMustFail { + Expect(err).To(HaveOccurred(), "adding proxy ARP range passed successfully but must fail") + return + } + Expect(err).ToNot(HaveOccurred(), "adding proxy ARP range failed") + + afterAddRanges, err := h.DumpProxyArpRanges() + Expect(err).ToNot(HaveOccurred(), "dumping proxy ARP ranges failed") + Expect(afterAddRanges).To(HaveLen(1), "expected one proxy ARP range") + Expect(afterAddRanges[0].Range.FirstIpAddr).To(Equal(test.proxyARPRange.FirstIpAddr), + "First IP address of proxy ARP range retrieved from dump is not equal to expected", + ) + Expect(afterAddRanges[0].Range.LastIpAddr).To(Equal(test.proxyARPRange.LastIpAddr), + "Last IP address of proxy ARP range retrieved from dump is not equal to expected", + ) + Expect(afterAddRanges[0].Range.VrfId).To(Equal(test.proxyARPRange.VrfId), + "VRF ID of proxy ARP range retrieved from dump is not equal to expected", + ) + + Expect( + h.DeleteProxyArpRange( + net.ParseIP(test.proxyARPRange.FirstIpAddr).To4(), + net.ParseIP(test.proxyARPRange.LastIpAddr).To4(), + test.proxyARPRange.VrfId, + ), + ).To(Succeed(), "deleting proxy ARP range failed") + + afterDeleteRanges, err := h.DumpProxyArpRanges() + Expect(err).ToNot(HaveOccurred(), "dumping proxy ARP ranges failed") + Expect(afterDeleteRanges).To(HaveLen(0), "expected no proxy ARP ranges after deleting one") + }) + } +}