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