Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add VRF field to proxy ARP range #1672

Merged
merged 2 commits into from
Jul 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 107 additions & 62 deletions plugins/vpp/l3plugin/descriptor/proxy_arp.go
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -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),
Expand All @@ -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
Expand All @@ -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)
}
}

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions plugins/vpp/l3plugin/vppcalls/l3_vppcalls.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
})
}
Expand Down
33 changes: 25 additions & 8 deletions plugins/vpp/l3plugin/vppcalls/vpp1904/proxyarp_vppcalls.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
package vpp1904

import (
"fmt"
"net"

"github.com/pkg/errors"
"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp1904/ip"
)
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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
}
Loading