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