github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/maps/nat/nat.go (about) 1 // Copyright 2019 Authors of Cilium 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 nat 16 17 import ( 18 "bytes" 19 "fmt" 20 "unsafe" 21 22 "github.com/cilium/cilium/pkg/bpf" 23 "github.com/cilium/cilium/pkg/logging" 24 "github.com/cilium/cilium/pkg/logging/logfields" 25 "github.com/cilium/cilium/pkg/option" 26 "github.com/cilium/cilium/pkg/tuple" 27 ) 28 29 var ( 30 log = logging.DefaultLogger.WithField(logfields.LogSubsys, "map-nat") 31 ) 32 33 const ( 34 // MapNameSnat4Global represents global IPv4 NAT table. 35 MapNameSnat4Global = "cilium_snat_v4_external" 36 // MapNameSnat6Global represents global IPv6 NAT table. 37 MapNameSnat6Global = "cilium_snat_v6_external" 38 39 // MinPortSnatDefault represents default min port from range. 40 MinPortSnatDefault = 1024 41 // MaxPortSnatDefault represents default max port from range. 42 MaxPortSnatDefault = 65535 43 44 mapCount = 2 45 ) 46 47 // Map represents a NAT map. 48 type Map struct { 49 bpf.Map 50 v4 bool 51 } 52 53 // NatEntry is the interface describing values to the NAT map. 54 type NatEntry interface { 55 bpf.MapValue 56 57 // ToHost converts fields to host byte order. 58 ToHost() NatEntry 59 60 // Dumps the Nat entry as string. 61 Dump(key NatKey, start uint64) string 62 } 63 64 // NatDumpCreated returns time in seconds when NAT entry was created. 65 func NatDumpCreated(dumpStart, entryCreated uint64) string { 66 tsecCreated := entryCreated / 1000000000 67 tsecStart := dumpStart / 1000000000 68 69 return fmt.Sprintf("%dsec", tsecStart-tsecCreated) 70 } 71 72 // NewMap instantiates a Map. 73 func NewMap(name string, v4 bool, entries int) *Map { 74 var sizeKey, sizeVal int 75 var mapKey bpf.MapKey 76 var mapValue bpf.MapValue 77 78 if v4 { 79 mapKey = &NatKey4{} 80 sizeKey = int(unsafe.Sizeof(NatKey4{})) 81 mapValue = &NatEntry4{} 82 sizeVal = int(unsafe.Sizeof(NatEntry4{})) 83 } else { 84 mapKey = &NatKey6{} 85 sizeKey = int(unsafe.Sizeof(NatKey6{})) 86 mapValue = &NatEntry6{} 87 sizeVal = int(unsafe.Sizeof(NatEntry6{})) 88 } 89 return &Map{ 90 Map: *bpf.NewMap( 91 name, 92 bpf.MapTypeLRUHash, 93 mapKey, 94 sizeKey, 95 mapValue, 96 sizeVal, 97 entries, 98 0, 0, 99 bpf.ConvertKeyValue, 100 ).WithCache(), 101 v4: v4, 102 } 103 } 104 105 // DumpEntries iterates through Map m and writes the values of the 106 // nat entries in m to a string. 107 func (m *Map) DumpEntries() (string, error) { 108 var buffer bytes.Buffer 109 110 nsecStart, _ := bpf.GetMtime() 111 cb := func(k bpf.MapKey, v bpf.MapValue) { 112 key := k.(NatKey) 113 if !key.ToHost().Dump(&buffer, false) { 114 return 115 } 116 val := v.(NatEntry) 117 buffer.WriteString(val.ToHost().Dump(key, nsecStart)) 118 } 119 err := m.DumpWithCallback(cb) 120 return buffer.String(), err 121 } 122 123 type gcStats struct { 124 *bpf.DumpStats 125 126 // deleted is the number of keys deleted 127 deleted uint32 128 129 // dumpError records any error that occurred during the dump. 130 dumpError error 131 } 132 133 func statStartGc(m *Map) gcStats { 134 return gcStats{ 135 DumpStats: bpf.NewDumpStats(&m.Map), 136 } 137 } 138 139 func doFlush4(m *Map) gcStats { 140 stats := statStartGc(m) 141 filterCallback := func(key bpf.MapKey, _ bpf.MapValue) { 142 err := m.Delete(key) 143 if err != nil { 144 log.WithError(err).WithField(logfields.Key, key.String()).Error("Unable to delete CT entry") 145 } else { 146 stats.deleted++ 147 } 148 } 149 stats.dumpError = m.DumpReliablyWithCallback(filterCallback, stats.DumpStats) 150 return stats 151 } 152 153 func doFlush6(m *Map) gcStats { 154 stats := statStartGc(m) 155 filterCallback := func(key bpf.MapKey, _ bpf.MapValue) { 156 err := m.Delete(key) 157 if err != nil { 158 log.WithError(err).WithField(logfields.Key, key.String()).Error("Unable to delete CT entry") 159 } else { 160 stats.deleted++ 161 } 162 } 163 stats.dumpError = m.DumpReliablyWithCallback(filterCallback, stats.DumpStats) 164 return stats 165 } 166 167 // Flush deletes all NAT mappings from the given table. 168 func (m *Map) Flush() int { 169 if m.v4 { 170 return int(doFlush4(m).deleted) 171 } 172 return int(doFlush6(m).deleted) 173 } 174 175 func deleteMapping4(m *Map, ctKey *tuple.TupleKey4Global) error { 176 key := NatKey4{ 177 TupleKey4Global: *ctKey, 178 } 179 // Workaround #5848. 180 addr := key.SourceAddr 181 key.SourceAddr = key.DestAddr 182 key.DestAddr = addr 183 valMap, err := m.Lookup(&key) 184 if err == nil { 185 val := *(*NatEntry4)(unsafe.Pointer(valMap.GetValuePtr())) 186 rkey := key 187 rkey.SourceAddr = key.DestAddr 188 rkey.SourcePort = key.DestPort 189 rkey.DestAddr = val.Addr 190 rkey.DestPort = val.Port 191 rkey.Flags = tuple.TUPLE_F_IN 192 193 m.Delete(&key) 194 m.Delete(&rkey) 195 } 196 return nil 197 } 198 199 func deleteMapping6(m *Map, ctKey *tuple.TupleKey6Global) error { 200 key := NatKey6{ 201 TupleKey6Global: *ctKey, 202 } 203 // Workaround #5848. 204 addr := key.SourceAddr 205 key.SourceAddr = key.DestAddr 206 key.DestAddr = addr 207 valMap, err := m.Lookup(&key) 208 if err == nil { 209 val := *(*NatEntry6)(unsafe.Pointer(valMap.GetValuePtr())) 210 rkey := key 211 rkey.SourceAddr = key.DestAddr 212 rkey.SourcePort = key.DestPort 213 rkey.DestAddr = val.Addr 214 rkey.DestPort = val.Port 215 rkey.Flags = tuple.TUPLE_F_IN 216 217 m.Delete(&key) 218 m.Delete(&rkey) 219 } 220 return nil 221 } 222 223 // DeleteMapping removes a NAT mapping from the global NAT table. 224 func (m *Map) DeleteMapping(key tuple.TupleKey) error { 225 if key.GetFlags()&tuple.TUPLE_F_IN != 0 { 226 return nil 227 } 228 if m.v4 { 229 return deleteMapping4(m, key.(*tuple.TupleKey4Global)) 230 } 231 return deleteMapping6(m, key.(*tuple.TupleKey6Global)) 232 } 233 234 // GlobalMaps returns all global NAT maps. 235 func GlobalMaps(ipv4, ipv6 bool) (ipv4Map, ipv6Map *Map) { 236 entries := option.Config.NATMapEntriesGlobal 237 if entries == 0 { 238 entries = option.LimitTableMax 239 } 240 if ipv4 { 241 ipv4Map = NewMap(MapNameSnat4Global, true, entries) 242 } 243 if ipv6 { 244 ipv6Map = NewMap(MapNameSnat6Global, false, entries) 245 } 246 return 247 }