go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/natplugin/vppcalls/vpp2106/nat_vppcalls.go (about) 1 // Copyright (c) 2021 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 vpp2106 16 17 import ( 18 "fmt" 19 "net" 20 21 "go.fd.io/govpp/api" 22 23 "github.com/pkg/errors" 24 25 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/interface_types" 26 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/ip_types" 27 vpp_nat_ed "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/nat44_ed" 28 vpp_nat_ei "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/nat44_ei" 29 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2106/nat_types" 30 "go.ligato.io/vpp-agent/v3/plugins/vpp/natplugin/vppcalls" 31 nat "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/nat" 32 ) 33 34 // Num protocol representation 35 const ( 36 ICMP uint8 = 1 37 TCP uint8 = 6 38 UDP uint8 = 17 39 ) 40 41 const ( 42 // NoInterface is sw-if-idx which means 'no interface' 43 NoInterface = interface_types.InterfaceIndex(^uint32(0)) 44 // Maximal length of tag 45 maxTagLen = 64 46 ) 47 48 // holds a list of NAT44 ED flags set 49 type nat44EdFlags struct { 50 isTwiceNat bool 51 isSelfTwiceNat bool 52 isOut2In bool 53 isAddrOnly bool 54 isOutside bool 55 isInside bool 56 isStatic bool 57 isExtHostValid bool 58 } 59 60 // holds a list of NAT44 EI flags set 61 type nat44EiFlags struct { 62 eiStaticMappingOnly bool 63 eiConnectionTracking bool 64 eiOut2InDpo bool 65 eiAddrOnlyMapping bool 66 eiIfInside bool 67 eiIfOutside bool 68 eiStaticMapping bool 69 } 70 71 func (h *NatVppHandler) enableNAT44EdPlugin(opts vppcalls.Nat44InitOpts) error { 72 var flags vpp_nat_ed.Nat44ConfigFlags 73 if opts.ConnectionTracking { 74 flags |= vpp_nat_ed.NAT44_IS_CONNECTION_TRACKING 75 } 76 if opts.StaticMappingOnly { 77 flags |= vpp_nat_ed.NAT44_IS_STATIC_MAPPING_ONLY 78 } 79 80 req := &vpp_nat_ed.Nat44EdPluginEnableDisable{ 81 Enable: true, 82 Flags: flags, 83 } 84 reply := &vpp_nat_ed.Nat44EdPluginEnableDisableReply{} 85 86 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 87 return err 88 } 89 return nil 90 } 91 92 func (h *NatVppHandler) enableNAT44EiPlugin(opts vppcalls.Nat44InitOpts) error { 93 var flags vpp_nat_ei.Nat44EiConfigFlags 94 if opts.ConnectionTracking { 95 flags |= vpp_nat_ei.NAT44_EI_CONNECTION_TRACKING 96 } 97 if opts.StaticMappingOnly { 98 flags |= vpp_nat_ei.NAT44_EI_STATIC_MAPPING_ONLY 99 } 100 if opts.OutToInDPO { 101 flags |= vpp_nat_ei.NAT44_EI_OUT2IN_DPO 102 } 103 104 req := &vpp_nat_ei.Nat44EiPluginEnableDisable{ 105 Enable: true, 106 Flags: flags, 107 } 108 reply := &vpp_nat_ei.Nat44EiPluginEnableDisableReply{} 109 110 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 111 return err 112 } 113 return nil 114 } 115 116 // EnableNAT44plugin and apply the given set of options. 117 func (h *NatVppHandler) EnableNAT44Plugin(opts vppcalls.Nat44InitOpts) error { 118 // VPP since version 21.06 supports running both NAT EI and NAT ED simultaneously, 119 // but not vpp-agent yet. 120 // TODO: separate vpp-agent natplugin into 2 separate plugins 121 // (for ED and EI NAT) or create a separate handlers inside one plugin, 122 // this have number of advantages and will probably also become necessary as VPP 123 // NAT plugins will differ more and more over time. 124 if opts.EndpointDependent { 125 h.ed = true 126 return h.enableNAT44EdPlugin(opts) 127 } else { 128 h.ed = false 129 return h.enableNAT44EiPlugin(opts) 130 } 131 } 132 133 func (h *NatVppHandler) disableNAT44EdPlugin() error { 134 req := &vpp_nat_ed.Nat44EdPluginEnableDisable{ 135 Enable: false, 136 } 137 reply := &vpp_nat_ed.Nat44EdPluginEnableDisableReply{} 138 err := h.callsChannel.SendRequest(req).ReceiveReply(reply) 139 if err == api.VPPApiError(1) { 140 return nil 141 } else if err != nil { 142 return err 143 } 144 return nil 145 } 146 147 func (h *NatVppHandler) disableNAT44EiPlugin() error { 148 req := &vpp_nat_ei.Nat44EiPluginEnableDisable{ 149 Enable: false, 150 } 151 reply := &vpp_nat_ei.Nat44EiPluginEnableDisableReply{} 152 err := h.callsChannel.SendRequest(req).ReceiveReply(reply) 153 if err == api.VPPApiError(1) { 154 return nil 155 } else if err != nil { 156 return err 157 } 158 return nil 159 } 160 161 // DisableNAT44Plugin disables NAT44 plugin. 162 func (h *NatVppHandler) DisableNAT44Plugin() error { 163 if h.ed { 164 return h.disableNAT44EdPlugin() 165 } else { 166 return h.disableNAT44EiPlugin() 167 } 168 } 169 170 func (h *NatVppHandler) setNat44EdForwarding(enableFwd bool) error { 171 req := &vpp_nat_ed.Nat44ForwardingEnableDisable{ 172 Enable: enableFwd, 173 } 174 reply := &vpp_nat_ed.Nat44ForwardingEnableDisableReply{} 175 176 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 177 return err 178 } 179 180 return nil 181 } 182 183 func (h *NatVppHandler) setNat44EiForwarding(enableFwd bool) error { 184 req := &vpp_nat_ei.Nat44EiForwardingEnableDisable{ 185 Enable: enableFwd, 186 } 187 reply := &vpp_nat_ei.Nat44EiForwardingEnableDisableReply{} 188 189 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 190 return err 191 } 192 193 return nil 194 } 195 196 // SetNat44Forwarding configures NAT44 forwarding. 197 func (h *NatVppHandler) SetNat44Forwarding(enableFwd bool) error { 198 if h.ed { 199 return h.setNat44EdForwarding(enableFwd) 200 } else { 201 return h.setNat44EiForwarding(enableFwd) 202 } 203 } 204 205 // EnableNat44Interface enables NAT44 feature for provided interface. 206 func (h *NatVppHandler) EnableNat44Interface(iface string, isInside, isOutput bool) error { 207 if isOutput { 208 return h.handleNat44InterfaceOutputFeature(iface, isInside, true) 209 } 210 return h.handleNat44Interface(iface, isInside, true) 211 } 212 213 // DisableNat44Interface disables NAT44 feature for provided interface. 214 func (h *NatVppHandler) DisableNat44Interface(iface string, isInside, isOutput bool) error { 215 if isOutput { 216 return h.handleNat44InterfaceOutputFeature(iface, isInside, false) 217 } 218 return h.handleNat44Interface(iface, isInside, false) 219 } 220 221 // AddNat44AddressPool adds new IPV4 address pool into the NAT pools. 222 func (h *NatVppHandler) AddNat44AddressPool(vrf uint32, firstIP, lastIP string, twiceNat bool) error { 223 return h.handleNat44AddressPool(vrf, firstIP, lastIP, twiceNat, true) 224 } 225 226 // DelNat44AddressPool removes existing IPv4 address pool from the NAT pools. 227 func (h *NatVppHandler) DelNat44AddressPool(vrf uint32, firstIP, lastIP string, twiceNat bool) error { 228 return h.handleNat44AddressPool(vrf, firstIP, lastIP, twiceNat, false) 229 } 230 231 // SetVirtualReassemblyIPv4 configures NAT virtual reassembly for IPv4 packets. 232 func (h *NatVppHandler) SetVirtualReassemblyIPv4(vrCfg *nat.VirtualReassembly) error { 233 return h.handleNatVirtualReassembly(vrCfg, false) 234 } 235 236 // SetVirtualReassemblyIPv6 configures NAT virtual reassembly for IPv6 packets. 237 func (h *NatVppHandler) SetVirtualReassemblyIPv6(vrCfg *nat.VirtualReassembly) error { 238 return h.handleNatVirtualReassembly(vrCfg, true) 239 } 240 241 // AddNat44IdentityMapping adds new NAT44 identity mapping 242 func (h *NatVppHandler) AddNat44IdentityMapping(mapping *nat.DNat44_IdentityMapping, dnatLabel string) error { 243 return h.handleNat44IdentityMapping(mapping, dnatLabel, true) 244 } 245 246 // DelNat44IdentityMapping removes existing NAT44 identity mapping 247 func (h *NatVppHandler) DelNat44IdentityMapping(mapping *nat.DNat44_IdentityMapping, dnatLabel string) error { 248 return h.handleNat44IdentityMapping(mapping, dnatLabel, false) 249 } 250 251 // AddNat44StaticMapping creates new NAT44 static mapping entry. 252 func (h *NatVppHandler) AddNat44StaticMapping(mapping *nat.DNat44_StaticMapping, dnatLabel string) error { 253 if len(mapping.LocalIps) == 0 { 254 return errors.Errorf("cannot configure static mapping for DNAT %s: no local address provided", dnatLabel) 255 } 256 if len(mapping.LocalIps) == 1 { 257 return h.handleNat44StaticMapping(mapping, dnatLabel, true) 258 } 259 return h.handleNat44StaticMappingLb(mapping, dnatLabel, true) 260 } 261 262 // DelNat44StaticMapping removes existing NAT44 static mapping entry. 263 func (h *NatVppHandler) DelNat44StaticMapping(mapping *nat.DNat44_StaticMapping, dnatLabel string) error { 264 if len(mapping.LocalIps) == 0 { 265 return errors.Errorf("cannot un-configure static mapping from DNAT %s: no local address provided", dnatLabel) 266 } 267 if len(mapping.LocalIps) == 1 { 268 return h.handleNat44StaticMapping(mapping, dnatLabel, false) 269 } 270 return h.handleNat44StaticMappingLb(mapping, dnatLabel, false) 271 } 272 273 func (h *NatVppHandler) handleNatEd44Interface(iface string, isInside, isAdd bool) error { 274 // get interface metadata 275 ifaceMeta, found := h.ifIndexes.LookupByName(iface) 276 if !found { 277 return errors.New("failed to get interface metadata") 278 } 279 280 req := &vpp_nat_ed.Nat44InterfaceAddDelFeature{ 281 SwIfIndex: interface_types.InterfaceIndex(ifaceMeta.SwIfIndex), 282 Flags: setNat44EdFlags(&nat44EdFlags{isInside: isInside}), 283 IsAdd: isAdd, 284 } 285 reply := &vpp_nat_ed.Nat44InterfaceAddDelFeatureReply{} 286 287 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 288 return err 289 } 290 291 return nil 292 } 293 294 func (h *NatVppHandler) handleNat44EiInterface(iface string, isInside, isAdd bool) error { 295 // get interface metadata 296 ifaceMeta, found := h.ifIndexes.LookupByName(iface) 297 if !found { 298 return errors.New("failed to get interface metadata") 299 } 300 301 req := &vpp_nat_ei.Nat44EiInterfaceAddDelFeature{ 302 SwIfIndex: interface_types.InterfaceIndex(ifaceMeta.SwIfIndex), 303 Flags: setNat44EiFlags(&nat44EiFlags{eiIfInside: isInside}), 304 IsAdd: isAdd, 305 } 306 reply := &vpp_nat_ei.Nat44EiInterfaceAddDelFeatureReply{} 307 308 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 309 return err 310 } 311 312 return nil 313 } 314 315 // Calls VPP binary API to set/unset interface NAT44 feature. 316 func (h *NatVppHandler) handleNat44Interface(iface string, isInside, isAdd bool) error { 317 if h.ed { 318 return h.handleNatEd44Interface(iface, isInside, isAdd) 319 } else { 320 return h.handleNat44EiInterface(iface, isInside, isAdd) 321 } 322 } 323 324 func (h *NatVppHandler) handleNat44EdInterfaceOutputFeature(iface string, isInside, isAdd bool) error { 325 // get interface metadata 326 ifaceMeta, found := h.ifIndexes.LookupByName(iface) 327 if !found { 328 return errors.New("failed to get interface metadata") 329 } 330 331 req := &vpp_nat_ed.Nat44InterfaceAddDelOutputFeature{ 332 SwIfIndex: interface_types.InterfaceIndex(ifaceMeta.SwIfIndex), 333 Flags: setNat44EdFlags(&nat44EdFlags{isInside: isInside}), 334 IsAdd: isAdd, 335 } 336 reply := &vpp_nat_ed.Nat44InterfaceAddDelOutputFeatureReply{} 337 338 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 339 return err 340 } 341 342 return nil 343 } 344 345 func (h *NatVppHandler) handleNat44EiInterfaceOutputFeature(iface string, isInside, isAdd bool) error { 346 // get interface metadata 347 ifaceMeta, found := h.ifIndexes.LookupByName(iface) 348 if !found { 349 return errors.New("failed to get interface metadata") 350 } 351 352 req := &vpp_nat_ei.Nat44EiInterfaceAddDelFeature{ 353 SwIfIndex: interface_types.InterfaceIndex(ifaceMeta.SwIfIndex), 354 Flags: setNat44EiFlags(&nat44EiFlags{eiIfInside: isInside}), 355 IsAdd: isAdd, 356 } 357 reply := &vpp_nat_ei.Nat44EiInterfaceAddDelFeatureReply{} 358 359 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 360 return err 361 } 362 363 return nil 364 } 365 366 // Calls VPP binary API to set/unset interface NAT44 output feature 367 func (h *NatVppHandler) handleNat44InterfaceOutputFeature(iface string, isInside, isAdd bool) error { 368 if h.ed { 369 return h.handleNat44EdInterfaceOutputFeature(iface, isInside, isAdd) 370 } else { 371 return h.handleNat44EiInterfaceOutputFeature(iface, isInside, isAdd) 372 } 373 } 374 375 func (h *NatVppHandler) handleNat44EdAddressPool(vrf uint32, firstIP, lastIP string, twiceNat, isAdd bool) error { 376 firstAddr, err := ipTo4Address(firstIP) 377 if err != nil { 378 return errors.Errorf("unable to parse address %s from the NAT pool: %v", firstIP, err) 379 } 380 lastAddr := firstAddr 381 if lastIP != "" { 382 lastAddr, err = ipTo4Address(lastIP) 383 if err != nil { 384 return errors.Errorf("unable to parse address %s from the NAT pool: %v", lastIP, err) 385 } 386 } 387 388 req := &vpp_nat_ed.Nat44AddDelAddressRange{ 389 FirstIPAddress: firstAddr, 390 LastIPAddress: lastAddr, 391 VrfID: vrf, 392 Flags: setNat44EdFlags(&nat44EdFlags{isTwiceNat: twiceNat}), 393 IsAdd: isAdd, 394 } 395 reply := &vpp_nat_ed.Nat44AddDelAddressRangeReply{} 396 397 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 398 return err 399 } 400 401 return nil 402 } 403 404 func (h *NatVppHandler) handleNat44EiAddressPool(vrf uint32, firstIP, lastIP string, twiceNat, isAdd bool) error { 405 firstAddr, err := ipTo4Address(firstIP) 406 if err != nil { 407 return errors.Errorf("unable to parse address %s from the NAT pool: %v", firstIP, err) 408 } 409 lastAddr := firstAddr 410 if lastIP != "" { 411 lastAddr, err = ipTo4Address(lastIP) 412 if err != nil { 413 return errors.Errorf("unable to parse address %s from the NAT pool: %v", lastIP, err) 414 } 415 } 416 417 req := &vpp_nat_ei.Nat44EiAddDelAddressRange{ 418 FirstIPAddress: firstAddr, 419 LastIPAddress: lastAddr, 420 VrfID: vrf, 421 IsAdd: isAdd, 422 } 423 reply := &vpp_nat_ei.Nat44EiAddDelAddressRangeReply{} 424 425 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 426 return err 427 } 428 429 return nil 430 } 431 432 // Calls VPP binary API to add/remove addresses to/from the NAT44 pool. 433 func (h *NatVppHandler) handleNat44AddressPool(vrf uint32, firstIP, lastIP string, twiceNat, isAdd bool) error { 434 if h.ed { 435 return h.handleNat44EdAddressPool(vrf, firstIP, lastIP, twiceNat, isAdd) 436 } else { 437 return h.handleNat44EiAddressPool(vrf, firstIP, lastIP, twiceNat, isAdd) 438 } 439 } 440 441 // Calls VPP binary API to setup NAT virtual reassembly 442 func (h *NatVppHandler) handleNatVirtualReassembly(vrCfg *nat.VirtualReassembly, isIpv6 bool) error { 443 // Virtual Reassembly has been removed from NAT API in VPP (moved to IP API) 444 // TODO: define IPReassembly model in L3 plugin 445 return nil 446 /*req := &vpp_nat.NatSetReass{ 447 Timeout: vrCfg.Timeout, 448 MaxReass: uint16(vrCfg.MaxReassemblies), 449 MaxFrag: uint8(vrCfg.MaxFragments), 450 DropFrag: boolToUint(vrCfg.DropFragments), 451 IsIP6: isIpv6, 452 } 453 reply := &vpp_nat.NatSetReassReply{} 454 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 455 return err 456 }*/ 457 } 458 459 // Calls VPP binary API to add/remove NAT44 static mapping 460 func (h *NatVppHandler) handleNat44StaticMapping(mapping *nat.DNat44_StaticMapping, dnatLabel string, isAdd bool) error { 461 var ifIdx = NoInterface 462 var exIPAddr ip_types.IP4Address 463 464 // check tag length limit 465 if err := checkTagLength(dnatLabel); err != nil { 466 return err 467 } 468 469 // parse local endpoint 470 lcIPAddr, err := ipTo4Address(mapping.LocalIps[0].LocalIp) 471 if err != nil { 472 return errors.Errorf("cannot configure DNAT static mapping %s: unable to parse local IP %s: %v", 473 dnatLabel, mapping.LocalIps[0].LocalIp, err) 474 } 475 lcPort := uint16(mapping.LocalIps[0].LocalPort) 476 lcVrf := mapping.LocalIps[0].VrfId 477 478 // Check external interface (prioritized over external IP) 479 if mapping.ExternalInterface != "" { 480 // Check external interface 481 ifMeta, found := h.ifIndexes.LookupByName(mapping.ExternalInterface) 482 if !found { 483 return errors.Errorf("cannot configure static mapping for DNAT %s: required external interface %s is missing", 484 dnatLabel, mapping.ExternalInterface) 485 } 486 ifIdx = interface_types.InterfaceIndex(ifMeta.SwIfIndex) 487 } else { 488 // Parse external IP address 489 exIPAddr, err = ipTo4Address(mapping.ExternalIp) 490 if err != nil { 491 return errors.Errorf("cannot configure static mapping for DNAT %s: unable to parse external IP %s: %v", 492 dnatLabel, mapping.ExternalIp, err) 493 } 494 } 495 496 // Resolve mapping (address only or address and port) 497 var addrOnly bool 498 if lcPort == 0 || mapping.ExternalPort == 0 { 499 addrOnly = true 500 } 501 502 if h.ed { 503 req := &vpp_nat_ed.Nat44AddDelStaticMappingV2{ 504 Tag: dnatLabel, 505 LocalIPAddress: lcIPAddr, 506 ExternalIPAddress: exIPAddr, 507 Protocol: h.protocolNBValueToNumber(mapping.Protocol), 508 ExternalSwIfIndex: ifIdx, 509 VrfID: lcVrf, 510 Flags: setNat44EdFlags(&nat44EdFlags{ 511 isTwiceNat: mapping.TwiceNat == nat.DNat44_StaticMapping_ENABLED, 512 isSelfTwiceNat: mapping.TwiceNat == nat.DNat44_StaticMapping_SELF, 513 isOut2In: true, 514 isAddrOnly: addrOnly, 515 }), 516 IsAdd: isAdd, 517 } 518 519 if !addrOnly { 520 req.LocalPort = lcPort 521 req.ExternalPort = uint16(mapping.ExternalPort) 522 } 523 524 // Applying(if needed) the override of IP address picking from twice-NAT address pool 525 if mapping.TwiceNatPoolIp != "" { 526 req.MatchPool = true 527 req.PoolIPAddress, err = ipTo4Address(mapping.TwiceNatPoolIp) 528 if err != nil { 529 return errors.Errorf("cannot configure static mapping for DNAT %s: unable to parse "+ 530 "twice-NAT pool IP %s: %v", dnatLabel, mapping.TwiceNatPoolIp, err) 531 } 532 } 533 534 reply := &vpp_nat_ed.Nat44AddDelStaticMappingV2Reply{} 535 536 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 537 return err 538 } 539 } else { 540 req := &vpp_nat_ei.Nat44EiAddDelStaticMapping{ 541 Tag: dnatLabel, 542 LocalIPAddress: lcIPAddr, 543 ExternalIPAddress: exIPAddr, 544 Protocol: h.protocolNBValueToNumber(mapping.Protocol), 545 ExternalSwIfIndex: ifIdx, 546 VrfID: lcVrf, 547 Flags: setNat44EiFlags(&nat44EiFlags{ 548 eiAddrOnlyMapping: addrOnly, 549 }), 550 IsAdd: isAdd, 551 } 552 553 if !addrOnly { 554 req.LocalPort = lcPort 555 req.ExternalPort = uint16(mapping.ExternalPort) 556 } 557 558 reply := &vpp_nat_ei.Nat44EiAddDelStaticMappingReply{} 559 560 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 561 return err 562 } 563 } 564 565 return nil 566 } 567 568 func (h *NatVppHandler) handleNat44EdStaticMappingLb(mapping *nat.DNat44_StaticMapping, dnatLabel string, isAdd bool) error { 569 // check tag length limit 570 if err := checkTagLength(dnatLabel); err != nil { 571 return err 572 } 573 574 // parse external IP address 575 exIPAddrByte, err := ipTo4Address(mapping.ExternalIp) 576 if err != nil { 577 return errors.Errorf("cannot configure LB static mapping for DNAT %s: unable to parse external IP %s: %v", 578 dnatLabel, mapping.ExternalIp, err) 579 } 580 581 // In this case, external port is required 582 if mapping.ExternalPort == 0 { 583 return errors.Errorf("cannot configure LB static mapping for DNAT %s: external port is not set", dnatLabel) 584 } 585 586 // Transform local IP/Ports 587 var locals []vpp_nat_ed.Nat44LbAddrPort 588 for _, local := range mapping.LocalIps { 589 if local.LocalPort == 0 { 590 return errors.Errorf("cannot set local IP/Port for DNAT mapping %s: port is missing", 591 dnatLabel) 592 } 593 594 localIP, err := ipTo4Address(local.LocalIp) 595 if err != nil { 596 return errors.Errorf("cannot set local IP/Port for DNAT mapping %s: unable to parse local IP %v: %v", 597 dnatLabel, local.LocalIp, err) 598 } 599 600 locals = append(locals, vpp_nat_ed.Nat44LbAddrPort{ 601 Addr: localIP, 602 Port: uint16(local.LocalPort), 603 Probability: uint8(local.Probability), 604 VrfID: local.VrfId, 605 }) 606 } 607 608 req := &vpp_nat_ed.Nat44AddDelLbStaticMapping{ 609 Tag: dnatLabel, 610 Locals: locals, 611 // LocalNum: uint32(len(locals)), // should not be needed (will be set by struc) 612 ExternalAddr: exIPAddrByte, 613 ExternalPort: uint16(mapping.ExternalPort), 614 Protocol: h.protocolNBValueToNumber(mapping.Protocol), 615 Flags: setNat44EdFlags(&nat44EdFlags{ 616 isTwiceNat: mapping.TwiceNat == nat.DNat44_StaticMapping_ENABLED, 617 isSelfTwiceNat: mapping.TwiceNat == nat.DNat44_StaticMapping_SELF, 618 isOut2In: true, 619 }), 620 IsAdd: isAdd, 621 Affinity: mapping.SessionAffinity, 622 } 623 624 reply := &vpp_nat_ed.Nat44AddDelLbStaticMappingReply{} 625 626 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 627 return err 628 } 629 630 return nil 631 } 632 633 // Calls VPP binary API to add/remove NAT44 static mapping with load balancing. 634 func (h *NatVppHandler) handleNat44StaticMappingLb(mapping *nat.DNat44_StaticMapping, dnatLabel string, isAdd bool) error { 635 if h.ed { 636 return h.handleNat44EdStaticMappingLb(mapping, dnatLabel, isAdd) 637 } else { 638 // no static mapping with load balancing implemented for EI nat yet 639 return nil 640 } 641 } 642 643 // Calls VPP binary API to add/remove NAT44 identity mapping. 644 func (h *NatVppHandler) handleNat44IdentityMapping(mapping *nat.DNat44_IdentityMapping, dnatLabel string, isAdd bool) (err error) { 645 var ifIdx = NoInterface 646 var ipAddr ip_types.IP4Address 647 648 // check tag length limit 649 if err := checkTagLength(dnatLabel); err != nil { 650 return err 651 } 652 653 // get interface index 654 if mapping.Interface != "" { 655 ifMeta, found := h.ifIndexes.LookupByName(mapping.Interface) 656 if !found { 657 return errors.Errorf("failed to configure identity mapping for DNAT %s: addressed interface %s does not exist", 658 dnatLabel, mapping.Interface) 659 } 660 ifIdx = interface_types.InterfaceIndex(ifMeta.SwIfIndex) 661 } 662 663 if ifIdx == NoInterface { 664 // Case with IP (optionally port). Verify and parse input IP/port 665 ipAddr, err = ipTo4Address(mapping.IpAddress) 666 if err != nil { 667 return errors.Errorf("failed to configure identity mapping for DNAT %s: unable to parse IP address %s: %v", 668 dnatLabel, mapping.IpAddress, err) 669 } 670 } 671 672 var addrOnly bool 673 if mapping.Port == 0 { 674 addrOnly = true 675 } 676 677 if h.ed { 678 req := &vpp_nat_ed.Nat44AddDelIdentityMapping{ 679 Tag: dnatLabel, 680 Flags: setNat44EdFlags(&nat44EdFlags{isAddrOnly: addrOnly}), 681 IPAddress: ipAddr, 682 Port: uint16(mapping.Port), 683 Protocol: h.protocolNBValueToNumber(mapping.Protocol), 684 SwIfIndex: ifIdx, 685 VrfID: mapping.VrfId, 686 IsAdd: isAdd, 687 } 688 689 reply := &vpp_nat_ed.Nat44AddDelIdentityMappingReply{} 690 691 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 692 return err 693 } 694 } else { 695 req := &vpp_nat_ei.Nat44EiAddDelIdentityMapping{ 696 Tag: dnatLabel, 697 Flags: setNat44EiFlags(&nat44EiFlags{eiAddrOnlyMapping: addrOnly}), 698 IPAddress: ipAddr, 699 Port: uint16(mapping.Port), 700 Protocol: h.protocolNBValueToNumber(mapping.Protocol), 701 SwIfIndex: ifIdx, 702 VrfID: mapping.VrfId, 703 IsAdd: isAdd, 704 } 705 706 reply := &vpp_nat_ei.Nat44EiAddDelIdentityMappingReply{} 707 708 if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil { 709 return err 710 } 711 } 712 713 return nil 714 } 715 716 func setNat44EdFlags(flags *nat44EdFlags) nat_types.NatConfigFlags { 717 var flagsCfg nat_types.NatConfigFlags 718 if flags.isTwiceNat { 719 flagsCfg |= nat_types.NAT_IS_TWICE_NAT 720 } 721 if flags.isSelfTwiceNat { 722 flagsCfg |= nat_types.NAT_IS_SELF_TWICE_NAT 723 } 724 if flags.isOut2In { 725 flagsCfg |= nat_types.NAT_IS_OUT2IN_ONLY 726 } 727 if flags.isAddrOnly { 728 flagsCfg |= nat_types.NAT_IS_ADDR_ONLY 729 } 730 if flags.isOutside { 731 flagsCfg |= nat_types.NAT_IS_OUTSIDE 732 } 733 if flags.isInside { 734 flagsCfg |= nat_types.NAT_IS_INSIDE 735 } 736 if flags.isStatic { 737 flagsCfg |= nat_types.NAT_IS_STATIC 738 } 739 if flags.isExtHostValid { 740 flagsCfg |= nat_types.NAT_IS_EXT_HOST_VALID 741 } 742 return flagsCfg 743 } 744 745 func setNat44EiFlags(flags *nat44EiFlags) vpp_nat_ei.Nat44EiConfigFlags { 746 var flagsCfg vpp_nat_ei.Nat44EiConfigFlags 747 if flags.eiStaticMappingOnly { 748 flagsCfg |= vpp_nat_ei.NAT44_EI_STATIC_MAPPING_ONLY 749 } 750 if flags.eiConnectionTracking { 751 flagsCfg |= vpp_nat_ei.NAT44_EI_CONNECTION_TRACKING 752 } 753 if flags.eiOut2InDpo { 754 flagsCfg |= vpp_nat_ei.NAT44_EI_OUT2IN_DPO 755 } 756 if flags.eiAddrOnlyMapping { 757 flagsCfg |= vpp_nat_ei.NAT44_EI_ADDR_ONLY_MAPPING 758 } 759 if flags.eiIfInside { 760 flagsCfg |= vpp_nat_ei.NAT44_EI_IF_INSIDE 761 } 762 if flags.eiIfOutside { 763 flagsCfg |= vpp_nat_ei.NAT44_EI_IF_OUTSIDE 764 } 765 if flags.eiStaticMapping { 766 flagsCfg |= vpp_nat_ei.NAT44_EI_STATIC_MAPPING 767 } 768 return flagsCfg 769 } 770 771 func ipTo4Address(ipStr string) (addr ip_types.IP4Address, err error) { 772 netIP := net.ParseIP(ipStr) 773 if netIP == nil { 774 return ip_types.IP4Address{}, fmt.Errorf("invalid IP: %q", ipStr) 775 } 776 if ip4 := netIP.To4(); ip4 != nil { 777 var ip4Addr ip_types.IP4Address 778 copy(ip4Addr[:], netIP.To4()) 779 addr = ip4Addr 780 } else { 781 return ip_types.IP4Address{}, fmt.Errorf("required IPv4, provided: %q", ipStr) 782 } 783 return 784 } 785 786 // checkTagLength serves as a validator for static/identity mapping tag length 787 func checkTagLength(tag string) error { 788 if len(tag) > maxTagLen { 789 return errors.Errorf("DNAT label '%s' has %d bytes, max allowed is %d", 790 tag, len(tag), maxTagLen) 791 } 792 return nil 793 }