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  }