github.com/zhyoulun/cilium@v1.6.12/pkg/maps/lxcmap/lxcmap.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 lxcmap 16 17 import ( 18 "fmt" 19 "net" 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 ) 26 27 var log = logging.DefaultLogger.WithField(logfields.LogSubsys, "map-lxc") 28 29 const ( 30 MapName = "cilium_lxc" 31 32 // MaxEntries represents the maximum number of endpoints in the map 33 MaxEntries = 65535 34 35 // PortMapMax represents the maximum number of Ports Mapping per container. 36 PortMapMax = 16 37 ) 38 39 var ( 40 // LXCMap represents the BPF map for endpoints 41 LXCMap = bpf.NewMap(MapName, 42 bpf.MapTypeHash, 43 &EndpointKey{}, 44 int(unsafe.Sizeof(EndpointKey{})), 45 &EndpointInfo{}, 46 int(unsafe.Sizeof(EndpointInfo{})), 47 MaxEntries, 48 0, 0, 49 bpf.ConvertKeyValue, 50 ).WithCache() 51 ) 52 53 // MAC is the __u64 representation of a MAC address. 54 type MAC uint64 55 56 func (m MAC) String() string { 57 return fmt.Sprintf("%02X:%02X:%02X:%02X:%02X:%02X", 58 uint64((m & 0x0000000000FF)), 59 uint64((m&0x00000000FF00)>>8), 60 uint64((m&0x000000FF0000)>>16), 61 uint64((m&0x0000FF000000)>>24), 62 uint64((m&0x00FF00000000)>>32), 63 uint64((m&0xFF0000000000)>>40), 64 ) 65 } 66 67 // ParseMAC parses s only as an IEEE 802 MAC-48. 68 func ParseMAC(s string) (MAC, error) { 69 ha, err := net.ParseMAC(s) 70 if err != nil { 71 return 0, err 72 } 73 if len(ha) != 6 { 74 return 0, fmt.Errorf("invalid MAC address %s", s) 75 } 76 return MAC(ha[5])<<40 | MAC(ha[4])<<32 | MAC(ha[3])<<24 | 77 MAC(ha[2])<<16 | MAC(ha[1])<<8 | MAC(ha[0]), nil 78 } 79 80 const ( 81 // EndpointFlagHost indicates that this endpoint represents the host 82 EndpointFlagHost = 1 83 ) 84 85 // EndpointFrontend is the interface to implement for an object to synchronize 86 // with the endpoint BPF map 87 type EndpointFrontend interface { 88 // GetBPFKeys must return a slice of EndpointKey which all represent the endpoint 89 GetBPFKeys() []*EndpointKey 90 91 // GetBPFValue must return an EndpointInfo structure representing the frontend 92 GetBPFValue() (*EndpointInfo, error) 93 } 94 95 type pad4uint32 [4]uint32 96 97 // DeepCopyInto is a deepcopy function, copying the receiver, writing into out. in must be non-nil. 98 func (in *pad4uint32) DeepCopyInto(out *pad4uint32) { 99 copy(out[:], in[:]) 100 return 101 } 102 103 // EndpointInfo represents the value of the endpoints BPF map. 104 // 105 // Must be in sync with struct endpoint_info in <bpf/lib/common.h> 106 // +k8s:deepcopy-gen=true 107 // +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapValue 108 type EndpointInfo struct { 109 IfIndex uint32 `align:"ifindex"` 110 Unused uint16 `align:"unused"` 111 LxcID uint16 `align:"lxc_id"` 112 Flags uint32 `align:"flags"` 113 // go alignment 114 _ uint32 115 MAC MAC `align:"mac"` 116 NodeMAC MAC `align:"node_mac"` 117 Pad pad4uint32 `align:"pad"` 118 } 119 120 // GetValuePtr returns the unsafe pointer to the BPF value 121 func (v *EndpointInfo) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(v) } 122 123 // +k8s:deepcopy-gen=true 124 // +k8s:deepcopy-gen:interfaces=github.com/cilium/cilium/pkg/bpf.MapKey 125 type EndpointKey struct { 126 bpf.EndpointKey 127 } 128 129 // NewValue returns a new empty instance of the structure representing the BPF 130 // map value 131 func (k EndpointKey) NewValue() bpf.MapValue { return &EndpointInfo{} } 132 133 // NewEndpointKey returns an EndpointKey based on the provided IP address. The 134 // address family is automatically detected 135 func NewEndpointKey(ip net.IP) *EndpointKey { 136 return &EndpointKey{ 137 EndpointKey: bpf.NewEndpointKey(ip), 138 } 139 } 140 141 // IsHost returns true if the EndpointInfo represents a host IP 142 func (v *EndpointInfo) IsHost() bool { 143 return v.Flags&EndpointFlagHost != 0 144 } 145 146 // String returns the human readable representation of an EndpointInfo 147 func (v *EndpointInfo) String() string { 148 if v.Flags&EndpointFlagHost != 0 { 149 return fmt.Sprintf("(localhost)") 150 } 151 152 return fmt.Sprintf("id=%-5d flags=0x%04X ifindex=%-3d mac=%s nodemac=%s", 153 v.LxcID, 154 v.Flags, 155 v.IfIndex, 156 v.MAC, 157 v.NodeMAC, 158 ) 159 } 160 161 // WriteEndpoint updates the BPF map with the endpoint information and links 162 // the endpoint information to all keys provided. 163 func WriteEndpoint(f EndpointFrontend) error { 164 info, err := f.GetBPFValue() 165 if err != nil { 166 return err 167 } 168 169 // FIXME: Revert on failure 170 for _, v := range f.GetBPFKeys() { 171 if err := LXCMap.Update(v, info); err != nil { 172 return err 173 } 174 } 175 176 return nil 177 } 178 179 // AddHostEntry adds a special endpoint which represents the local host 180 func AddHostEntry(ip net.IP) error { 181 key := NewEndpointKey(ip) 182 ep := &EndpointInfo{Flags: EndpointFlagHost} 183 return LXCMap.Update(key, ep) 184 } 185 186 // SyncHostEntry checks if a host entry exists in the lxcmap and adds one if needed. 187 // Returns boolean indicating if a new entry was added and an error. 188 func SyncHostEntry(ip net.IP) (bool, error) { 189 key := NewEndpointKey(ip) 190 value, err := LXCMap.Lookup(key) 191 if err != nil || value.(*EndpointInfo).Flags&EndpointFlagHost == 0 { 192 err = AddHostEntry(ip) 193 if err == nil { 194 return true, nil 195 } 196 } 197 return false, err 198 } 199 200 // DeleteEntry deletes a single map entry 201 func DeleteEntry(ip net.IP) error { 202 return LXCMap.Delete(NewEndpointKey(ip)) 203 } 204 205 // DeleteElement deletes the endpoint using all keys which represent the 206 // endpoint. It returns the number of errors encountered during deletion. 207 func DeleteElement(f EndpointFrontend) []error { 208 var errors []error 209 for _, k := range f.GetBPFKeys() { 210 if err := LXCMap.Delete(k); err != nil { 211 errors = append(errors, fmt.Errorf("Unable to delete key %v from %s: %s", k, bpf.MapPath(MapName), err)) 212 } 213 } 214 215 return errors 216 } 217 218 // DumpToMap dumps the contents of the lxcmap into a map and returns it 219 func DumpToMap() (map[string]*EndpointInfo, error) { 220 m := map[string]*EndpointInfo{} 221 callback := func(key bpf.MapKey, value bpf.MapValue) { 222 if info, ok := value.DeepCopyMapValue().(*EndpointInfo); ok { 223 if endpointKey, ok := key.(*EndpointKey); ok { 224 m[endpointKey.ToIP().String()] = info 225 } 226 } 227 } 228 229 if err := LXCMap.DumpWithCallback(callback); err != nil { 230 return nil, fmt.Errorf("unable to read BPF endpoint list: %s", err) 231 } 232 233 return m, nil 234 }