github.com/cilium/cilium@v1.16.2/pkg/maps/ipmasq/ipmasq.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package ipmasq
     5  
     6  import (
     7  	"net"
     8  	"sync"
     9  
    10  	"github.com/cilium/cilium/pkg/bpf"
    11  	"github.com/cilium/cilium/pkg/ebpf"
    12  	"github.com/cilium/cilium/pkg/ip"
    13  	"github.com/cilium/cilium/pkg/option"
    14  	"github.com/cilium/cilium/pkg/types"
    15  )
    16  
    17  const (
    18  	MapNameIPv4    = "cilium_ipmasq_v4"
    19  	MaxEntriesIPv4 = 16384
    20  	MapNameIPv6    = "cilium_ipmasq_v6"
    21  	MaxEntriesIPv6 = 16384
    22  )
    23  
    24  type Key4 struct {
    25  	PrefixLen uint32
    26  	Address   types.IPv4
    27  }
    28  
    29  func (k *Key4) String() string  { return k.Address.String() }
    30  func (k *Key4) New() bpf.MapKey { return &Key4{} }
    31  
    32  type Key6 struct {
    33  	PrefixLen uint32
    34  	Address   types.IPv6
    35  }
    36  
    37  func (k *Key6) String() string  { return k.Address.String() }
    38  func (k *Key6) New() bpf.MapKey { return &Key6{} }
    39  
    40  type Value struct {
    41  	Pad uint8 // not used
    42  }
    43  
    44  func (v *Value) String() string    { return "" }
    45  func (v *Value) New() bpf.MapValue { return &Value{} }
    46  
    47  var (
    48  	ipMasq4Map *bpf.Map
    49  	onceIPv4   sync.Once
    50  	ipMasq6Map *bpf.Map
    51  	onceIPv6   sync.Once
    52  )
    53  
    54  func IPMasq4Map() *bpf.Map {
    55  	onceIPv4.Do(func() {
    56  		ipMasq4Map = bpf.NewMap(
    57  			MapNameIPv4,
    58  			ebpf.LPMTrie,
    59  			&Key4{},
    60  			&Value{},
    61  			MaxEntriesIPv4,
    62  			bpf.BPF_F_NO_PREALLOC,
    63  		).WithCache().WithPressureMetric().
    64  			WithEvents(option.Config.GetEventBufferConfig(MapNameIPv4))
    65  	})
    66  	return ipMasq4Map
    67  }
    68  
    69  func IPMasq6Map() *bpf.Map {
    70  	onceIPv6.Do(func() {
    71  		ipMasq6Map = bpf.NewMap(
    72  			MapNameIPv6,
    73  			ebpf.LPMTrie,
    74  			&Key6{},
    75  			&Value{},
    76  			MaxEntriesIPv6,
    77  			bpf.BPF_F_NO_PREALLOC,
    78  		).WithCache().WithPressureMetric().
    79  			WithEvents(option.Config.GetEventBufferConfig(MapNameIPv6))
    80  	})
    81  	return ipMasq6Map
    82  }
    83  
    84  type IPMasqBPFMap struct{}
    85  
    86  func (*IPMasqBPFMap) Update(cidr net.IPNet) error {
    87  	if ip.IsIPv4(cidr.IP) {
    88  		if option.Config.EnableIPv4Masquerade {
    89  			return IPMasq4Map().Update(keyIPv4(cidr), &Value{})
    90  		}
    91  	} else {
    92  		if option.Config.EnableIPv6Masquerade {
    93  			return IPMasq6Map().Update(keyIPv6(cidr), &Value{})
    94  		}
    95  	}
    96  	return nil
    97  }
    98  
    99  func (*IPMasqBPFMap) Delete(cidr net.IPNet) error {
   100  	if ip.IsIPv4(cidr.IP) {
   101  		if option.Config.EnableIPv4Masquerade {
   102  			return IPMasq4Map().Delete(keyIPv4(cidr))
   103  		}
   104  	} else {
   105  		if option.Config.EnableIPv6Masquerade {
   106  			return IPMasq6Map().Delete(keyIPv6(cidr))
   107  		}
   108  	}
   109  	return nil
   110  }
   111  
   112  // DumpForProtocols dumps the contents of the ip-masq-agent maps for IPv4
   113  // and/or IPv6, as requested by the caller.
   114  // Given that the package does not expose the maps directly, it's necessary to
   115  // specify which protocol we need when ipMasq4Map/ipMasq6Map, or config
   116  // options, have not been set, as is the case when calling from the CLI, for
   117  // example.
   118  func (*IPMasqBPFMap) DumpForProtocols(ipv4Needed, ipv6Needed bool) ([]net.IPNet, error) {
   119  	cidrs := []net.IPNet{}
   120  	if ipv4Needed {
   121  		if err := IPMasq4Map().DumpWithCallback(
   122  			func(keyIPv4 bpf.MapKey, _ bpf.MapValue) {
   123  				cidrs = append(cidrs, keyToIPNetIPv4(keyIPv4.(*Key4)))
   124  			}); err != nil {
   125  			return nil, err
   126  		}
   127  	}
   128  	if ipv6Needed {
   129  		if err := IPMasq6Map().DumpWithCallback(
   130  			func(keyIPv6 bpf.MapKey, _ bpf.MapValue) {
   131  				cidrs = append(cidrs, keyToIPNetIPv6(keyIPv6.(*Key6)))
   132  			}); err != nil {
   133  			return nil, err
   134  		}
   135  	}
   136  	return cidrs, nil
   137  }
   138  
   139  // Dump dumps the contents of the ip-masq-agent maps for IPv4 and/or IPv6, as
   140  // required based on configuration options.
   141  func (*IPMasqBPFMap) Dump() ([]net.IPNet, error) {
   142  	return (&IPMasqBPFMap{}).DumpForProtocols(option.Config.EnableIPv4Masquerade, option.Config.EnableIPv6Masquerade)
   143  }
   144  
   145  func keyIPv4(cidr net.IPNet) *Key4 {
   146  	ones, _ := cidr.Mask.Size()
   147  	key := &Key4{PrefixLen: uint32(ones)}
   148  	copy(key.Address[:], cidr.IP.To4())
   149  	return key
   150  }
   151  
   152  func keyToIPNetIPv4(key *Key4) net.IPNet {
   153  	var (
   154  		cidr net.IPNet
   155  		ip   types.IPv4
   156  	)
   157  
   158  	cidr.Mask = net.CIDRMask(int(key.PrefixLen), 32)
   159  	key.Address.DeepCopyInto(&ip)
   160  	cidr.IP = ip.IP()
   161  
   162  	return cidr
   163  }
   164  
   165  func keyIPv6(cidr net.IPNet) *Key6 {
   166  	ones, _ := cidr.Mask.Size()
   167  	key := &Key6{PrefixLen: uint32(ones)}
   168  	copy(key.Address[:], cidr.IP.To16())
   169  	return key
   170  }
   171  
   172  func keyToIPNetIPv6(key *Key6) net.IPNet {
   173  	var (
   174  		cidr net.IPNet
   175  		ip   types.IPv6
   176  	)
   177  
   178  	cidr.Mask = net.CIDRMask(int(key.PrefixLen), 128)
   179  	key.Address.DeepCopyInto(&ip)
   180  	cidr.IP = ip.IP()
   181  
   182  	return cidr
   183  }