github.com/cilium/cilium@v1.16.2/pkg/maps/lbmap/skip_lb_map.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package lbmap
     5  
     6  import (
     7  	"fmt"
     8  	"net"
     9  	"unsafe"
    10  
    11  	"github.com/sirupsen/logrus"
    12  
    13  	"github.com/cilium/cilium/pkg/bpf"
    14  	"github.com/cilium/cilium/pkg/byteorder"
    15  	"github.com/cilium/cilium/pkg/ebpf"
    16  	"github.com/cilium/cilium/pkg/logging/logfields"
    17  	"github.com/cilium/cilium/pkg/option"
    18  	"github.com/cilium/cilium/pkg/types"
    19  )
    20  
    21  const (
    22  	// SkipLB4MapName is the name of the IPv4 BPF map that stores entries to skip LB.
    23  	SkipLB4MapName = "cilium_skip_lb4"
    24  
    25  	// SkipLB6MapName is the name of the IPv6 BPF map that stores entries to skip LB.
    26  	SkipLB6MapName = "cilium_skip_lb6"
    27  
    28  	// SkipLBMapMaxEntries is the maximum number of entries in the skip LB BPF maps.
    29  	SkipLBMapMaxEntries = 100
    30  )
    31  
    32  // SkipLBMap provides access to the eBPF map that stores entries for which load-balancing is skipped.
    33  type SkipLBMap interface {
    34  	AddLB4(netnsCookie uint64, ip net.IP, port uint16) error
    35  	AddLB6(netnsCookie uint64, ip net.IP, port uint16) error
    36  	DeleteLB4ByAddrPort(ip net.IP, port uint16)
    37  	DeleteLB6ByAddrPort(ip net.IP, port uint16)
    38  	DeleteLB4ByNetnsCookie(cookie uint64)
    39  	DeleteLB6ByNetnsCookie(cookie uint64)
    40  }
    41  
    42  func NewSkipLBMap() (SkipLBMap, error) {
    43  	skipLBMap := &skipLBMap{}
    44  
    45  	if option.Config.EnableIPv4 {
    46  		skipLBMap.bpfMap4 = ebpf.NewMap(&ebpf.MapSpec{
    47  			Name:       SkipLB4MapName,
    48  			Type:       ebpf.Hash,
    49  			KeySize:    uint32(unsafe.Sizeof(SkipLB4Key{})),
    50  			ValueSize:  uint32(unsafe.Sizeof(SkipLB4Value{})),
    51  			MaxEntries: SkipLBMapMaxEntries,
    52  			Flags:      bpf.BPF_F_NO_PREALLOC,
    53  			Pinning:    ebpf.PinByName},
    54  		)
    55  		if err := skipLBMap.bpfMap4.OpenOrCreate(); err != nil {
    56  			return nil, fmt.Errorf("failed to open or create %s: %w", SkipLB4MapName, err)
    57  		}
    58  	}
    59  	if option.Config.EnableIPv6 {
    60  		skipLBMap.bpfMap6 = ebpf.NewMap(&ebpf.MapSpec{
    61  			Name:       SkipLB6MapName,
    62  			Type:       ebpf.Hash,
    63  			KeySize:    uint32(unsafe.Sizeof(SkipLB6Key{})),
    64  			ValueSize:  uint32(unsafe.Sizeof(SkipLB6Value{})),
    65  			MaxEntries: SkipLBMapMaxEntries,
    66  			Flags:      bpf.BPF_F_NO_PREALLOC,
    67  			Pinning:    ebpf.PinByName},
    68  		)
    69  		if err := skipLBMap.bpfMap6.OpenOrCreate(); err != nil {
    70  			return nil, fmt.Errorf("failed to open or create %s: %w", SkipLB6MapName, err)
    71  		}
    72  	}
    73  
    74  	return skipLBMap, nil
    75  }
    76  
    77  // AddLB4 adds the given tuple to skip LB for to the BPF v4 map.
    78  func (m *skipLBMap) AddLB4(netnsCookie uint64, ip net.IP, port uint16) error {
    79  	return m.bpfMap4.Update(
    80  		NewSkipLB4Key(netnsCookie, ip.To4(), port),
    81  		&SkipLB4Value{}, 0)
    82  }
    83  
    84  // AddLB6 adds the given tuple to skip LB for to the BPF v6 map.
    85  func (m *skipLBMap) AddLB6(netnsCookie uint64, ip net.IP, port uint16) error {
    86  	return m.bpfMap6.Update(
    87  		NewSkipLB6Key(netnsCookie, ip.To16(), port),
    88  		&SkipLB6Value{}, 0)
    89  }
    90  
    91  // DeleteLB4ByAddrPort deletes entries associated with the passed address and port from the v4 map.
    92  func (m *skipLBMap) DeleteLB4ByAddrPort(ip net.IP, port uint16) {
    93  	deleted := 0
    94  	errors := 0
    95  	deleteEntry := func(key *SkipLB4Key, _ *SkipLB4Value) {
    96  		if key == nil {
    97  			return
    98  		}
    99  		if ip.To4().Equal(key.Address.IP()) && byteorder.NetworkToHost16(key.Port) == port {
   100  			if err := m.bpfMap4.Delete(key); err != nil {
   101  				errors++
   102  				log.WithError(err).WithFields(logrus.Fields{
   103  					"key": key,
   104  					"map": SkipLB4MapName,
   105  				}).Error("error deleting entry from map")
   106  				return
   107  			}
   108  			deleted++
   109  		}
   110  	}
   111  	if err := m.bpfMap4.IterateWithCallback(&SkipLB4Key{}, &SkipLB4Value{},
   112  		func(k, v interface{}) {
   113  			key := k.(*SkipLB4Key)
   114  			value := v.(*SkipLB4Value)
   115  			deleteEntry(key, value)
   116  		}); err != nil {
   117  		log.WithError(err).Error("error iterating over skip_lb4 map")
   118  	}
   119  	scopedLog := log.WithFields(logrus.Fields{
   120  		logfields.Address: ip,
   121  		logfields.Port:    port,
   122  	})
   123  	scopedLog.WithFields(logrus.Fields{
   124  		"deleted": deleted,
   125  		"errors":  errors,
   126  	}).Info("DeleteLB4ByAddrPort")
   127  }
   128  
   129  // DeleteLB4ByNetnsCookie deletes entries associated with the passed netns cookie from the v4 map.
   130  func (m *skipLBMap) DeleteLB4ByNetnsCookie(cookie uint64) {
   131  	deleted := 0
   132  	errors := 0
   133  	deleteEntry := func(key *SkipLB4Key, _ *SkipLB4Value) {
   134  		if key == nil {
   135  			return
   136  		}
   137  		if key.NetnsCookie == cookie {
   138  			if err := m.bpfMap4.Delete(key); err != nil {
   139  				errors++
   140  				log.WithFields(logrus.Fields{
   141  					"key": key,
   142  					"map": SkipLB4MapName,
   143  				}).Error("error deleting entry from map")
   144  				return
   145  			}
   146  			deleted++
   147  		}
   148  	}
   149  	if err := m.bpfMap4.IterateWithCallback(&SkipLB4Key{}, &SkipLB4Value{},
   150  		func(k, v interface{}) {
   151  			key := k.(*SkipLB4Key)
   152  			value := v.(*SkipLB4Value)
   153  			deleteEntry(key, value)
   154  		}); err != nil {
   155  		log.WithError(err).Error("error iterating over skip_lb4 map")
   156  	}
   157  	scopedLog := log.WithFields(logrus.Fields{
   158  		"netns_cookie": cookie,
   159  	})
   160  	scopedLog.WithFields(logrus.Fields{
   161  		"deleted": deleted,
   162  		"errors":  errors,
   163  	}).Info("DeleteLB4ByNetnsCookie")
   164  }
   165  
   166  // DeleteLB6ByAddrPort deletes entries associated with the passed address and port from the v6 map.
   167  func (m *skipLBMap) DeleteLB6ByAddrPort(ip net.IP, port uint16) {
   168  	deleted := 0
   169  	errors := 0
   170  	deleteEntry := func(key *SkipLB6Key, _ *SkipLB6Value) {
   171  		if key == nil {
   172  			return
   173  		}
   174  		if ip.To16().Equal(key.Address.IP()) && byteorder.NetworkToHost16(key.Port) == port {
   175  			if err := m.bpfMap6.Delete(key); err != nil {
   176  				errors++
   177  				log.WithFields(logrus.Fields{
   178  					"key": key,
   179  					"map": SkipLB6MapName,
   180  				}).Error("error deleting entry from map")
   181  				return
   182  			}
   183  			deleted++
   184  		}
   185  	}
   186  	if err := m.bpfMap6.IterateWithCallback(&SkipLB6Key{}, &SkipLB6Value{},
   187  		func(k, v interface{}) {
   188  			key := k.(*SkipLB6Key)
   189  			value := v.(*SkipLB6Value)
   190  			deleteEntry(key, value)
   191  		}); err != nil {
   192  		log.WithError(err).Error("error iterating over skip_lb6 map")
   193  	}
   194  	scopedLog := log.WithFields(logrus.Fields{
   195  		logfields.Address: ip,
   196  		logfields.Port:    port,
   197  	})
   198  	scopedLog.WithFields(logrus.Fields{
   199  		"deleted": deleted,
   200  		"errors":  errors,
   201  	}).Info("DeleteLB6ByAddrPort")
   202  }
   203  
   204  // DeleteLB6ByNetnsCookie deletes entries associated with the passed netns cookie from the v6 map.
   205  func (m *skipLBMap) DeleteLB6ByNetnsCookie(cookie uint64) {
   206  	deleted := 0
   207  	errors := 0
   208  	deleteEntry := func(key *SkipLB6Key, _ *SkipLB6Value) {
   209  		if key == nil {
   210  			return
   211  		}
   212  		if key.NetnsCookie == cookie {
   213  			if err := m.bpfMap6.Delete(key); err != nil {
   214  				errors++
   215  				log.WithError(err).WithFields(logrus.Fields{
   216  					"key": key,
   217  					"map": SkipLB6MapName,
   218  				}).Error("error deleting entry from map")
   219  				return
   220  			}
   221  			deleted++
   222  		}
   223  	}
   224  	if err := m.bpfMap6.IterateWithCallback(&SkipLB6Key{}, &SkipLB6Value{},
   225  		func(k, v interface{}) {
   226  			key := k.(*SkipLB6Key)
   227  			value := v.(*SkipLB6Value)
   228  			deleteEntry(key, value)
   229  		}); err != nil {
   230  		log.WithError(err).Error("error iterating over skip_lb6 map")
   231  	}
   232  	scopedLog := log.WithFields(logrus.Fields{
   233  		logfields.NetnsCookie: cookie,
   234  	})
   235  	scopedLog.WithFields(logrus.Fields{
   236  		"deleted": deleted,
   237  		"errors":  errors,
   238  	}).Info("DeleteLB6ByNetnsCookie")
   239  }
   240  
   241  // SkipLB4Key is the tuple with netns cookie, address and port and used as key in
   242  // the skip LB4 map.
   243  type SkipLB4Key struct {
   244  	NetnsCookie uint64     `align:"netns_cookie"`
   245  	Address     types.IPv4 `align:"address"`
   246  	Port        uint16     `align:"port"`
   247  	Pad         int16      `align:"pad"`
   248  }
   249  
   250  type SkipLB4Value struct {
   251  	Pad uint8 `align:"pad"`
   252  }
   253  
   254  // NewSkipLB4Key creates the SkipLB4Key
   255  func NewSkipLB4Key(netnsCookie uint64, address net.IP, port uint16) *SkipLB4Key {
   256  	key := SkipLB4Key{
   257  		NetnsCookie: netnsCookie,
   258  		Port:        byteorder.HostToNetwork16(port),
   259  	}
   260  	copy(key.Address[:], address.To4())
   261  
   262  	return &key
   263  }
   264  
   265  func (k *SkipLB4Key) New() bpf.MapKey { return &SkipLB4Key{} }
   266  
   267  // GetValuePtr returns the unsafe pointer to the BPF value
   268  func (v *SkipLB4Value) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(v) }
   269  
   270  // String converts the key into a human-readable string format.
   271  func (k *SkipLB4Key) String() string {
   272  	return fmt.Sprintf("[%d]:%d, %d", k.NetnsCookie, k.Address, k.Port)
   273  }
   274  
   275  func (v *SkipLB4Value) New() bpf.MapValue { return &SkipLB4Value{} }
   276  
   277  // String converts the value into a human-readable string format.
   278  func (v *SkipLB4Value) String() string {
   279  	return ""
   280  }
   281  
   282  // SkipLB6Key is the tuple with netns cookie, address and port and used as key in
   283  // the skip LB6 map.
   284  type SkipLB6Key struct {
   285  	NetnsCookie uint64     `align:"netns_cookie"`
   286  	Address     types.IPv6 `align:"address"`
   287  	Pad         uint32     `align:"pad"`
   288  	Port        uint16     `align:"port"`
   289  	Pad2        uint16     `align:"pad2"`
   290  }
   291  
   292  type SkipLB6Value struct {
   293  	Pad uint8 `align:"pad"`
   294  }
   295  
   296  // NewSkipLB6Key creates the SkipLB6Key
   297  func NewSkipLB6Key(netnsCookie uint64, address net.IP, port uint16) *SkipLB6Key {
   298  	key := SkipLB6Key{
   299  		NetnsCookie: netnsCookie,
   300  		Port:        port,
   301  	}
   302  	copy(key.Address[:], address.To16())
   303  
   304  	return &key
   305  }
   306  
   307  func (k *SkipLB6Key) New() bpf.MapKey { return &SkipLB6Key{} }
   308  
   309  // GetKeyPtr returns the unsafe pointer to the BPF key
   310  func (k *SkipLB6Key) GetKeyPtr() unsafe.Pointer { return unsafe.Pointer(k) }
   311  
   312  // GetValuePtr returns the unsafe pointer to the BPF value
   313  func (v *SkipLB6Value) GetValuePtr() unsafe.Pointer { return unsafe.Pointer(v) }
   314  
   315  // String converts the key into a human-readable string format.
   316  func (k *SkipLB6Key) String() string {
   317  	return fmt.Sprintf("[%d]:%d, %d", k.NetnsCookie, k.Address, k.Port)
   318  }
   319  
   320  func (v *SkipLB6Value) New() bpf.MapValue { return &SkipLB6Value{} }
   321  
   322  // String converts the value into a human-readable string format.
   323  func (v *SkipLB6Value) String() string {
   324  	return ""
   325  }
   326  
   327  // NewValue returns a new empty instance of the structure representing the BPF
   328  // map value
   329  func (k *SkipLB6Key) NewValue() bpf.MapValue { return &SkipLB6Value{} }
   330  
   331  type skipLBMap struct {
   332  	bpfMap4 *ebpf.Map
   333  	bpfMap6 *ebpf.Map
   334  }