go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/natplugin/vppcalls/vpp2210/dump_nat_vppcalls.go (about)

     1  //  Copyright (c) 2022 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 vpp2210
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"io"
    21  	"net"
    22  	"sort"
    23  	"strings"
    24  
    25  	"google.golang.org/protobuf/proto"
    26  
    27  	vpp_nat_ed "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2210/nat44_ed"
    28  	vpp_nat_ei "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2210/nat44_ei"
    29  	"go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2210/nat_types"
    30  	"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/ifaceidx"
    31  	ifs "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces"
    32  	nat "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/nat"
    33  )
    34  
    35  // DNATs sorted by tags
    36  type dnatMap map[string]*nat.DNat44
    37  
    38  // static mappings sorted by tags
    39  type stMappingMap map[string][]*nat.DNat44_StaticMapping
    40  
    41  // identity mappings sorted by tags
    42  type idMappingMap map[string][]*nat.DNat44_IdentityMapping
    43  
    44  // WithLegacyStartupConf returns true if the loaded VPP NAT plugin is still using
    45  // the legacy startup NAT configuration (this is the case for VPP <= 20.09).
    46  func (h *NatVppHandler) WithLegacyStartupConf() bool {
    47  	return false
    48  }
    49  
    50  func (h *NatVppHandler) DefaultNat44GlobalConfig() *nat.Nat44Global {
    51  	return &nat.Nat44Global{
    52  		Forwarding:          false,
    53  		EndpointIndependent: false,
    54  		NatInterfaces:       nil,
    55  		AddressPool:         nil,
    56  		VirtualReassembly:   nil, // VirtualReassembly is not part of NAT API in VPP 20.01+ anymore
    57  	}
    58  }
    59  
    60  func (h *NatVppHandler) nat44EiGlobalConfigDump(dumpDeprecated bool) (cfg *nat.Nat44Global, err error) {
    61  	cfg = &nat.Nat44Global{}
    62  	req := &vpp_nat_ei.Nat44EiShowRunningConfig{}
    63  	reply := &vpp_nat_ei.Nat44EiShowRunningConfigReply{}
    64  	if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
    65  		return nil, err
    66  	}
    67  	cfg.EndpointIndependent = true
    68  	cfg.Forwarding = reply.ForwardingEnabled
    69  	cfg.VirtualReassembly, _, err = h.virtualReassemblyDump()
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  	if dumpDeprecated {
    74  		cfg.NatInterfaces, err = h.nat44InterfaceDump()
    75  		if err != nil {
    76  			return nil, err
    77  		}
    78  		cfg.AddressPool, err = h.nat44AddressDump()
    79  		if err != nil {
    80  			return nil, err
    81  		}
    82  	}
    83  	return
    84  }
    85  
    86  func (h *NatVppHandler) nat44EdGlobalConfigDump(dumpDeprecated bool) (cfg *nat.Nat44Global, err error) {
    87  	cfg = &nat.Nat44Global{}
    88  	req := &vpp_nat_ed.Nat44ShowRunningConfig{}
    89  	reply := &vpp_nat_ed.Nat44ShowRunningConfigReply{}
    90  	if err := h.callsChannel.SendRequest(req).ReceiveReply(reply); err != nil {
    91  		return nil, err
    92  	}
    93  	cfg.EndpointIndependent = false
    94  	cfg.Forwarding = reply.ForwardingEnabled
    95  	cfg.VirtualReassembly, _, err = h.virtualReassemblyDump()
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	if dumpDeprecated {
   100  		cfg.NatInterfaces, err = h.nat44InterfaceDump()
   101  		if err != nil {
   102  			return nil, err
   103  		}
   104  		cfg.AddressPool, err = h.nat44AddressDump()
   105  		if err != nil {
   106  			return nil, err
   107  		}
   108  	}
   109  	return
   110  }
   111  
   112  // Nat44GlobalConfigDump dumps global NAT44 config in NB format.
   113  func (h *NatVppHandler) Nat44GlobalConfigDump(dumpDeprecated bool) (cfg *nat.Nat44Global, err error) {
   114  	if h.ed {
   115  		return h.nat44EdGlobalConfigDump(dumpDeprecated)
   116  	} else {
   117  		return h.nat44EiGlobalConfigDump(dumpDeprecated)
   118  	}
   119  
   120  }
   121  
   122  // DNat44Dump dumps all configured DNAT-44 configurations ordered by label.
   123  func (h *NatVppHandler) DNat44Dump() (dnats []*nat.DNat44, err error) {
   124  	dnatMap := make(dnatMap)
   125  
   126  	// Static mappings
   127  	natStMappings, err := h.nat44StaticMappingDump()
   128  	if err != nil {
   129  		return nil, fmt.Errorf("failed to dump NAT44 static mappings: %v", err)
   130  	}
   131  	for label, mappings := range natStMappings {
   132  		dnat := getOrCreateDNAT(dnatMap, label)
   133  		dnat.StMappings = append(dnat.StMappings, mappings...)
   134  	}
   135  
   136  	// Static mappings with load balancer
   137  	natStLbMappings, err := h.nat44StaticMappingLbDump()
   138  	if err != nil {
   139  		return nil, fmt.Errorf("failed to dump NAT44 static mappings with load balancer: %v", err)
   140  	}
   141  	for label, mappings := range natStLbMappings {
   142  		dnat := getOrCreateDNAT(dnatMap, label)
   143  		dnat.StMappings = append(dnat.StMappings, mappings...)
   144  	}
   145  
   146  	// Identity mappings
   147  	natIDMappings, err := h.nat44IdentityMappingDump()
   148  	if err != nil {
   149  		return nil, fmt.Errorf("failed to dump NAT44 identity mappings: %v", err)
   150  	}
   151  	for label, mappings := range natIDMappings {
   152  		dnat := getOrCreateDNAT(dnatMap, label)
   153  		dnat.IdMappings = append(dnat.IdMappings, mappings...)
   154  	}
   155  
   156  	// Convert map of DNAT configurations into a list.
   157  	for _, dnat := range dnatMap {
   158  		dnats = append(dnats, dnat)
   159  	}
   160  
   161  	// sort to simplify testing
   162  	sort.Slice(dnats, func(i, j int) bool { return dnats[i].Label < dnats[j].Label })
   163  
   164  	return dnats, nil
   165  }
   166  
   167  func (h *NatVppHandler) nat44EiInterfacesDump() ([]*nat.Nat44Interface, error) {
   168  	var natIfs []*nat.Nat44Interface
   169  
   170  	// dump non-output NAT interfaces
   171  	req1 := &vpp_nat_ei.Nat44EiInterfaceDump{}
   172  	reqContext := h.callsChannel.SendMultiRequest(req1)
   173  	for {
   174  		msg := &vpp_nat_ei.Nat44EiInterfaceDetails{}
   175  		stop, err := reqContext.ReceiveReply(msg)
   176  		if err != nil {
   177  			return nil, fmt.Errorf("failed to dump NAT44 interface: %v", err)
   178  		}
   179  		if stop {
   180  			break
   181  		}
   182  		ifName, _, found := h.ifIndexes.LookupBySwIfIndex(uint32(msg.SwIfIndex))
   183  		if !found {
   184  			h.log.Warnf("Interface with index %d not found in the mapping", msg.SwIfIndex)
   185  			continue
   186  		}
   187  		flags := getNat44EiFlags(msg.Flags)
   188  		natIf := &nat.Nat44Interface{
   189  			Name:          ifName,
   190  			NatInside:     flags.eiIfInside,
   191  			NatOutside:    flags.eiIfOutside,
   192  			OutputFeature: false,
   193  		}
   194  		natIfs = append(natIfs, natIf)
   195  	}
   196  
   197  	// dump output NAT interfaces
   198  	var cursor uint32
   199  	for {
   200  		rpcServ, err := h.natEi.Nat44EiOutputInterfaceGet(context.Background(), &vpp_nat_ei.Nat44EiOutputInterfaceGet{
   201  			Cursor: cursor,
   202  		})
   203  		if err != nil {
   204  			return nil, fmt.Errorf("failed to dump NAT44 interface output feature: %v", err)
   205  		}
   206  	RecvLoop:
   207  		for {
   208  			details, reply, err := rpcServ.Recv()
   209  			if err != nil && err != io.EOF {
   210  				return nil, fmt.Errorf("failed to dump NAT44 interface output feature: %v", err)
   211  			}
   212  			if reply != nil {
   213  				// TODO: Possible bug in VPP? When VPP contains no NAT interfaces this
   214  				// reply often returns cursor value of 0 repeatedly even though it should return
   215  				// ^uint32(0). So if the reply contains cursor that is the same as cursor
   216  				// from previous reply, return.
   217  				if reply.Cursor == cursor || reply.Cursor == ^uint32(0) {
   218  					return natIfs, nil
   219  				}
   220  				cursor = reply.Cursor
   221  				break RecvLoop
   222  			}
   223  			if details != nil {
   224  				ifName, _, found := h.ifIndexes.LookupBySwIfIndex(uint32(details.SwIfIndex))
   225  				if !found {
   226  					h.log.Warnf("Interface with index %d not found in the mapping", details.SwIfIndex)
   227  				}
   228  				natIfs = append(natIfs, &nat.Nat44Interface{
   229  					Name:          ifName,
   230  					OutputFeature: true,
   231  				})
   232  			}
   233  		}
   234  	}
   235  }
   236  
   237  func (h *NatVppHandler) nat44EdInterfacesDump() ([]*nat.Nat44Interface, error) {
   238  	var natIfs []*nat.Nat44Interface
   239  
   240  	// dump non-output NAT interfaces
   241  	req1 := &vpp_nat_ed.Nat44InterfaceDump{}
   242  	reqContext := h.callsChannel.SendMultiRequest(req1)
   243  	for {
   244  		msg := &vpp_nat_ed.Nat44InterfaceDetails{}
   245  		stop, err := reqContext.ReceiveReply(msg)
   246  		if err != nil {
   247  			return nil, fmt.Errorf("failed to dump NAT44 interface: %v", err)
   248  		}
   249  		if stop {
   250  			break
   251  		}
   252  		ifName, _, found := h.ifIndexes.LookupBySwIfIndex(uint32(msg.SwIfIndex))
   253  		if !found {
   254  			h.log.Warnf("Interface with index %d not found in the mapping", msg.SwIfIndex)
   255  			continue
   256  		}
   257  		flags := getNat44Flags(msg.Flags)
   258  		natIf := &nat.Nat44Interface{
   259  			Name:          ifName,
   260  			NatInside:     flags.isInside,
   261  			NatOutside:    flags.isOutside,
   262  			OutputFeature: false,
   263  		}
   264  		natIfs = append(natIfs, natIf)
   265  	}
   266  
   267  	// dump output NAT interfaces
   268  	var cursor uint32
   269  	for {
   270  		rpcServ, err := h.natEd.Nat44EdOutputInterfaceGet(context.Background(), &vpp_nat_ed.Nat44EdOutputInterfaceGet{
   271  			Cursor: cursor,
   272  		})
   273  		if err != nil {
   274  			return nil, fmt.Errorf("failed to dump NAT44 interface output feature: %v", err)
   275  		}
   276  	RecvLoop:
   277  		for {
   278  			details, reply, err := rpcServ.Recv()
   279  			if err != nil && err != io.EOF {
   280  				return nil, fmt.Errorf("failed to dump NAT44 interface output feature: %v", err)
   281  			}
   282  			if reply != nil {
   283  				// TODO: Possible bug in VPP? When VPP contains no NAT interfaces this
   284  				// reply often returns cursor value of 0 repeatedly even though it should return
   285  				// ^uint32(0). So if the reply contains cursor that is the same as cursor
   286  				// from previous reply, return.
   287  				if reply.Cursor == cursor || reply.Cursor == ^uint32(0) {
   288  					return natIfs, nil
   289  				}
   290  				cursor = reply.Cursor
   291  				break RecvLoop
   292  			}
   293  			if details != nil {
   294  				ifName, _, found := h.ifIndexes.LookupBySwIfIndex(uint32(details.SwIfIndex))
   295  				if !found {
   296  					h.log.Warnf("Interface with index %d not found in the mapping", details.SwIfIndex)
   297  				}
   298  				natIfs = append(natIfs, &nat.Nat44Interface{
   299  					Name:          ifName,
   300  					OutputFeature: true,
   301  				})
   302  			}
   303  		}
   304  	}
   305  }
   306  
   307  // Nat44InterfacesDump dumps NAT44 config of all NAT44-enabled interfaces.
   308  func (h *NatVppHandler) Nat44InterfacesDump() (natIfs []*nat.Nat44Interface, err error) {
   309  	if h.ed {
   310  		return h.nat44EdInterfacesDump()
   311  	} else {
   312  		return h.nat44EiInterfacesDump()
   313  	}
   314  }
   315  
   316  func (h *NatVppHandler) nat44EiAddressPoolsDump() (natPools []*nat.Nat44AddressPool, err error) {
   317  	var curPool *nat.Nat44AddressPool
   318  	var lastIP net.IP
   319  
   320  	req := &vpp_nat_ei.Nat44EiAddressDump{}
   321  	reqContext := h.callsChannel.SendMultiRequest(req)
   322  
   323  	for {
   324  		msg := &vpp_nat_ei.Nat44EiAddressDetails{}
   325  		stop, err := reqContext.ReceiveReply(msg)
   326  		if err != nil {
   327  			return nil, fmt.Errorf("failed to dump NAT44 Address pool: %v", err)
   328  		}
   329  		if stop {
   330  			break
   331  		}
   332  		ip := net.IP(msg.IPAddress[:])
   333  		// merge subsequent IPs into a single pool
   334  		if curPool != nil && curPool.VrfId == msg.VrfID && ip.Equal(incIP(lastIP)) {
   335  			// update current pool
   336  			curPool.LastIp = ip.String()
   337  		} else {
   338  			// start a new pool
   339  			pool := &nat.Nat44AddressPool{
   340  				FirstIp:  ip.String(),
   341  				VrfId:    msg.VrfID,
   342  				TwiceNat: false,
   343  			}
   344  			curPool = pool
   345  			natPools = append(natPools, pool)
   346  		}
   347  		lastIP = ip
   348  	}
   349  	return
   350  }
   351  
   352  func (h *NatVppHandler) nat44EdAddressPoolsDump() (natPools []*nat.Nat44AddressPool, err error) {
   353  	var curPool *nat.Nat44AddressPool
   354  	var lastIP net.IP
   355  
   356  	req := &vpp_nat_ed.Nat44AddressDump{}
   357  	reqContext := h.callsChannel.SendMultiRequest(req)
   358  
   359  	for {
   360  		msg := &vpp_nat_ed.Nat44AddressDetails{}
   361  		stop, err := reqContext.ReceiveReply(msg)
   362  		if err != nil {
   363  			return nil, fmt.Errorf("failed to dump NAT44 Address pool: %v", err)
   364  		}
   365  		if stop {
   366  			break
   367  		}
   368  		ip := net.IP(msg.IPAddress[:])
   369  		isTwiceNat := getNat44Flags(msg.Flags).isTwiceNat
   370  		// merge subsequent IPs into a single pool
   371  		if curPool != nil && curPool.VrfId == msg.VrfID && curPool.TwiceNat == isTwiceNat && ip.Equal(incIP(lastIP)) {
   372  			// update current pool
   373  			curPool.LastIp = ip.String()
   374  		} else {
   375  			// start a new pool
   376  			pool := &nat.Nat44AddressPool{
   377  				FirstIp:  ip.String(),
   378  				VrfId:    msg.VrfID,
   379  				TwiceNat: isTwiceNat,
   380  			}
   381  			curPool = pool
   382  			natPools = append(natPools, pool)
   383  		}
   384  		lastIP = ip
   385  	}
   386  	return
   387  }
   388  
   389  // Nat44AddressPoolsDump dumps all configured NAT44 address pools.
   390  func (h *NatVppHandler) Nat44AddressPoolsDump() (natPools []*nat.Nat44AddressPool, err error) {
   391  	if h.ed {
   392  		return h.nat44EdAddressPoolsDump()
   393  	} else {
   394  		return h.nat44EiAddressPoolsDump()
   395  	}
   396  }
   397  
   398  func (h *NatVppHandler) nat44EiAddressDump() (addressPool []*nat.Nat44Global_Address, err error) {
   399  	req := &vpp_nat_ei.Nat44EiAddressDump{}
   400  	reqContext := h.callsChannel.SendMultiRequest(req)
   401  
   402  	for {
   403  		msg := &vpp_nat_ei.Nat44EiAddressDetails{}
   404  		stop, err := reqContext.ReceiveReply(msg)
   405  		if err != nil {
   406  			return nil, fmt.Errorf("failed to dump NAT44 Address pool: %v", err)
   407  		}
   408  		if stop {
   409  			break
   410  		}
   411  
   412  		addressPool = append(addressPool, &nat.Nat44Global_Address{
   413  			Address:  net.IP(msg.IPAddress[:]).String(),
   414  			VrfId:    msg.VrfID,
   415  			TwiceNat: false,
   416  		})
   417  	}
   418  
   419  	return
   420  }
   421  
   422  func (h *NatVppHandler) nat44EdAddressDump() (addressPool []*nat.Nat44Global_Address, err error) {
   423  	req := &vpp_nat_ed.Nat44AddressDump{}
   424  	reqContext := h.callsChannel.SendMultiRequest(req)
   425  
   426  	for {
   427  		msg := &vpp_nat_ed.Nat44AddressDetails{}
   428  		stop, err := reqContext.ReceiveReply(msg)
   429  		if err != nil {
   430  			return nil, fmt.Errorf("failed to dump NAT44 Address pool: %v", err)
   431  		}
   432  		if stop {
   433  			break
   434  		}
   435  
   436  		addressPool = append(addressPool, &nat.Nat44Global_Address{
   437  			Address:  net.IP(msg.IPAddress[:]).String(),
   438  			VrfId:    msg.VrfID,
   439  			TwiceNat: getNat44Flags(msg.Flags).isTwiceNat,
   440  		})
   441  	}
   442  
   443  	return
   444  }
   445  
   446  // nat44AddressDump returns NAT44 address pool configured in the VPP.
   447  // Deprecated. Functionality moved to Nat44AddressPoolsDump. Kept for backward compatibility.
   448  func (h *NatVppHandler) nat44AddressDump() (addressPool []*nat.Nat44Global_Address, err error) {
   449  	if h.ed {
   450  		return h.nat44EdAddressDump()
   451  	} else {
   452  		return h.nat44EiAddressDump()
   453  	}
   454  }
   455  
   456  // virtualReassemblyDump returns current NAT virtual-reassembly configuration.
   457  func (h *NatVppHandler) virtualReassemblyDump() (vrIPv4 *nat.VirtualReassembly, vrIPv6 *nat.VirtualReassembly, err error) {
   458  	/*ipv4vr, err := h.ip.IPReassemblyGet(context.TODO(), &vpp_ip.IPReassemblyGet{IsIP6: false})
   459  	if err != nil {
   460  		return nil, nil, fmt.Errorf("getting virtual reassembly IPv4 config failed: %w", err)
   461  	}
   462  	h.log.Debugf("IP Reassembly config IPv4: %+v\n", ipv4vr)
   463  	ipv6vr, err := h.ip.IPReassemblyGet(context.TODO(), &vpp_ip.IPReassemblyGet{IsIP6: true})
   464  	if err != nil {
   465  		return nil, nil, fmt.Errorf("getting virtual reassembly IPv6 config failed: %w", err)
   466  	}
   467  	h.log.Debugf("IP Reassembly config IPv6: %+v\n", ipv6vr)*/
   468  
   469  	// Virtual Reassembly has been removed from NAT API in VPP (moved to IP API)
   470  	// TODO: define IPReassembly model in L3 plugin
   471  	return nil, nil, nil
   472  	/*vrIPv4 = &nat.VirtualReassembly{
   473  		Timeout:         reply.IP4Timeout,
   474  		MaxReassemblies: uint32(reply.IP4MaxReass),
   475  		MaxFragments:    uint32(reply.IP4MaxFrag),
   476  		DropFragments:   uintToBool(reply.IP4DropFrag),
   477  	}
   478  	vrIPv6 = &nat.VirtualReassembly{
   479  		Timeout:         reply.IP6Timeout,
   480  		MaxReassemblies: uint32(reply.IP6MaxReass),
   481  		MaxFragments:    uint32(reply.IP6MaxFrag),
   482  		DropFragments:   uintToBool(reply.IP6DropFrag),
   483  	}
   484  	return*/
   485  }
   486  
   487  func (h *NatVppHandler) nat44EiStaticMappingDump() (entries stMappingMap, err error) {
   488  	entries = make(stMappingMap)
   489  	childMappings := make(stMappingMap)
   490  	req := &vpp_nat_ei.Nat44EiStaticMappingDump{}
   491  	reqContext := h.callsChannel.SendMultiRequest(req)
   492  
   493  	for {
   494  		msg := &vpp_nat_ei.Nat44EiStaticMappingDetails{}
   495  		stop, err := reqContext.ReceiveReply(msg)
   496  		if err != nil {
   497  			return nil, fmt.Errorf("failed to dump NAT44 static mapping: %v", err)
   498  		}
   499  		if stop {
   500  			break
   501  		}
   502  		lcIPAddress := net.IP(msg.LocalIPAddress[:]).String()
   503  		exIPAddress := net.IP(msg.ExternalIPAddress[:]).String()
   504  
   505  		// Parse tag (DNAT label)
   506  		tag := strings.TrimRight(msg.Tag, "\x00")
   507  		if _, hasTag := entries[tag]; !hasTag {
   508  			entries[tag] = []*nat.DNat44_StaticMapping{}
   509  			childMappings[tag] = []*nat.DNat44_StaticMapping{}
   510  		}
   511  
   512  		// resolve interface name
   513  		var (
   514  			found        bool
   515  			extIfaceName string
   516  			extIfaceMeta *ifaceidx.IfaceMetadata
   517  		)
   518  		if msg.ExternalSwIfIndex != NoInterface {
   519  			extIfaceName, extIfaceMeta, found = h.ifIndexes.LookupBySwIfIndex(uint32(msg.ExternalSwIfIndex))
   520  			if !found {
   521  				h.log.Warnf("Interface with index %v not found in the mapping", msg.ExternalSwIfIndex)
   522  				continue
   523  			}
   524  		}
   525  
   526  		// Add mapping into the map.
   527  		mapping := &nat.DNat44_StaticMapping{
   528  			ExternalInterface: extIfaceName,
   529  			ExternalIp:        exIPAddress,
   530  			ExternalPort:      uint32(msg.ExternalPort),
   531  			LocalIps: []*nat.DNat44_StaticMapping_LocalIP{ // single-value
   532  				{
   533  					VrfId:     msg.VrfID,
   534  					LocalIp:   lcIPAddress,
   535  					LocalPort: uint32(msg.LocalPort),
   536  				},
   537  			},
   538  			Protocol: h.protocolNumberToNBValue(msg.Protocol),
   539  			TwiceNat: h.getTwiceNatMode(false, false),
   540  			// if there is only one backend the affinity can not be set
   541  			SessionAffinity: 0,
   542  		}
   543  		entries[tag] = append(entries[tag], mapping)
   544  
   545  		if msg.ExternalSwIfIndex != NoInterface {
   546  			// collect auto-generated "child" mappings (interface replaced with every assigned IP address)
   547  			for _, ipAddr := range h.getInterfaceIPAddresses(extIfaceName, extIfaceMeta) {
   548  				childMapping := proto.Clone(mapping).(*nat.DNat44_StaticMapping)
   549  				childMapping.ExternalIp = ipAddr
   550  				childMapping.ExternalInterface = ""
   551  				childMappings[tag] = append(childMappings[tag], childMapping)
   552  			}
   553  		}
   554  	}
   555  
   556  	// do not dump auto-generated child mappings
   557  	for tag, mappings := range entries {
   558  		var filtered []*nat.DNat44_StaticMapping
   559  		for _, mapping := range mappings {
   560  			isChild := false
   561  			for _, child := range childMappings[tag] {
   562  				if proto.Equal(mapping, child) {
   563  					isChild = true
   564  					break
   565  				}
   566  			}
   567  			if !isChild {
   568  				filtered = append(filtered, mapping)
   569  			}
   570  		}
   571  		entries[tag] = filtered
   572  	}
   573  	return entries, nil
   574  }
   575  
   576  func (h *NatVppHandler) nat44EdStaticMappingDump() (entries stMappingMap, err error) {
   577  	entries = make(stMappingMap)
   578  	childMappings := make(stMappingMap)
   579  	req := &vpp_nat_ed.Nat44StaticMappingDump{}
   580  	reqContext := h.callsChannel.SendMultiRequest(req)
   581  
   582  	for {
   583  		msg := &vpp_nat_ed.Nat44StaticMappingDetails{}
   584  		stop, err := reqContext.ReceiveReply(msg)
   585  		if err != nil {
   586  			return nil, fmt.Errorf("failed to dump NAT44 static mapping: %v", err)
   587  		}
   588  		if stop {
   589  			break
   590  		}
   591  		lcIPAddress := net.IP(msg.LocalIPAddress[:]).String()
   592  		exIPAddress := net.IP(msg.ExternalIPAddress[:]).String()
   593  
   594  		// Parse tag (DNAT label)
   595  		tag := strings.TrimRight(msg.Tag, "\x00")
   596  		if _, hasTag := entries[tag]; !hasTag {
   597  			entries[tag] = []*nat.DNat44_StaticMapping{}
   598  			childMappings[tag] = []*nat.DNat44_StaticMapping{}
   599  		}
   600  
   601  		// resolve interface name
   602  		var (
   603  			found        bool
   604  			extIfaceName string
   605  			extIfaceMeta *ifaceidx.IfaceMetadata
   606  		)
   607  		if msg.ExternalSwIfIndex != NoInterface {
   608  			extIfaceName, extIfaceMeta, found = h.ifIndexes.LookupBySwIfIndex(uint32(msg.ExternalSwIfIndex))
   609  			if !found {
   610  				h.log.Warnf("Interface with index %v not found in the mapping", msg.ExternalSwIfIndex)
   611  				continue
   612  			}
   613  		}
   614  
   615  		flags := getNat44Flags(msg.Flags)
   616  
   617  		// Add mapping into the map.
   618  		mapping := &nat.DNat44_StaticMapping{
   619  			ExternalInterface: extIfaceName,
   620  			ExternalIp:        exIPAddress,
   621  			ExternalPort:      uint32(msg.ExternalPort),
   622  			LocalIps: []*nat.DNat44_StaticMapping_LocalIP{ // single-value
   623  				{
   624  					VrfId:     msg.VrfID,
   625  					LocalIp:   lcIPAddress,
   626  					LocalPort: uint32(msg.LocalPort),
   627  				},
   628  			},
   629  			Protocol: h.protocolNumberToNBValue(msg.Protocol),
   630  			TwiceNat: h.getTwiceNatMode(flags.isTwiceNat, flags.isSelfTwiceNat),
   631  			// if there is only one backend the affinity can not be set
   632  			SessionAffinity: 0,
   633  		}
   634  		entries[tag] = append(entries[tag], mapping)
   635  
   636  		if msg.ExternalSwIfIndex != NoInterface {
   637  			// collect auto-generated "child" mappings (interface replaced with every assigned IP address)
   638  			for _, ipAddr := range h.getInterfaceIPAddresses(extIfaceName, extIfaceMeta) {
   639  				childMapping := proto.Clone(mapping).(*nat.DNat44_StaticMapping)
   640  				childMapping.ExternalIp = ipAddr
   641  				childMapping.ExternalInterface = ""
   642  				childMappings[tag] = append(childMappings[tag], childMapping)
   643  			}
   644  		}
   645  	}
   646  
   647  	// do not dump auto-generated child mappings
   648  	for tag, mappings := range entries {
   649  		var filtered []*nat.DNat44_StaticMapping
   650  		for _, mapping := range mappings {
   651  			isChild := false
   652  			for _, child := range childMappings[tag] {
   653  				if proto.Equal(mapping, child) {
   654  					isChild = true
   655  					break
   656  				}
   657  			}
   658  			if !isChild {
   659  				filtered = append(filtered, mapping)
   660  			}
   661  		}
   662  		entries[tag] = filtered
   663  	}
   664  	return entries, nil
   665  }
   666  
   667  // nat44StaticMappingDump returns a map of NAT44 static mappings sorted by tags
   668  func (h *NatVppHandler) nat44StaticMappingDump() (entries stMappingMap, err error) {
   669  	if h.ed {
   670  		return h.nat44EdStaticMappingDump()
   671  	} else {
   672  		return h.nat44EiStaticMappingDump()
   673  	}
   674  }
   675  
   676  func (h *NatVppHandler) nat44EiStaticMappingLbDump() (entries stMappingMap, err error) {
   677  	return make(stMappingMap), nil
   678  }
   679  
   680  func (h *NatVppHandler) nat44EdStaticMappingLbDump() (entries stMappingMap, err error) {
   681  	entries = make(stMappingMap)
   682  	req := &vpp_nat_ed.Nat44LbStaticMappingDump{}
   683  	reqContext := h.callsChannel.SendMultiRequest(req)
   684  
   685  	for {
   686  		msg := &vpp_nat_ed.Nat44LbStaticMappingDetails{}
   687  		stop, err := reqContext.ReceiveReply(msg)
   688  		if err != nil {
   689  			return nil, fmt.Errorf("failed to dump NAT44 lb-static mapping: %v", err)
   690  		}
   691  		if stop {
   692  			break
   693  		}
   694  
   695  		// Parse tag (DNAT label)
   696  		tag := strings.TrimRight(msg.Tag, "\x00")
   697  		if _, hasTag := entries[tag]; !hasTag {
   698  			entries[tag] = []*nat.DNat44_StaticMapping{}
   699  		}
   700  
   701  		// Prepare localIPs
   702  		var locals []*nat.DNat44_StaticMapping_LocalIP
   703  		for _, localIPVal := range msg.Locals {
   704  			locals = append(locals, &nat.DNat44_StaticMapping_LocalIP{
   705  				VrfId:       localIPVal.VrfID,
   706  				LocalIp:     net.IP(localIPVal.Addr[:]).String(),
   707  				LocalPort:   uint32(localIPVal.Port),
   708  				Probability: uint32(localIPVal.Probability),
   709  			})
   710  		}
   711  		exIPAddress := net.IP(msg.ExternalAddr[:]).String()
   712  
   713  		flags := getNat44Flags(msg.Flags)
   714  
   715  		// Add mapping into the map.
   716  		mapping := &nat.DNat44_StaticMapping{
   717  			ExternalIp:      exIPAddress,
   718  			ExternalPort:    uint32(msg.ExternalPort),
   719  			LocalIps:        locals,
   720  			Protocol:        h.protocolNumberToNBValue(msg.Protocol),
   721  			TwiceNat:        h.getTwiceNatMode(flags.isTwiceNat, flags.isSelfTwiceNat),
   722  			SessionAffinity: msg.Affinity,
   723  		}
   724  		entries[tag] = append(entries[tag], mapping)
   725  	}
   726  
   727  	return entries, nil
   728  }
   729  
   730  // nat44StaticMappingLbDump returns a map of NAT44 static mapping with load balancing sorted by tags.
   731  func (h *NatVppHandler) nat44StaticMappingLbDump() (entries stMappingMap, err error) {
   732  	if h.ed {
   733  		return h.nat44EdStaticMappingLbDump()
   734  	} else {
   735  		return h.nat44EiStaticMappingLbDump()
   736  	}
   737  }
   738  
   739  func (h *NatVppHandler) nat44EiIdentityMappingDump() (entries idMappingMap, err error) {
   740  	entries = make(idMappingMap)
   741  	childMappings := make(idMappingMap)
   742  	req := &vpp_nat_ei.Nat44EiIdentityMappingDump{}
   743  	reqContext := h.callsChannel.SendMultiRequest(req)
   744  
   745  	for {
   746  		msg := &vpp_nat_ei.Nat44EiIdentityMappingDetails{}
   747  		stop, err := reqContext.ReceiveReply(msg)
   748  		if err != nil {
   749  			return nil, fmt.Errorf("failed to dump NAT44 identity mapping: %v", err)
   750  		}
   751  		if stop {
   752  			break
   753  		}
   754  
   755  		// Parse tag (DNAT label)
   756  		tag := strings.TrimRight(msg.Tag, "\x00")
   757  		if _, hasTag := entries[tag]; !hasTag {
   758  			entries[tag] = []*nat.DNat44_IdentityMapping{}
   759  			childMappings[tag] = []*nat.DNat44_IdentityMapping{}
   760  		}
   761  
   762  		// resolve interface name
   763  		var (
   764  			found     bool
   765  			ifaceName string
   766  			ifaceMeta *ifaceidx.IfaceMetadata
   767  		)
   768  		if msg.SwIfIndex != NoInterface {
   769  			ifaceName, ifaceMeta, found = h.ifIndexes.LookupBySwIfIndex(uint32(msg.SwIfIndex))
   770  			if !found {
   771  				h.log.Warnf("Interface with index %v not found in the mapping", msg.SwIfIndex)
   772  				continue
   773  			}
   774  		}
   775  
   776  		// Add mapping into the map.
   777  		mapping := &nat.DNat44_IdentityMapping{
   778  			IpAddress: net.IP(msg.IPAddress[:]).String(),
   779  			VrfId:     msg.VrfID,
   780  			Interface: ifaceName,
   781  			Port:      uint32(msg.Port),
   782  			Protocol:  h.protocolNumberToNBValue(msg.Protocol),
   783  		}
   784  		entries[tag] = append(entries[tag], mapping)
   785  
   786  		if msg.SwIfIndex != NoInterface {
   787  			// collect auto-generated "child" mappings (interface replaced with every assigned IP address)
   788  			for _, ipAddr := range h.getInterfaceIPAddresses(ifaceName, ifaceMeta) {
   789  				childMapping := proto.Clone(mapping).(*nat.DNat44_IdentityMapping)
   790  				childMapping.IpAddress = ipAddr
   791  				childMapping.Interface = ""
   792  				childMappings[tag] = append(childMappings[tag], childMapping)
   793  			}
   794  		}
   795  	}
   796  
   797  	// do not dump auto-generated child mappings
   798  	for tag, mappings := range entries {
   799  		var filtered []*nat.DNat44_IdentityMapping
   800  		for _, mapping := range mappings {
   801  			isChild := false
   802  			for _, child := range childMappings[tag] {
   803  				if proto.Equal(mapping, child) {
   804  					isChild = true
   805  					break
   806  				}
   807  			}
   808  			if !isChild {
   809  				filtered = append(filtered, mapping)
   810  			}
   811  		}
   812  		entries[tag] = filtered
   813  	}
   814  
   815  	return entries, nil
   816  }
   817  
   818  func (h *NatVppHandler) nat44EdIdentityMappingDump() (entries idMappingMap, err error) {
   819  	entries = make(idMappingMap)
   820  	childMappings := make(idMappingMap)
   821  	req := &vpp_nat_ed.Nat44IdentityMappingDump{}
   822  	reqContext := h.callsChannel.SendMultiRequest(req)
   823  
   824  	for {
   825  		msg := &vpp_nat_ed.Nat44IdentityMappingDetails{}
   826  		stop, err := reqContext.ReceiveReply(msg)
   827  		if err != nil {
   828  			return nil, fmt.Errorf("failed to dump NAT44 identity mapping: %v", err)
   829  		}
   830  		if stop {
   831  			break
   832  		}
   833  
   834  		// Parse tag (DNAT label)
   835  		tag := strings.TrimRight(msg.Tag, "\x00")
   836  		if _, hasTag := entries[tag]; !hasTag {
   837  			entries[tag] = []*nat.DNat44_IdentityMapping{}
   838  			childMappings[tag] = []*nat.DNat44_IdentityMapping{}
   839  		}
   840  
   841  		// resolve interface name
   842  		var (
   843  			found     bool
   844  			ifaceName string
   845  			ifaceMeta *ifaceidx.IfaceMetadata
   846  		)
   847  		if msg.SwIfIndex != NoInterface {
   848  			ifaceName, ifaceMeta, found = h.ifIndexes.LookupBySwIfIndex(uint32(msg.SwIfIndex))
   849  			if !found {
   850  				h.log.Warnf("Interface with index %v not found in the mapping", msg.SwIfIndex)
   851  				continue
   852  			}
   853  		}
   854  
   855  		// Add mapping into the map.
   856  		mapping := &nat.DNat44_IdentityMapping{
   857  			IpAddress: net.IP(msg.IPAddress[:]).String(),
   858  			VrfId:     msg.VrfID,
   859  			Interface: ifaceName,
   860  			Port:      uint32(msg.Port),
   861  			Protocol:  h.protocolNumberToNBValue(msg.Protocol),
   862  		}
   863  		entries[tag] = append(entries[tag], mapping)
   864  
   865  		if msg.SwIfIndex != NoInterface {
   866  			// collect auto-generated "child" mappings (interface replaced with every assigned IP address)
   867  			for _, ipAddr := range h.getInterfaceIPAddresses(ifaceName, ifaceMeta) {
   868  				childMapping := proto.Clone(mapping).(*nat.DNat44_IdentityMapping)
   869  				childMapping.IpAddress = ipAddr
   870  				childMapping.Interface = ""
   871  				childMappings[tag] = append(childMappings[tag], childMapping)
   872  			}
   873  		}
   874  	}
   875  
   876  	// do not dump auto-generated child mappings
   877  	for tag, mappings := range entries {
   878  		var filtered []*nat.DNat44_IdentityMapping
   879  		for _, mapping := range mappings {
   880  			isChild := false
   881  			for _, child := range childMappings[tag] {
   882  				if proto.Equal(mapping, child) {
   883  					isChild = true
   884  					break
   885  				}
   886  			}
   887  			if !isChild {
   888  				filtered = append(filtered, mapping)
   889  			}
   890  		}
   891  		entries[tag] = filtered
   892  	}
   893  
   894  	return entries, nil
   895  }
   896  
   897  // nat44IdentityMappingDump returns a map of NAT44 identity mappings sorted by tags.
   898  func (h *NatVppHandler) nat44IdentityMappingDump() (entries idMappingMap, err error) {
   899  	if h.ed {
   900  		return h.nat44EdIdentityMappingDump()
   901  	} else {
   902  		return h.nat44EiIdentityMappingDump()
   903  	}
   904  }
   905  
   906  func (h *NatVppHandler) nat44EiInterfaceDump() ([]*nat.Nat44Global_Interface, error) {
   907  	var natIfs []*nat.Nat44Global_Interface
   908  
   909  	// dump non-output NAT interfaces
   910  	req1 := &vpp_nat_ei.Nat44EiInterfaceDump{}
   911  	reqContext := h.callsChannel.SendMultiRequest(req1)
   912  
   913  	for {
   914  		msg := &vpp_nat_ei.Nat44EiInterfaceDetails{}
   915  		stop, err := reqContext.ReceiveReply(msg)
   916  		if err != nil {
   917  			return nil, fmt.Errorf("failed to dump NAT44 interface: %v", err)
   918  		}
   919  		if stop {
   920  			break
   921  		}
   922  
   923  		// Find interface name
   924  		ifName, _, found := h.ifIndexes.LookupBySwIfIndex(uint32(msg.SwIfIndex))
   925  		if !found {
   926  			h.log.Warnf("Interface with index %d not found in the mapping", msg.SwIfIndex)
   927  			continue
   928  		}
   929  
   930  		flags := getNat44EiFlags(msg.Flags)
   931  
   932  		if flags.eiIfInside {
   933  			natIfs = append(natIfs, &nat.Nat44Global_Interface{
   934  				Name:     ifName,
   935  				IsInside: true,
   936  			})
   937  		} else {
   938  			natIfs = append(natIfs, &nat.Nat44Global_Interface{
   939  				Name:     ifName,
   940  				IsInside: false,
   941  			})
   942  		}
   943  	}
   944  
   945  	// dump output NAT interfaces
   946  	var cursor uint32
   947  	for {
   948  		rpcServ, err := h.natEi.Nat44EiOutputInterfaceGet(context.Background(), &vpp_nat_ei.Nat44EiOutputInterfaceGet{
   949  			Cursor: cursor,
   950  		})
   951  		if err != nil {
   952  			return nil, fmt.Errorf("failed to dump NAT44 interface output feature: %v", err)
   953  		}
   954  	RecvLoop:
   955  		for {
   956  			details, reply, err := rpcServ.Recv()
   957  			if err != nil && err != io.EOF {
   958  				return nil, fmt.Errorf("failed to dump NAT44 interface output feature: %v", err)
   959  			}
   960  			if reply != nil {
   961  				// TODO: Possible bug in VPP? When VPP contains no NAT interfaces this
   962  				// reply often returns cursor value of 0 repeatedly even though it should return
   963  				// ^uint32(0). So if the reply contains cursor that is the same as cursor
   964  				// from previous reply, return.
   965  				if reply.Cursor == cursor || reply.Cursor == ^uint32(0) {
   966  					return natIfs, nil
   967  				}
   968  				cursor = reply.Cursor
   969  				break RecvLoop
   970  			}
   971  			if details != nil {
   972  				ifName, _, found := h.ifIndexes.LookupBySwIfIndex(uint32(details.SwIfIndex))
   973  				if !found {
   974  					h.log.Warnf("Interface with index %d not found in the mapping", details.SwIfIndex)
   975  				}
   976  				natIfs = append(natIfs, &nat.Nat44Global_Interface{
   977  					Name:          ifName,
   978  					OutputFeature: true,
   979  				})
   980  			}
   981  		}
   982  	}
   983  }
   984  
   985  func (h *NatVppHandler) nat44EdInterfaceDump() ([]*nat.Nat44Global_Interface, error) {
   986  	var natIfs []*nat.Nat44Global_Interface
   987  
   988  	// dump non-output NAT interfaces
   989  	req1 := &vpp_nat_ed.Nat44InterfaceDump{}
   990  	reqContext := h.callsChannel.SendMultiRequest(req1)
   991  
   992  	for {
   993  		msg := &vpp_nat_ed.Nat44InterfaceDetails{}
   994  		stop, err := reqContext.ReceiveReply(msg)
   995  		if err != nil {
   996  			return nil, fmt.Errorf("failed to dump NAT44 interface: %v", err)
   997  		}
   998  		if stop {
   999  			break
  1000  		}
  1001  
  1002  		// Find interface name
  1003  		ifName, _, found := h.ifIndexes.LookupBySwIfIndex(uint32(msg.SwIfIndex))
  1004  		if !found {
  1005  			h.log.Warnf("Interface with index %d not found in the mapping", msg.SwIfIndex)
  1006  			continue
  1007  		}
  1008  
  1009  		flags := getNat44Flags(msg.Flags)
  1010  
  1011  		if flags.isInside {
  1012  			natIfs = append(natIfs, &nat.Nat44Global_Interface{
  1013  				Name:     ifName,
  1014  				IsInside: true,
  1015  			})
  1016  		} else {
  1017  			natIfs = append(natIfs, &nat.Nat44Global_Interface{
  1018  				Name:     ifName,
  1019  				IsInside: false,
  1020  			})
  1021  		}
  1022  	}
  1023  
  1024  	// dump output NAT interfaces
  1025  	var cursor uint32
  1026  	for {
  1027  		rpcServ, err := h.natEd.Nat44EdOutputInterfaceGet(context.Background(), &vpp_nat_ed.Nat44EdOutputInterfaceGet{
  1028  			Cursor: cursor,
  1029  		})
  1030  		if err != nil {
  1031  			return nil, fmt.Errorf("failed to dump NAT44 interface output feature: %v", err)
  1032  		}
  1033  	RecvLoop:
  1034  		for {
  1035  			details, reply, err := rpcServ.Recv()
  1036  			if err != nil && err != io.EOF {
  1037  				return nil, fmt.Errorf("failed to dump NAT44 interface output feature: %v", err)
  1038  			}
  1039  			if reply != nil {
  1040  				// TODO: Possible bug in VPP? When VPP contains no NAT interfaces this
  1041  				// reply often returns cursor value of 0 repeatedly even though it should return
  1042  				// ^uint32(0). So if the reply contains cursor that is the same as cursor
  1043  				// from previous reply, return.
  1044  				if reply.Cursor == cursor || reply.Cursor == ^uint32(0) {
  1045  					return natIfs, nil
  1046  				}
  1047  				cursor = reply.Cursor
  1048  				break RecvLoop
  1049  			}
  1050  			if details != nil {
  1051  				ifName, _, found := h.ifIndexes.LookupBySwIfIndex(uint32(details.SwIfIndex))
  1052  				if !found {
  1053  					h.log.Warnf("Interface with index %d not found in the mapping", details.SwIfIndex)
  1054  				}
  1055  				natIfs = append(natIfs, &nat.Nat44Global_Interface{
  1056  					Name:          ifName,
  1057  					OutputFeature: true,
  1058  				})
  1059  			}
  1060  		}
  1061  	}
  1062  }
  1063  
  1064  // nat44InterfaceDump dumps NAT44 interface features.
  1065  // Deprecated. Functionality moved to Nat44Nat44InterfacesDump. Kept for backward compatibility.
  1066  func (h *NatVppHandler) nat44InterfaceDump() ([]*nat.Nat44Global_Interface, error) {
  1067  	if h.ed {
  1068  		return h.nat44EdInterfaceDump()
  1069  	} else {
  1070  		return h.nat44EiInterfaceDump()
  1071  	}
  1072  }
  1073  
  1074  func (h *NatVppHandler) getInterfaceIPAddresses(ifaceName string, ifaceMeta *ifaceidx.IfaceMetadata) (ipAddrs []string) {
  1075  	ipAddrNets := ifaceMeta.IPAddresses
  1076  	dhcpLease, hasDHCPLease := h.dhcpIndex.GetValue(ifaceName)
  1077  	if hasDHCPLease {
  1078  		lease := dhcpLease.(*ifs.DHCPLease)
  1079  		ipAddrNets = append(ipAddrNets, lease.HostIpAddress)
  1080  	}
  1081  	for _, ipAddrNet := range ipAddrNets {
  1082  		ipAddr := strings.Split(ipAddrNet, "/")[0]
  1083  		ipAddrs = append(ipAddrs, ipAddr)
  1084  	}
  1085  	return ipAddrs
  1086  }
  1087  
  1088  // protocolNumberToNBValue converts protocol numeric representation into the corresponding enum
  1089  // enum value from the NB model.
  1090  func (h *NatVppHandler) protocolNumberToNBValue(protocol uint8) (proto nat.DNat44_Protocol) {
  1091  	switch protocol {
  1092  	case TCP:
  1093  		return nat.DNat44_TCP
  1094  	case UDP:
  1095  		return nat.DNat44_UDP
  1096  	case ICMP:
  1097  		return nat.DNat44_ICMP
  1098  	default:
  1099  		h.log.Warnf("Unknown protocol %v", protocol)
  1100  		return 0
  1101  	}
  1102  }
  1103  
  1104  // protocolNBValueToNumber converts protocol enum value from the NB model into the
  1105  // corresponding numeric representation.
  1106  func (h *NatVppHandler) protocolNBValueToNumber(protocol nat.DNat44_Protocol) (proto uint8) {
  1107  	switch protocol {
  1108  	case nat.DNat44_TCP:
  1109  		return TCP
  1110  	case nat.DNat44_UDP:
  1111  		return UDP
  1112  	case nat.DNat44_ICMP:
  1113  		return ICMP
  1114  	default:
  1115  		h.log.Warnf("Unknown protocol %v, defaulting to TCP", protocol)
  1116  		return TCP
  1117  	}
  1118  }
  1119  
  1120  func (h *NatVppHandler) getTwiceNatMode(twiceNat, selfTwiceNat bool) nat.DNat44_StaticMapping_TwiceNatMode {
  1121  	if twiceNat {
  1122  		if selfTwiceNat {
  1123  			h.log.Warnf("Both TwiceNAT and self-TwiceNAT are enabled")
  1124  			return 0
  1125  		}
  1126  		return nat.DNat44_StaticMapping_ENABLED
  1127  	}
  1128  	if selfTwiceNat {
  1129  		return nat.DNat44_StaticMapping_SELF
  1130  	}
  1131  	return nat.DNat44_StaticMapping_DISABLED
  1132  }
  1133  
  1134  func getOrCreateDNAT(dnats dnatMap, label string) *nat.DNat44 {
  1135  	if _, created := dnats[label]; !created {
  1136  		dnats[label] = &nat.DNat44{Label: label}
  1137  	}
  1138  	return dnats[label]
  1139  }
  1140  
  1141  func getNat44Flags(flags nat_types.NatConfigFlags) *nat44EdFlags {
  1142  	natFlags := &nat44EdFlags{}
  1143  	if flags&nat_types.NAT_IS_EXT_HOST_VALID != 0 {
  1144  		natFlags.isExtHostValid = true
  1145  	}
  1146  	if flags&nat_types.NAT_IS_STATIC != 0 {
  1147  		natFlags.isStatic = true
  1148  	}
  1149  	if flags&nat_types.NAT_IS_INSIDE != 0 {
  1150  		natFlags.isInside = true
  1151  	}
  1152  	if flags&nat_types.NAT_IS_OUTSIDE != 0 {
  1153  		natFlags.isOutside = true
  1154  	}
  1155  	if flags&nat_types.NAT_IS_ADDR_ONLY != 0 {
  1156  		natFlags.isAddrOnly = true
  1157  	}
  1158  	if flags&nat_types.NAT_IS_OUT2IN_ONLY != 0 {
  1159  		natFlags.isOut2In = true
  1160  	}
  1161  	if flags&nat_types.NAT_IS_SELF_TWICE_NAT != 0 {
  1162  		natFlags.isSelfTwiceNat = true
  1163  	}
  1164  	if flags&nat_types.NAT_IS_TWICE_NAT != 0 {
  1165  		natFlags.isTwiceNat = true
  1166  	}
  1167  	return natFlags
  1168  }
  1169  
  1170  func getNat44EiFlags(flags vpp_nat_ei.Nat44EiConfigFlags) *nat44EiFlags {
  1171  	natFlags := &nat44EiFlags{}
  1172  	if flags&vpp_nat_ei.NAT44_EI_STATIC_MAPPING_ONLY != 0 {
  1173  		natFlags.eiStaticMappingOnly = true
  1174  	}
  1175  	if flags&vpp_nat_ei.NAT44_EI_CONNECTION_TRACKING != 0 {
  1176  		natFlags.eiConnectionTracking = true
  1177  	}
  1178  	if flags&vpp_nat_ei.NAT44_EI_OUT2IN_DPO != 0 {
  1179  		natFlags.eiOut2InDpo = true
  1180  	}
  1181  	if flags&vpp_nat_ei.NAT44_EI_ADDR_ONLY_MAPPING != 0 {
  1182  		natFlags.eiAddrOnlyMapping = true
  1183  	}
  1184  	if flags&vpp_nat_ei.NAT44_EI_IF_INSIDE != 0 {
  1185  		natFlags.eiIfInside = true
  1186  	}
  1187  	if flags&vpp_nat_ei.NAT44_EI_IF_OUTSIDE != 0 {
  1188  		natFlags.eiIfOutside = true
  1189  	}
  1190  	if flags&vpp_nat_ei.NAT44_EI_STATIC_MAPPING != 0 {
  1191  		natFlags.eiStaticMapping = true
  1192  	}
  1193  	return natFlags
  1194  }
  1195  
  1196  // incIP increments IP address and returns it.
  1197  // Based on: https://play.golang.org/p/m8TNTtygK0
  1198  func incIP(ip net.IP) net.IP {
  1199  	retIP := make(net.IP, len(ip))
  1200  	copy(retIP, ip)
  1201  	for j := len(retIP) - 1; j >= 0; j-- {
  1202  		retIP[j]++
  1203  		if retIP[j] > 0 {
  1204  			break
  1205  		}
  1206  	}
  1207  	return retIP
  1208  }