go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/l3plugin/descriptor/proxy_arp.go (about) 1 // Copyright (c) 2020 Cisco and/or its affiliates. 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 descriptor 16 17 import ( 18 "net" 19 "strings" 20 21 "github.com/pkg/errors" 22 "go.ligato.io/cn-infra/v2/logging" 23 24 "go.ligato.io/vpp-agent/v3/pkg/models" 25 kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api" 26 ifdescriptor "go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/descriptor" 27 "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/descriptor/adapter" 28 "go.ligato.io/vpp-agent/v3/plugins/vpp/l3plugin/vppcalls" 29 l3 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l3" 30 ) 31 32 const ( 33 // ProxyArpDescriptorName is the name of the descriptor. 34 ProxyArpDescriptorName = "vpp-proxy-arp" 35 36 // Dependency labels: 37 vrfTableProxyARPDep = "vrf-table-exists" 38 ) 39 40 // Validation errors: 41 var ( 42 // ErrMissingIP returned when one of IP fields in ProxyARP range is not set. 43 ErrMissingIP = errors.New("missing IP address") 44 // ErrIPWithMask returned when one of IP fields in ProxyARP range is set with a subnet mask. 45 ErrIPWithMask = errors.New("only one IP must be defined (e.g. \"192.0.2.1\"), not a subnet") 46 // ErrInvalidIP returned when one of IP fields in ProxyARP range can not be parsed. 47 ErrInvalidIP = errors.New("invalid IP address") 48 // ErrIPv6NotSupported returned when one of IP fields in ProxyARP range is defined as IPv6. 49 ErrIPv6NotSupported = errors.New("IP address must be IPv4, not IPv6") 50 ) 51 52 // ProxyArpDescriptor teaches KVScheduler how to configure VPP proxy ARPs. 53 type ProxyArpDescriptor struct { 54 log logging.Logger 55 proxyArpHandler vppcalls.ProxyArpVppAPI 56 scheduler kvs.KVScheduler 57 } 58 59 // NewProxyArpDescriptor creates a new instance of the ProxyArpDescriptor. 60 func NewProxyArpDescriptor(scheduler kvs.KVScheduler, 61 proxyArpHandler vppcalls.ProxyArpVppAPI, log logging.PluginLogger) *kvs.KVDescriptor { 62 63 ctx := &ProxyArpDescriptor{ 64 scheduler: scheduler, 65 proxyArpHandler: proxyArpHandler, 66 log: log.NewLogger("proxy-arp-descriptor"), 67 } 68 69 typedDescr := &adapter.ProxyARPDescriptor{ 70 Name: ProxyArpDescriptorName, 71 NBKeyPrefix: l3.ModelProxyARP.KeyPrefix(), 72 ValueTypeName: l3.ModelProxyARP.ProtoName(), 73 KeySelector: l3.ModelProxyARP.IsKeyValid, 74 ValueComparator: ctx.EquivalentProxyArps, 75 Validate: ctx.Validate, 76 Create: ctx.Create, 77 Update: ctx.Update, 78 Delete: ctx.Delete, 79 Retrieve: ctx.Retrieve, 80 Dependencies: ctx.Dependencies, 81 DerivedValues: ctx.DerivedValues, 82 RetrieveDependencies: []string{ifdescriptor.InterfaceDescriptorName}, 83 } 84 return adapter.NewProxyARPDescriptor(typedDescr) 85 } 86 87 // Validate validates ProxyARP setup. 88 func (d *ProxyArpDescriptor) Validate(key string, proxyArp *l3.ProxyARP) error { 89 for _, r := range proxyArp.Ranges { 90 if r.FirstIpAddr == "" { 91 return kvs.NewInvalidValueError(ErrMissingIP, "ranges.first_ip_addr") 92 } 93 if r.LastIpAddr == "" { 94 return kvs.NewInvalidValueError(ErrMissingIP, "ranges.last_ip_addr") 95 } 96 97 if strings.Contains(r.FirstIpAddr, "/") { 98 return kvs.NewInvalidValueError(ErrIPWithMask, "ranges.first_ip_addr") 99 } 100 if strings.Contains(r.LastIpAddr, "/") { 101 return kvs.NewInvalidValueError(ErrIPWithMask, "ranges.last_ip_addr") 102 } 103 104 firstIP := net.ParseIP(r.FirstIpAddr) 105 if firstIP == nil { 106 return kvs.NewInvalidValueError(ErrInvalidIP, "ranges.first_ip_addr") 107 } 108 lastIP := net.ParseIP(r.LastIpAddr) 109 if lastIP == nil { 110 return kvs.NewInvalidValueError(ErrInvalidIP, "ranges.last_ip_addr") 111 } 112 113 if firstIP.To4() == nil { 114 return kvs.NewInvalidValueError(ErrIPv6NotSupported, "ranges.first_ip_addr") 115 } 116 if lastIP.To4() == nil { 117 return kvs.NewInvalidValueError(ErrIPv6NotSupported, "ranges.last_ip_addr") 118 } 119 } 120 return nil 121 } 122 123 // Dependencies lists dependencies for a VPP Proxy ARP. 124 func (d *ProxyArpDescriptor) Dependencies(key string, proxyArp *l3.ProxyARP) []kvs.Dependency { 125 var dependencies []kvs.Dependency 126 127 for _, r := range proxyArp.Ranges { 128 if r.VrfId == 0 { 129 continue 130 } 131 dependencies = append(dependencies, kvs.Dependency{ 132 Label: vrfTableProxyARPDep, 133 Key: l3.VrfTableKey(r.VrfId, l3.VrfTable_IPV4), 134 }) 135 } 136 137 return dependencies 138 } 139 140 // DerivedValues derives l3.ProxyARP_Interface for every interface. 141 func (d *ProxyArpDescriptor) DerivedValues(key string, proxyArp *l3.ProxyARP) (derValues []kvs.KeyValuePair) { 142 for _, iface := range proxyArp.Interfaces { 143 derValues = append(derValues, kvs.KeyValuePair{ 144 Key: l3.ProxyARPInterfaceKey(iface.Name), 145 Value: iface, 146 }) 147 } 148 return derValues 149 } 150 151 // EquivalentProxyArps compares VPP Proxy ARPs. 152 func (d *ProxyArpDescriptor) EquivalentProxyArps(key string, oldValue, newValue *l3.ProxyARP) bool { 153 if len(newValue.Ranges) != len(oldValue.Ranges) { 154 return false 155 } 156 toAdd, toDelete := calculateRngDiff(newValue.Ranges, oldValue.Ranges) 157 return len(toAdd) == 0 && len(toDelete) == 0 158 } 159 160 // Create adds VPP Proxy ARP. 161 func (d *ProxyArpDescriptor) Create(key string, value *l3.ProxyARP) (metadata interface{}, err error) { 162 for _, r := range value.Ranges { 163 firstIP := net.ParseIP(r.FirstIpAddr).To4() 164 lastIP := net.ParseIP(r.LastIpAddr).To4() 165 166 if err := d.proxyArpHandler.AddProxyArpRange(firstIP, lastIP, r.VrfId); err != nil { 167 return nil, errors.Errorf("failed to add proxy ARP address range %s - %s (VRF: %d): %v", firstIP, lastIP, r.VrfId, err) 168 } 169 } 170 return nil, nil 171 } 172 173 // Update modifies VPP Proxy ARP. 174 func (d *ProxyArpDescriptor) Update(key string, oldValue, newValue *l3.ProxyARP, oldMetadata interface{}) (newMetadata interface{}, err error) { 175 toAdd, toDelete := calculateRngDiff(newValue.Ranges, oldValue.Ranges) 176 177 for _, r := range toDelete { 178 firstIP := net.ParseIP(r.FirstIpAddr).To4() 179 lastIP := net.ParseIP(r.LastIpAddr).To4() 180 181 if err := d.proxyArpHandler.DeleteProxyArpRange(firstIP, lastIP, r.VrfId); err != nil { 182 return nil, errors.Errorf("failed to delete proxy ARP address range %s - %s (VRF: %d): %v", firstIP, lastIP, r.VrfId, err) 183 } 184 } 185 186 for _, r := range toAdd { 187 firstIP := net.ParseIP(r.FirstIpAddr).To4() 188 lastIP := net.ParseIP(r.LastIpAddr).To4() 189 190 if err := d.proxyArpHandler.AddProxyArpRange(firstIP, lastIP, r.VrfId); err != nil { 191 return nil, errors.Errorf("failed to add proxy ARP address range %s - %s (VRF: %d): %v", firstIP, lastIP, r.VrfId, err) 192 } 193 } 194 195 return nil, nil 196 } 197 198 // Delete deletes VPP Proxy ARP. 199 func (d *ProxyArpDescriptor) Delete(key string, value *l3.ProxyARP, metadata interface{}) error { 200 for _, r := range value.Ranges { 201 firstIP := net.ParseIP(r.FirstIpAddr).To4() 202 lastIP := net.ParseIP(r.LastIpAddr).To4() 203 204 if err := d.proxyArpHandler.DeleteProxyArpRange(firstIP, lastIP, r.VrfId); err != nil { 205 return errors.Errorf("failed to delete proxy ARP address range %s - %s (VRF: %d): %v", firstIP, lastIP, r.VrfId, err) 206 } 207 } 208 return nil 209 } 210 211 // Retrieve returns VPP Proxy ARP configuration. 212 func (d *ProxyArpDescriptor) Retrieve(correlate []adapter.ProxyARPKVWithMetadata) ( 213 retrieved []adapter.ProxyARPKVWithMetadata, err error) { 214 215 // Retrieve VPP configuration 216 rangesDetails, err := d.proxyArpHandler.DumpProxyArpRanges() 217 if err != nil { 218 return nil, err 219 } 220 ifacesDetails, err := d.proxyArpHandler.DumpProxyArpInterfaces() 221 if err != nil { 222 return nil, err 223 } 224 225 proxyArp := &l3.ProxyARP{} 226 for _, rangeDetail := range rangesDetails { 227 proxyArp.Ranges = append(proxyArp.Ranges, rangeDetail.Range) 228 } 229 for _, ifaceDetail := range ifacesDetails { 230 proxyArp.Interfaces = append(proxyArp.Interfaces, ifaceDetail.Interface) 231 } 232 233 retrieved = append(retrieved, adapter.ProxyARPKVWithMetadata{ 234 Key: models.Key(proxyArp), 235 Value: proxyArp, 236 Origin: kvs.UnknownOrigin, 237 }) 238 239 return retrieved, nil 240 } 241 242 // calculateRngDiff calculates difference between old and new ranges. 243 func calculateRngDiff(newRngs, oldRngs []*l3.ProxyARP_Range) (toAdd, toDelete []*l3.ProxyARP_Range) { 244 // Find missing ranges. 245 for _, newRng := range newRngs { 246 var found bool 247 for _, oldRng := range oldRngs { 248 if newRng.VrfId == oldRng.VrfId && 249 newRng.FirstIpAddr == oldRng.FirstIpAddr && 250 newRng.LastIpAddr == oldRng.LastIpAddr { 251 found = true 252 break 253 } 254 } 255 if !found { 256 toAdd = append(toAdd, newRng) 257 } 258 } 259 // Find obsolete ranges. 260 for _, oldRng := range oldRngs { 261 var found bool 262 for _, newRng := range newRngs { 263 if oldRng.VrfId == newRng.VrfId && 264 oldRng.FirstIpAddr == newRng.FirstIpAddr && 265 oldRng.LastIpAddr == newRng.LastIpAddr { 266 found = true 267 break 268 } 269 } 270 if !found { 271 toDelete = append(toDelete, oldRng) 272 } 273 } 274 return 275 }