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 }