github.com/cilium/cilium@v1.16.2/pkg/datapath/ipcache/listener.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package ipcache
     5  
     6  import (
     7  	"net"
     8  
     9  	"github.com/sirupsen/logrus"
    10  
    11  	"github.com/cilium/cilium/pkg/bpf"
    12  	cmtypes "github.com/cilium/cilium/pkg/clustermesh/types"
    13  	"github.com/cilium/cilium/pkg/ipcache"
    14  	"github.com/cilium/cilium/pkg/logging"
    15  	"github.com/cilium/cilium/pkg/logging/logfields"
    16  	ipcacheMap "github.com/cilium/cilium/pkg/maps/ipcache"
    17  	monitorAPI "github.com/cilium/cilium/pkg/monitor/api"
    18  	"github.com/cilium/cilium/pkg/node"
    19  	"github.com/cilium/cilium/pkg/option"
    20  )
    21  
    22  var (
    23  	log = logging.DefaultLogger.WithField(logfields.LogSubsys, "datapath-ipcache")
    24  )
    25  
    26  // monitorNotify is an interface to notify the monitor about ipcache changes.
    27  type monitorNotify interface {
    28  	SendEvent(typ int, event interface{}) error
    29  }
    30  
    31  type Map interface {
    32  	Update(key bpf.MapKey, value bpf.MapValue) error
    33  	Delete(key bpf.MapKey) error
    34  }
    35  
    36  // BPFListener implements the ipcache.IPIdentityMappingBPFListener
    37  // interface with an IPCache store that is backed by BPF maps.
    38  type BPFListener struct {
    39  	// bpfMap is the BPF map that this listener will update when events are
    40  	// received from the IPCache.
    41  	bpfMap Map
    42  
    43  	// monitorNotify is used to notify the monitor about ipcache updates
    44  	monitorNotify monitorNotify
    45  }
    46  
    47  // NewListener returns a new listener to push IPCache entries into BPF maps.
    48  func NewListener(m Map, mn monitorNotify) *BPFListener {
    49  	return &BPFListener{
    50  		bpfMap:        m,
    51  		monitorNotify: mn,
    52  	}
    53  }
    54  
    55  func (l *BPFListener) notifyMonitor(modType ipcache.CacheModification,
    56  	cidr net.IPNet, oldHostIP, newHostIP net.IP, oldID *ipcache.Identity,
    57  	newID ipcache.Identity, encryptKey uint8, k8sMeta *ipcache.K8sMetadata) {
    58  	var (
    59  		k8sNamespace, k8sPodName string
    60  		newIdentity, oldIdentity uint32
    61  		oldIdentityPtr           *uint32
    62  	)
    63  
    64  	if l.monitorNotify == nil {
    65  		return
    66  	}
    67  
    68  	if k8sMeta != nil {
    69  		k8sNamespace = k8sMeta.Namespace
    70  		k8sPodName = k8sMeta.PodName
    71  	}
    72  
    73  	newIdentity = newID.ID.Uint32()
    74  	if oldID != nil {
    75  		oldIdentity = oldID.ID.Uint32()
    76  		oldIdentityPtr = &oldIdentity
    77  	}
    78  
    79  	switch modType {
    80  	case ipcache.Upsert:
    81  		msg := monitorAPI.IPCacheUpsertedMessage(cidr.String(), newIdentity, oldIdentityPtr,
    82  			newHostIP, oldHostIP, encryptKey, k8sNamespace, k8sPodName)
    83  		l.monitorNotify.SendEvent(monitorAPI.MessageTypeAgent, msg)
    84  	case ipcache.Delete:
    85  		msg := monitorAPI.IPCacheDeletedMessage(cidr.String(), newIdentity, oldIdentityPtr,
    86  			newHostIP, oldHostIP, encryptKey, k8sNamespace, k8sPodName)
    87  		l.monitorNotify.SendEvent(monitorAPI.MessageTypeAgent, msg)
    88  	}
    89  }
    90  
    91  // OnIPIdentityCacheChange is called whenever there is a change of state in the
    92  // IPCache (pkg/ipcache).
    93  // TODO (FIXME): GH-3161.
    94  //
    95  // 'oldIPIDPair' is ignored here, because in the BPF maps an update for the
    96  // IP->ID mapping will replace any existing contents; knowledge of the old pair
    97  // is not required to upsert the new pair.
    98  func (l *BPFListener) OnIPIdentityCacheChange(modType ipcache.CacheModification, cidrCluster cmtypes.PrefixCluster,
    99  	oldHostIP, newHostIP net.IP, oldID *ipcache.Identity, newID ipcache.Identity,
   100  	encryptKey uint8, k8sMeta *ipcache.K8sMetadata) {
   101  	cidr := cidrCluster.AsIPNet()
   102  
   103  	scopedLog := log
   104  	if option.Config.Debug {
   105  		scopedLog = log.WithFields(logrus.Fields{
   106  			logfields.IPAddr:       cidr,
   107  			logfields.Identity:     newID,
   108  			logfields.Modification: modType,
   109  		})
   110  	}
   111  
   112  	scopedLog.Debug("Daemon notified of IP-Identity cache state change")
   113  
   114  	l.notifyMonitor(modType, cidr, oldHostIP, newHostIP, oldID, newID, encryptKey, k8sMeta)
   115  
   116  	// TODO - see if we can factor this into an interface under something like
   117  	// pkg/datapath instead of in the daemon directly so that the code is more
   118  	// logically located.
   119  
   120  	// Update BPF Maps.
   121  
   122  	key := ipcacheMap.NewKey(cidr.IP, cidr.Mask, uint16(cidrCluster.ClusterID()))
   123  
   124  	switch modType {
   125  	case ipcache.Upsert:
   126  		value := ipcacheMap.RemoteEndpointInfo{
   127  			SecurityIdentity: uint32(newID.ID),
   128  			Key:              encryptKey,
   129  		}
   130  
   131  		if newHostIP != nil {
   132  			// If the hostIP is specified and it doesn't point to
   133  			// the local host, then the ipcache should be populated
   134  			// with the hostIP so that this traffic can be guided
   135  			// to a tunnel endpoint destination.
   136  			nodeIPv4 := node.GetIPv4()
   137  			if ip4 := newHostIP.To4(); ip4 != nil && !ip4.Equal(nodeIPv4) {
   138  				copy(value.TunnelEndpoint[:], ip4)
   139  			}
   140  		}
   141  		err := l.bpfMap.Update(&key, &value)
   142  		if err != nil {
   143  			scopedLog.WithError(err).WithFields(logrus.Fields{
   144  				"key":                  key.String(),
   145  				"value":                value.String(),
   146  				logfields.IPAddr:       cidr,
   147  				logfields.Identity:     newID,
   148  				logfields.Modification: modType,
   149  			}).Warning("unable to update bpf map")
   150  		}
   151  	case ipcache.Delete:
   152  		err := l.bpfMap.Delete(&key)
   153  		if err != nil {
   154  			scopedLog.WithError(err).WithFields(logrus.Fields{
   155  				"key":                  key.String(),
   156  				logfields.IPAddr:       cidr,
   157  				logfields.Identity:     newID,
   158  				logfields.Modification: modType,
   159  			}).Warning("unable to delete from bpf map")
   160  		}
   161  	default:
   162  		scopedLog.Warning("cache modification type not supported")
   163  	}
   164  }