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 }