github.com/cilium/cilium@v1.16.2/pkg/maps/ctmap/lookup.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package ctmap 5 6 import ( 7 "fmt" 8 "net/netip" 9 10 "github.com/cilium/cilium/pkg/bpf" 11 "github.com/cilium/cilium/pkg/tuple" 12 "github.com/cilium/cilium/pkg/u8proto" 13 ) 14 15 func createTupleKey(isGlobal bool, srcAddr, dstAddr string, proto u8proto.U8proto, ingress bool) (bpf.MapKey, bool, error) { 16 srcAddrPort, err := netip.ParseAddrPort(srcAddr) 17 if err != nil { 18 return nil, false, fmt.Errorf("invalid source address '%s': %w", srcAddr, err) 19 } 20 21 dstAddrPort, err := netip.ParseAddrPort(dstAddr) 22 if err != nil { 23 return nil, false, fmt.Errorf("invalid destination address '%s': %w", dstAddr, err) 24 } 25 26 if srcAddrPort.Addr().Is4() { 27 if isGlobal { 28 key := &CtKey4Global{ 29 TupleKey4Global: tuple.TupleKey4Global{ 30 TupleKey4: tuple.TupleKey4{ 31 SourcePort: uint16(srcAddrPort.Port()), 32 DestPort: uint16(dstAddrPort.Port()), 33 NextHeader: proto, 34 Flags: TUPLE_F_OUT, 35 }, 36 }, 37 } 38 // CTmap has the addresses in the reverse order w.r.t. the original direction 39 key.SourceAddr.FromAddr(dstAddrPort.Addr()) 40 key.DestAddr.FromAddr(srcAddrPort.Addr()) 41 if ingress { 42 key.Flags = TUPLE_F_IN 43 } 44 return key.ToNetwork(), true, nil 45 } 46 47 key := &CtKey4{ 48 TupleKey4: tuple.TupleKey4{ 49 SourcePort: uint16(srcAddrPort.Port()), 50 DestPort: uint16(dstAddrPort.Port()), 51 NextHeader: proto, 52 Flags: TUPLE_F_OUT, 53 }, 54 } 55 // CTmap has the addresses in the reverse order w.r.t. the original direction 56 key.SourceAddr.FromAddr(dstAddrPort.Addr()) 57 key.DestAddr.FromAddr(srcAddrPort.Addr()) 58 if ingress { 59 key.Flags = TUPLE_F_IN 60 } 61 return key.ToNetwork(), true, nil 62 } 63 64 if isGlobal { 65 key := &CtKey6Global{ 66 TupleKey6Global: tuple.TupleKey6Global{ 67 TupleKey6: tuple.TupleKey6{ 68 SourcePort: uint16(srcAddrPort.Port()), 69 DestPort: uint16(dstAddrPort.Port()), 70 NextHeader: proto, 71 Flags: TUPLE_F_OUT, 72 }, 73 }, 74 } 75 // CTmap has the addresses in the reverse order w.r.t. the original direction 76 key.SourceAddr.FromAddr(dstAddrPort.Addr()) 77 key.DestAddr.FromAddr(srcAddrPort.Addr()) 78 if ingress { 79 key.Flags = TUPLE_F_IN 80 } 81 return key.ToNetwork(), false, nil 82 } 83 84 key := &CtKey6{ 85 TupleKey6: tuple.TupleKey6{ 86 SourcePort: uint16(srcAddrPort.Port()), 87 DestPort: uint16(dstAddrPort.Port()), 88 NextHeader: proto, 89 Flags: TUPLE_F_OUT, 90 }, 91 } 92 // CTmap has the addresses in the reverse order w.r.t. the original direction 93 key.SourceAddr.FromAddr(dstAddrPort.Addr()) 94 key.DestAddr.FromAddr(srcAddrPort.Addr()) 95 if ingress { 96 key.Flags = TUPLE_F_IN 97 } 98 return key.ToNetwork(), false, nil 99 } 100 101 func getMapName(mapname string, ipv4 bool, proto u8proto.U8proto) string { 102 if ipv4 { 103 if proto == u8proto.TCP { 104 mapname = MapNameTCP4 + mapname 105 } else { 106 mapname = MapNameAny4 + mapname 107 } 108 } else { 109 if proto == u8proto.TCP { 110 mapname = MapNameTCP6 + mapname 111 } else { 112 mapname = MapNameAny6 + mapname 113 } 114 } 115 return mapname 116 } 117 118 func getOrOpenMap(epname string, ipv4 bool, proto u8proto.U8proto) (*bpf.Map, error) { 119 mapname := getMapName(epname, ipv4, proto) 120 if m := bpf.GetMap(mapname); m != nil { 121 return m, nil 122 } 123 124 if epname == "global" { 125 if ipv4 { 126 return bpf.OpenMap(bpf.MapPath(mapname), &CtKey4Global{}, &CtEntry{}) 127 } 128 129 return bpf.OpenMap(bpf.MapPath(mapname), &CtKey6Global{}, &CtEntry{}) 130 } 131 132 if ipv4 { 133 return bpf.OpenMap(bpf.MapPath(mapname), &CtKey4{}, &CtEntry{}) 134 } 135 136 return bpf.OpenMap(bpf.MapPath(mapname), &CtKey6{}, &CtEntry{}) 137 } 138 139 // Lookup opens a conntrack map if necessary, and does a lookup on it with a key constructed from 140 // the parameters 141 // 'epname' is a 5-digit representation of the endpoint ID if local maps 142 // are to be used, or "global" if global maps should be used. 143 func Lookup(epname string, srcAddr, dstAddr string, proto u8proto.U8proto, ingress bool) (*CtEntry, error) { 144 isGlobal := epname == "global" 145 146 key, ipv4, err := createTupleKey(isGlobal, srcAddr, dstAddr, proto, ingress) 147 if err != nil { 148 return nil, err 149 } 150 151 m, err := getOrOpenMap(epname, ipv4, proto) 152 if err != nil || m == nil { 153 return nil, err 154 } 155 156 v, err := m.Lookup(key) 157 if err != nil || v == nil { 158 return nil, err 159 } 160 161 return v.(*CtEntry), err 162 } 163 164 // Update opens a conntrack map if necessary, and does a lookup on it with a key constructed from 165 // the parameters, and updates the found entry (if any) via 'updateFn'. 166 // 'epname' is a 5-digit representation of the endpoint ID if local maps 167 // are to be used, or "global" if global maps should be used. 168 func Update(epname string, srcAddr, dstAddr string, proto u8proto.U8proto, ingress bool, 169 updateFn func(*CtEntry) error) error { 170 isGlobal := epname == "global" 171 172 key, ipv4, err := createTupleKey(isGlobal, srcAddr, dstAddr, proto, ingress) 173 if err != nil { 174 return err 175 } 176 177 m, err := getOrOpenMap(epname, ipv4, proto) 178 if err != nil || m == nil { 179 return err 180 } 181 182 v, err := m.Lookup(key) 183 if err != nil || v == nil { 184 return err 185 } 186 187 entry := v.(*CtEntry) 188 err = updateFn(entry) 189 if err != nil { 190 return err 191 } 192 193 return m.Update(key, entry) 194 } 195 196 func getMapWithName(epname string, ipv4 bool, proto u8proto.U8proto) *bpf.Map { 197 return bpf.GetMap(getMapName(epname, ipv4, proto)) 198 } 199 200 // CloseLocalMaps closes all local conntrack maps opened previously 201 // for lookup with the given 'mapname'. 202 func CloseLocalMaps(mapname string) { 203 // only close local maps. Global map is kept open as long as cilium-agent is running. 204 if mapname != "global" { 205 // close IPv4 maps, if any 206 if m := getMapWithName(mapname, true, u8proto.TCP); m != nil { 207 m.Close() 208 } 209 if m := getMapWithName(mapname, true, u8proto.UDP); m != nil { 210 m.Close() 211 } 212 213 // close IPv6 maps, if any 214 if m := getMapWithName(mapname, false, u8proto.TCP); m != nil { 215 m.Close() 216 } 217 if m := getMapWithName(mapname, false, u8proto.UDP); m != nil { 218 m.Close() 219 } 220 } 221 }