github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/maps/policymap/policymap.go (about) 1 // Copyright 2016-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 policymap 16 17 import ( 18 "bytes" 19 "fmt" 20 "syscall" 21 "unsafe" 22 23 "github.com/cilium/cilium/pkg/bpf" 24 "github.com/cilium/cilium/pkg/byteorder" 25 "github.com/cilium/cilium/pkg/logging" 26 "github.com/cilium/cilium/pkg/logging/logfields" 27 "github.com/cilium/cilium/pkg/policy/trafficdirection" 28 "github.com/cilium/cilium/pkg/u8proto" 29 ) 30 31 const ( 32 // CallMapName is the name of the map to do tail calls into policy 33 // enforcement programs 34 CallMapName = "cilium_policy" 35 36 // MapName is the prefix for endpoint-specific policy maps which map 37 // identity+ports+direction to whether the policy allows communication 38 // with that identity on that port for that direction. 39 MapName = CallMapName + "_" 40 41 // ProgArrayMaxEntries is the upper limit of entries in the program 42 // array for the tail calls to jump into the endpoint specific policy 43 // programs. This number *MUST* be identical to the maximum endponit ID. 44 ProgArrayMaxEntries = ^uint16(0) 45 46 // AllPorts is used to ignore the L4 ports in PolicyMap lookups; all ports 47 // are allowed. In the datapath, this is represented with the value 0 in the 48 // port field of map elements. 49 AllPorts = uint16(0) 50 ) 51 52 var ( 53 log = logging.DefaultLogger.WithField(logfields.LogSubsys, "map-policy") 54 55 // MaxEntries is the upper limit of entries in the per endpoint policy 56 // table 57 MaxEntries = 16384 58 ) 59 60 type PolicyMap struct { 61 *bpf.Map 62 } 63 64 func (pe *PolicyEntry) String() string { 65 return fmt.Sprintf("%d %d %d", pe.ProxyPort, pe.Packets, pe.Bytes) 66 } 67 68 // PolicyKey represents a key in the BPF policy map for an endpoint. It must 69 // match the layout of policy_key in bpf/lib/common.h. 70 // +k8s:deepcopy-gen=true 71 // +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapKey 72 type PolicyKey struct { 73 Identity uint32 74 DestPort uint16 // In network byte-order 75 Nexthdr uint8 76 TrafficDirection uint8 77 } 78 79 // PolicyEntry represents an entry in the BPF policy map for an endpoint. It must 80 // match the layout of policy_entry in bpf/lib/common.h. 81 // +k8s:deepcopy-gen=true 82 // +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapValue 83 type PolicyEntry struct { 84 ProxyPort uint16 // In network byte-order 85 Pad0 uint16 86 Pad1 uint16 87 Pad2 uint16 88 Packets uint64 89 Bytes uint64 90 } 91 92 func (pe *PolicyEntry) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(pe) } 93 func (pe *PolicyEntry) NewValue() bpf.MapValue { return &PolicyEntry{} } 94 95 func (pe *PolicyEntry) Add(oPe PolicyEntry) { 96 pe.Packets += oPe.Packets 97 pe.Bytes += oPe.Bytes 98 } 99 100 type PolicyEntryDump struct { 101 PolicyEntry 102 Key PolicyKey 103 } 104 105 // PolicyEntriesDump is a wrapper for a slice of PolicyEntryDump 106 type PolicyEntriesDump []PolicyEntryDump 107 108 // Less returns true if the element in index `i` has the value of 109 // TrafficDirection lower than `j`'s TrafficDirection or if the element in index 110 // `i` has the value of TrafficDirection lower and equal than `j`'s 111 // TrafficDirection and the identity of element `i` is lower than the Identity 112 // of element j. 113 func (p PolicyEntriesDump) Less(i, j int) bool { 114 if p[i].Key.TrafficDirection < p[j].Key.TrafficDirection { 115 return true 116 } 117 return p[i].Key.TrafficDirection <= p[j].Key.TrafficDirection && 118 p[i].Key.Identity < p[j].Key.Identity 119 } 120 121 func (key *PolicyKey) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(key) } 122 func (key *PolicyKey) NewValue() bpf.MapValue { return &PolicyEntry{} } 123 124 func (key *PolicyKey) String() string { 125 126 trafficDirectionString := (trafficdirection.TrafficDirection)(key.TrafficDirection).String() 127 if key.DestPort != 0 { 128 return fmt.Sprintf("%s: %d %d/%d", trafficDirectionString, key.Identity, byteorder.NetworkToHost(key.DestPort), key.Nexthdr) 129 } 130 return fmt.Sprintf("%s: %d", trafficDirectionString, key.Identity) 131 } 132 133 // ToHost returns a copy of key with fields converted from network byte-order 134 // to host-byte-order if necessary. 135 func (key *PolicyKey) ToHost() PolicyKey { 136 if key == nil { 137 return PolicyKey{} 138 } 139 140 n := *key 141 n.DestPort = byteorder.NetworkToHost(n.DestPort).(uint16) 142 return n 143 } 144 145 // ToNetwork returns a copy of key with fields converted from host byte-order 146 // to network-byte-order if necessary. 147 func (key *PolicyKey) ToNetwork() PolicyKey { 148 if key == nil { 149 return PolicyKey{} 150 } 151 152 n := *key 153 n.DestPort = byteorder.HostToNetwork(n.DestPort).(uint16) 154 return n 155 } 156 157 // newKey returns a PolicyKey representing the specified parameters in network 158 // byte-order. 159 func newKey(id uint32, dport uint16, proto u8proto.U8proto, trafficDirection trafficdirection.TrafficDirection) PolicyKey { 160 return PolicyKey{ 161 Identity: id, 162 DestPort: byteorder.HostToNetwork(dport).(uint16), 163 Nexthdr: uint8(proto), 164 TrafficDirection: trafficDirection.Uint8(), 165 } 166 } 167 168 // newEntry returns a PolicyEntry representing the specified parameters in 169 // network byte-order. 170 func newEntry(proxyPort uint16) PolicyEntry { 171 return PolicyEntry{ 172 ProxyPort: byteorder.HostToNetwork(proxyPort).(uint16), 173 } 174 } 175 176 // AllowKey pushes an entry into the PolicyMap for the given PolicyKey k. 177 // Returns an error if the update of the PolicyMap fails. 178 func (pm *PolicyMap) AllowKey(k PolicyKey, proxyPort uint16) error { 179 return pm.Allow(k.Identity, k.DestPort, u8proto.U8proto(k.Nexthdr), trafficdirection.TrafficDirection(k.TrafficDirection), proxyPort) 180 } 181 182 // Allow pushes an entry into the PolicyMap to allow traffic in the given 183 // `trafficDirection` for identity `id` with destination port `dport` over 184 // protocol `proto`. It is assumed that `dport` and `proxyPort` are in host byte-order. 185 func (pm *PolicyMap) Allow(id uint32, dport uint16, proto u8proto.U8proto, trafficDirection trafficdirection.TrafficDirection, proxyPort uint16) error { 186 key := newKey(id, dport, proto, trafficDirection) 187 entry := newEntry(proxyPort) 188 return pm.Update(&key, &entry) 189 } 190 191 // Exists determines whether PolicyMap currently contains an entry that 192 // allows traffic in `trafficDirection` for identity `id` with destination port 193 // `dport`over protocol `proto`. It is assumed that `dport` is in host byte-order. 194 func (pm *PolicyMap) Exists(id uint32, dport uint16, proto u8proto.U8proto, trafficDirection trafficdirection.TrafficDirection) bool { 195 key := newKey(id, dport, proto, trafficDirection) 196 _, err := pm.Lookup(&key) 197 return err == nil 198 } 199 200 // DeleteKey deletes the key-value pair from the given PolicyMap with PolicyKey 201 // k. Returns an error if deletion from the PolicyMap fails. 202 func (pm *PolicyMap) DeleteKeyWithErrno(key PolicyKey) (error, syscall.Errno) { 203 k := key.ToNetwork() 204 return pm.Map.DeleteWithErrno(&k) 205 } 206 207 // Delete removes an entry from the PolicyMap for identity `id` 208 // sending traffic in direction `trafficDirection` with destination port `dport` 209 // over protocol `proto`. It is assumed that `dport` is in host byte-order. 210 // Returns an error if the deletion did not succeed. 211 func (pm *PolicyMap) Delete(id uint32, dport uint16, proto u8proto.U8proto, trafficDirection trafficdirection.TrafficDirection) error { 212 k := newKey(id, dport, proto, trafficDirection) 213 return pm.Map.Delete(&k) 214 } 215 216 // DeleteEntry removes an entry from the PolicyMap. It can be used in 217 // conjunction with DumpToSlice() to inspect and delete map entries. 218 func (pm *PolicyMap) DeleteEntry(entry *PolicyEntryDump) error { 219 return pm.Map.Delete(&entry.Key) 220 } 221 222 // String returns a human-readable string representing the policy map. 223 func (pm *PolicyMap) String() string { 224 path, err := pm.Path() 225 if err != nil { 226 return err.Error() 227 } 228 return path 229 } 230 231 func (pm *PolicyMap) Dump() (string, error) { 232 var buffer bytes.Buffer 233 entries, err := pm.DumpToSlice() 234 if err != nil { 235 return "", err 236 } 237 for _, entry := range entries { 238 buffer.WriteString(fmt.Sprintf("%20s: %s\n", 239 entry.Key.String(), entry.PolicyEntry.String())) 240 } 241 return buffer.String(), nil 242 } 243 244 func (pm *PolicyMap) DumpToSlice() (PolicyEntriesDump, error) { 245 entries := PolicyEntriesDump{} 246 247 cb := func(key bpf.MapKey, value bpf.MapValue) { 248 eDump := PolicyEntryDump{ 249 Key: *key.DeepCopyMapKey().(*PolicyKey), 250 PolicyEntry: *value.DeepCopyMapValue().(*PolicyEntry), 251 } 252 entries = append(entries, eDump) 253 } 254 err := pm.DumpWithCallback(cb) 255 256 return entries, err 257 } 258 259 func newMap(path string) *PolicyMap { 260 mapType := bpf.MapType(bpf.BPF_MAP_TYPE_HASH) 261 flags := bpf.GetPreAllocateMapFlags(mapType) 262 return &PolicyMap{ 263 Map: bpf.NewMap( 264 path, 265 mapType, 266 &PolicyKey{}, 267 int(unsafe.Sizeof(PolicyKey{})), 268 &PolicyEntry{}, 269 int(unsafe.Sizeof(PolicyEntry{})), 270 MaxEntries, 271 flags, 0, 272 bpf.ConvertKeyValue, 273 ), 274 } 275 } 276 277 // OpenOrCreate opens (or creates) a policy map at the specified path, which 278 // is used to govern which peer identities can communicate with the endpoint 279 // protected by this map. 280 func OpenOrCreate(path string) (*PolicyMap, bool, error) { 281 m := newMap(path) 282 isNewMap, err := m.OpenOrCreate() 283 return m, isNewMap, err 284 } 285 286 // Open opens the policymap at the specified path. 287 func Open(path string) (*PolicyMap, error) { 288 m := newMap(path) 289 if err := m.Open(); err != nil { 290 return nil, err 291 } 292 return m, nil 293 } 294 295 // InitMapInfo updates the map info defaults for policy maps. 296 func InitMapInfo(maxEntries int) { 297 MaxEntries = maxEntries 298 }