github.com/elfadel/cilium@v1.6.12/pkg/datapath/linux/config.go (about) 1 // Copyright 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 linux 16 17 import ( 18 "bufio" 19 "encoding/base64" 20 "encoding/json" 21 "fmt" 22 "io" 23 "reflect" 24 "sort" 25 26 "github.com/cilium/cilium/pkg/bpf" 27 "github.com/cilium/cilium/pkg/byteorder" 28 "github.com/cilium/cilium/pkg/datapath" 29 "github.com/cilium/cilium/pkg/datapath/iptables" 30 "github.com/cilium/cilium/pkg/defaults" 31 "github.com/cilium/cilium/pkg/identity" 32 "github.com/cilium/cilium/pkg/labels" 33 bpfconfig "github.com/cilium/cilium/pkg/maps/configmap" 34 "github.com/cilium/cilium/pkg/maps/ctmap" 35 "github.com/cilium/cilium/pkg/maps/encrypt" 36 "github.com/cilium/cilium/pkg/maps/eppolicymap" 37 "github.com/cilium/cilium/pkg/maps/ipcache" 38 ipcachemap "github.com/cilium/cilium/pkg/maps/ipcache" 39 "github.com/cilium/cilium/pkg/maps/lbmap" 40 "github.com/cilium/cilium/pkg/maps/lxcmap" 41 "github.com/cilium/cilium/pkg/maps/metricsmap" 42 "github.com/cilium/cilium/pkg/maps/nat" 43 "github.com/cilium/cilium/pkg/maps/policymap" 44 "github.com/cilium/cilium/pkg/maps/sockmap" 45 "github.com/cilium/cilium/pkg/maps/tunnel" 46 "github.com/cilium/cilium/pkg/node" 47 "github.com/cilium/cilium/pkg/option" 48 "github.com/cilium/cilium/pkg/signal" 49 50 "github.com/vishvananda/netlink" 51 ) 52 53 func writeIncludes(w io.Writer) (int, error) { 54 return fmt.Fprintf(w, "#include \"lib/utils.h\"\n\n") 55 } 56 57 // WriteNodeConfig writes the local node configuration to the specified writer. 58 func (l *linuxDatapath) WriteNodeConfig(w io.Writer, cfg *datapath.LocalNodeConfiguration) error { 59 extraMacrosMap := make(map[string]string) 60 cDefinesMap := make(map[string]string) 61 62 fw := bufio.NewWriter(w) 63 64 writeIncludes(w) 65 66 routerIP := node.GetIPv6Router() 67 hostIP := node.GetIPv6() 68 69 fmt.Fprintf(fw, "/*\n") 70 fmt.Fprintf(fw, " cilium.v6.external.str %s\n", node.GetIPv6().String()) 71 fmt.Fprintf(fw, " cilium.v6.internal.str %s\n", node.GetIPv6Router().String()) 72 fmt.Fprintf(fw, " cilium.v6.nodeport.str %s\n", node.GetNodePortIPv6().String()) 73 fmt.Fprintf(fw, "\n") 74 fmt.Fprintf(fw, " cilium.v4.external.str %s\n", node.GetExternalIPv4().String()) 75 fmt.Fprintf(fw, " cilium.v4.internal.str %s\n", node.GetInternalIPv4().String()) 76 fmt.Fprintf(fw, " cilium.v4.nodeport.str %s\n", node.GetNodePortIPv4().String()) 77 fmt.Fprintf(fw, "\n") 78 fw.WriteString(dumpRaw(defaults.RestoreV6Addr, node.GetIPv6Router())) 79 fw.WriteString(dumpRaw(defaults.RestoreV4Addr, node.GetInternalIPv4())) 80 fmt.Fprintf(fw, " */\n\n") 81 82 if option.Config.EnableIPv6 { 83 extraMacrosMap["ROUTER_IP"] = routerIP.String() 84 fw.WriteString(defineIPv6("ROUTER_IP", routerIP)) 85 if option.Config.EnableNodePort { 86 ipv6NP := node.GetNodePortIPv6() 87 extraMacrosMap["IPV6_NODEPORT"] = ipv6NP.String() 88 fw.WriteString(defineIPv6("IPV6_NODEPORT", ipv6NP)) 89 } 90 } 91 92 if option.Config.EnableIPv4 { 93 ipv4GW := node.GetInternalIPv4() 94 loopbackIPv4 := node.GetIPv4Loopback() 95 ipv4Range := node.GetIPv4AllocRange() 96 cDefinesMap["IPV4_GATEWAY"] = fmt.Sprintf("%#x", byteorder.HostSliceToNetwork(ipv4GW, reflect.Uint32).(uint32)) 97 cDefinesMap["IPV4_LOOPBACK"] = fmt.Sprintf("%#x", byteorder.HostSliceToNetwork(loopbackIPv4, reflect.Uint32).(uint32)) 98 cDefinesMap["IPV4_MASK"] = fmt.Sprintf("%#x", byteorder.HostSliceToNetwork(ipv4Range.Mask, reflect.Uint32).(uint32)) 99 100 if option.Config.EnableNodePort { 101 ipv4NP := node.GetNodePortIPv4() 102 cDefinesMap["IPV4_NODEPORT"] = fmt.Sprintf("%#x", byteorder.HostSliceToNetwork(ipv4NP, reflect.Uint32).(uint32)) 103 } 104 } 105 106 if nat46Range := option.Config.NAT46Prefix; nat46Range != nil { 107 fw.WriteString(FmtDefineAddress("NAT46_PREFIX", nat46Range.IP)) 108 } 109 110 extraMacrosMap["HOST_IP"] = hostIP.String() 111 fw.WriteString(defineIPv6("HOST_IP", hostIP)) 112 113 cDefinesMap["HOST_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameHost)) 114 cDefinesMap["WORLD_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameWorld)) 115 cDefinesMap["HEALTH_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameHealth)) 116 cDefinesMap["UNMANAGED_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameUnmanaged)) 117 cDefinesMap["INIT_ID"] = fmt.Sprintf("%d", identity.GetReservedID(labels.IDNameInit)) 118 cDefinesMap["LB_RR_MAX_SEQ"] = fmt.Sprintf("%d", lbmap.MaxSeq) 119 cDefinesMap["CILIUM_LB_MAP_MAX_ENTRIES"] = fmt.Sprintf("%d", lbmap.MaxEntries) 120 cDefinesMap["TUNNEL_MAP"] = tunnel.MapName 121 cDefinesMap["TUNNEL_ENDPOINT_MAP_SIZE"] = fmt.Sprintf("%d", tunnel.MaxEntries) 122 cDefinesMap["ENDPOINTS_MAP"] = lxcmap.MapName 123 cDefinesMap["ENDPOINTS_MAP_SIZE"] = fmt.Sprintf("%d", lxcmap.MaxEntries) 124 cDefinesMap["METRICS_MAP"] = metricsmap.MapName 125 cDefinesMap["METRICS_MAP_SIZE"] = fmt.Sprintf("%d", metricsmap.MaxEntries) 126 cDefinesMap["POLICY_MAP_SIZE"] = fmt.Sprintf("%d", policymap.MaxEntries) 127 cDefinesMap["IPCACHE_MAP"] = ipcachemap.Name 128 cDefinesMap["IPCACHE_MAP_SIZE"] = fmt.Sprintf("%d", ipcachemap.MaxEntries) 129 cDefinesMap["POLICY_PROG_MAP_SIZE"] = fmt.Sprintf("%d", policymap.ProgArrayMaxEntries) 130 cDefinesMap["SOCKOPS_MAP_SIZE"] = fmt.Sprintf("%d", sockmap.MaxEntries) 131 cDefinesMap["ENCRYPT_MAP"] = encrypt.MapName 132 cDefinesMap["CT_CONNECTION_LIFETIME_TCP"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutTCP.Seconds())) 133 cDefinesMap["CT_CONNECTION_LIFETIME_NONTCP"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutAny.Seconds())) 134 cDefinesMap["CT_SERVICE_LIFETIME_TCP"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutSVCTCP.Seconds())) 135 cDefinesMap["CT_SERVICE_LIFETIME_NONTCP"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutSVCAny.Seconds())) 136 cDefinesMap["CT_SYN_TIMEOUT"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutSYN.Seconds())) 137 cDefinesMap["CT_CLOSE_TIMEOUT"] = fmt.Sprintf("%d", int64(option.Config.CTMapEntriesTimeoutFIN.Seconds())) 138 139 if option.Config.DatapathMode == option.DatapathModeIpvlan { 140 cDefinesMap["ENABLE_SECCTX_FROM_IPCACHE"] = "1" 141 } 142 143 if option.Config.PreAllocateMaps { 144 cDefinesMap["PREALLOCATE_MAPS"] = "1" 145 } 146 147 cDefinesMap["EVENTS_MAP"] = "cilium_events" 148 cDefinesMap["SIGNAL_MAP"] = signal.SignalMapName 149 cDefinesMap["POLICY_CALL_MAP"] = policymap.CallMapName 150 cDefinesMap["EP_POLICY_MAP"] = eppolicymap.MapName 151 cDefinesMap["LB6_REVERSE_NAT_MAP"] = "cilium_lb6_reverse_nat" 152 cDefinesMap["LB6_SERVICES_MAP_V2"] = "cilium_lb6_services_v2" 153 cDefinesMap["LB6_BACKEND_MAP"] = "cilium_lb6_backends" 154 cDefinesMap["LB6_RR_SEQ_MAP_V2"] = "cilium_lb6_rr_seq_v2" 155 cDefinesMap["LB6_REVERSE_NAT_SK_MAP"] = "cilium_lb6_reverse_sk" 156 cDefinesMap["LB4_REVERSE_NAT_MAP"] = "cilium_lb4_reverse_nat" 157 cDefinesMap["LB4_SERVICES_MAP_V2"] = "cilium_lb4_services_v2" 158 cDefinesMap["LB4_RR_SEQ_MAP_V2"] = "cilium_lb4_rr_seq_v2" 159 cDefinesMap["LB4_BACKEND_MAP"] = "cilium_lb4_backends" 160 cDefinesMap["LB4_REVERSE_NAT_SK_MAP"] = "cilium_lb4_reverse_sk" 161 162 cDefinesMap["TRACE_PAYLOAD_LEN"] = fmt.Sprintf("%dULL", option.Config.TracePayloadlen) 163 cDefinesMap["MTU"] = fmt.Sprintf("%d", cfg.MtuConfig.GetDeviceMTU()) 164 165 if option.Config.EnableIPv4 { 166 cDefinesMap["ENABLE_IPV4"] = "1" 167 } 168 169 if option.Config.EnableIPv6 { 170 cDefinesMap["ENABLE_IPV6"] = "1" 171 } 172 173 if option.Config.EnableIPSec { 174 cDefinesMap["ENABLE_IPSEC"] = "1" 175 } 176 177 if option.Config.InstallIptRules || iptables.KernelHasNetfilter() { 178 cDefinesMap["NO_REDIRECT"] = "1" 179 } 180 181 if option.Config.EncryptNode { 182 cDefinesMap["ENCRYPT_NODE"] = "1" 183 } 184 185 if option.Config.EnableHostReachableServices { 186 if option.Config.EnableHostServicesTCP { 187 cDefinesMap["ENABLE_HOST_SERVICES_TCP"] = "1" 188 } 189 if option.Config.EnableHostServicesUDP { 190 cDefinesMap["ENABLE_HOST_SERVICES_UDP"] = "1" 191 } 192 if option.Config.EnableHostServicesTCP && option.Config.EnableHostServicesUDP { 193 cDefinesMap["ENABLE_HOST_SERVICES_FULL"] = "1" 194 } 195 } 196 197 if option.Config.EncryptInterface != "" { 198 link, err := netlink.LinkByName(option.Config.EncryptInterface) 199 if err == nil { 200 cDefinesMap["ENCRYPT_IFACE"] = fmt.Sprintf("%d", link.Attrs().Index) 201 202 addr, err := netlink.AddrList(link, netlink.FAMILY_V4) 203 if err == nil { 204 a := byteorder.HostSliceToNetwork(addr[0].IPNet.IP, reflect.Uint32).(uint32) 205 cDefinesMap["IPV4_ENCRYPT_IFACE"] = fmt.Sprintf("%d", a) 206 } 207 } 208 } 209 if option.Config.IsPodSubnetsDefined() { 210 cDefinesMap["IP_POOLS"] = "1" 211 } 212 haveMasquerade := !option.Config.InstallIptRules && option.Config.Masquerade 213 if haveMasquerade || option.Config.EnableNodePort { 214 if option.Config.EnableIPv4 { 215 cDefinesMap["SNAT_MAPPING_IPV4"] = nat.MapNameSnat4Global 216 cDefinesMap["SNAT_MAPPING_IPV4_SIZE"] = fmt.Sprintf("%d", option.Config.NATMapEntriesGlobal) 217 } 218 219 if option.Config.EnableIPv6 { 220 cDefinesMap["SNAT_MAPPING_IPV6"] = nat.MapNameSnat6Global 221 cDefinesMap["SNAT_MAPPING_IPV6_SIZE"] = fmt.Sprintf("%d", option.Config.NATMapEntriesGlobal) 222 } 223 } 224 if haveMasquerade { 225 cDefinesMap["ENABLE_MASQUERADE"] = "1" 226 cDefinesMap["SNAT_MAPPING_MIN_PORT"] = fmt.Sprintf("%d", nat.MinPortSnatDefault) 227 cDefinesMap["SNAT_MAPPING_MAX_PORT"] = fmt.Sprintf("%d", nat.MaxPortSnatDefault) 228 229 // SNAT_DIRECTION is defined by init.sh 230 if option.Config.EnableIPv4 { 231 ipv4Addr := node.GetExternalIPv4() 232 cDefinesMap["SNAT_IPV4_EXTERNAL"] = fmt.Sprintf("%#x", byteorder.HostSliceToNetwork(ipv4Addr, reflect.Uint32).(uint32)) 233 } 234 235 if option.Config.EnableIPv6 { 236 extraMacrosMap["SNAT_IPV6_EXTERNAL"] = hostIP.String() 237 fw.WriteString(defineIPv6("SNAT_IPV6_EXTERNAL", hostIP)) 238 } 239 } 240 241 if (!option.Config.InstallIptRules && option.Config.Masquerade) || option.Config.EnableNodePort { 242 ctmap.WriteBPFMacros(fw, nil) 243 } 244 245 if option.Config.EnableNodePort { 246 cDefinesMap["ENABLE_NODEPORT"] = "1" 247 cDefinesMap["NODEPORT_PORT_MIN"] = fmt.Sprintf("%d", option.Config.NodePortMin) 248 cDefinesMap["NODEPORT_PORT_MAX"] = fmt.Sprintf("%d", option.Config.NodePortMax) 249 cDefinesMap["NODEPORT_PORT_MIN_NAT"] = fmt.Sprintf("%d", option.Config.NodePortMax+1) 250 cDefinesMap["NODEPORT_PORT_MAX_NAT"] = "65535" 251 252 if option.Config.EnableIPv4 { 253 cDefinesMap["NODEPORT_NEIGH4"] = "cilium_nodeport_neigh4" 254 } 255 if option.Config.EnableIPv6 { 256 cDefinesMap["NODEPORT_NEIGH6"] = "cilium_nodeport_neigh6" 257 } 258 } 259 260 // Since golang maps are unordered, we sort the keys in the map 261 // to get a consistent writtern format to the writer. This maintains 262 // the consistency when we try to calculate hash for a datapath after 263 // writing the config. 264 keys := []string{} 265 for key := range cDefinesMap { 266 keys = append(keys, key) 267 } 268 sort.Strings(keys) 269 270 for _, key := range keys { 271 fmt.Fprintf(fw, "#define %s %s\n", key, cDefinesMap[key]) 272 } 273 274 // Populate cDefinesMap with extraMacrosMap to get all the configuration 275 // in the cDefinesMap itself. 276 for key, value := range extraMacrosMap { 277 cDefinesMap[key] = value 278 } 279 280 // Write the JSON encoded config as base64 encoded commented string to 281 // the header file. 282 jsonBytes, err := json.Marshal(cDefinesMap) 283 if err == nil { 284 // We don't care if some error occurs while marshaling the map. 285 // In such cases we skip embedding the base64 encoded JSON configuration 286 // to the writer. 287 encodedConfig := base64.StdEncoding.EncodeToString(jsonBytes) 288 fmt.Fprintf(fw, "\n// JSON_OUTPUT: %s\n", encodedConfig) 289 } 290 291 return fw.Flush() 292 } 293 294 func (l *linuxDatapath) writeNetdevConfig(w io.Writer, cfg datapath.DeviceConfiguration) { 295 fmt.Fprint(w, cfg.GetOptions().GetFmtList()) 296 if option.Config.IsFlannelMasterDeviceSet() { 297 fmt.Fprint(w, "#define HOST_REDIRECT_TO_INGRESS 1\n") 298 } 299 300 // In case the Linux kernel doesn't support LPM map type, pass the set 301 // of prefix length for the datapath to lookup the map. 302 if ipcache.IPCache.MapType != bpf.BPF_MAP_TYPE_LPM_TRIE { 303 ipcachePrefixes6, ipcachePrefixes4 := cfg.GetCIDRPrefixLengths() 304 305 fmt.Fprint(w, "#define IPCACHE6_PREFIXES ") 306 for _, prefix := range ipcachePrefixes6 { 307 fmt.Fprintf(w, "%d,", prefix) 308 } 309 fmt.Fprint(w, "\n") 310 fmt.Fprint(w, "#define IPCACHE4_PREFIXES ") 311 for _, prefix := range ipcachePrefixes4 { 312 fmt.Fprintf(w, "%d,", prefix) 313 } 314 fmt.Fprint(w, "\n") 315 } 316 } 317 318 // WriteNetdevConfig writes the BPF configuration for the endpoint to a writer. 319 func (l *linuxDatapath) WriteNetdevConfig(w io.Writer, cfg datapath.DeviceConfiguration) error { 320 fw := bufio.NewWriter(w) 321 l.writeNetdevConfig(fw, cfg) 322 return fw.Flush() 323 } 324 325 // writeStaticData writes the endpoint-specific static data defines to the 326 // specified writer. This must be kept in sync with loader.ELFSubstitutions(). 327 func (l *linuxDatapath) writeStaticData(fw io.Writer, e datapath.EndpointConfiguration) { 328 fmt.Fprint(fw, defineIPv6("LXC_IP", e.IPv6Address())) 329 fmt.Fprint(fw, defineIPv4("LXC_IPV4", e.IPv4Address())) 330 331 fmt.Fprint(fw, defineMAC("NODE_MAC", e.GetNodeMAC())) 332 fmt.Fprint(fw, defineUint32("LXC_ID", uint32(e.GetID()))) 333 334 secID := e.GetIdentityLocked().Uint32() 335 fmt.Fprintf(fw, defineUint32("SECLABEL", secID)) 336 fmt.Fprintf(fw, defineUint32("SECLABEL_NB", byteorder.HostToNetwork(secID).(uint32))) 337 338 epID := uint16(e.GetID()) 339 fmt.Fprintf(fw, "#define POLICY_MAP %s\n", bpf.LocalMapName(policymap.MapName, epID)) 340 fmt.Fprintf(fw, "#define CALLS_MAP %s\n", bpf.LocalMapName("cilium_calls_", epID)) 341 fmt.Fprintf(fw, "#define CONFIG_MAP %s\n", bpf.LocalMapName(bpfconfig.MapNamePrefix, epID)) 342 } 343 344 // WriteEndpointConfig writes the BPF configuration for the endpoint to a writer. 345 func (l *linuxDatapath) WriteEndpointConfig(w io.Writer, e datapath.EndpointConfiguration) error { 346 fw := bufio.NewWriter(w) 347 348 writeIncludes(w) 349 l.writeStaticData(fw, e) 350 351 return l.writeTemplateConfig(fw, e) 352 } 353 354 func (l *linuxDatapath) writeTemplateConfig(fw *bufio.Writer, e datapath.EndpointConfiguration) error { 355 if e.RequireEgressProg() { 356 fmt.Fprintf(fw, "#define USE_BPF_PROG_FOR_INGRESS_POLICY 1\n") 357 } 358 359 if option.Config.ForceLocalPolicyEvalAtSource { 360 fmt.Fprintf(fw, "#define FORCE_LOCAL_POLICY_EVAL_AT_SOURCE 1\n") 361 } 362 363 if e.RequireRouting() { 364 fmt.Fprintf(fw, "#define ENABLE_ROUTING 1\n") 365 } 366 367 if !e.HasIpvlanDataPath() { 368 if e.RequireARPPassthrough() { 369 fmt.Fprint(fw, "#define ENABLE_ARP_PASSTHROUGH 1\n") 370 } else { 371 fmt.Fprint(fw, "#define ENABLE_ARP_RESPONDER 1\n") 372 } 373 374 fmt.Fprint(fw, "#define ENABLE_HOST_REDIRECT 1\n") 375 if option.Config.IsFlannelMasterDeviceSet() { 376 fmt.Fprint(fw, "#define HOST_REDIRECT_TO_INGRESS 1\n") 377 } 378 } 379 380 if e.ConntrackLocalLocked() { 381 ctmap.WriteBPFMacros(fw, e) 382 } else { 383 ctmap.WriteBPFMacros(fw, nil) 384 } 385 386 // Always enable L4 and L3 load balancer for now 387 fmt.Fprint(fw, "#define LB_L3 1\n") 388 fmt.Fprint(fw, "#define LB_L4 1\n") 389 390 // Local delivery metrics should always be set for endpoint programs. 391 fmt.Fprint(fw, "#define LOCAL_DELIVERY_METRICS 1\n") 392 393 l.writeNetdevConfig(fw, e) 394 395 return fw.Flush() 396 } 397 398 // WriteTemplateConfig writes the BPF configuration for the template to a writer. 399 func (l *linuxDatapath) WriteTemplateConfig(w io.Writer, e datapath.EndpointConfiguration) error { 400 fw := bufio.NewWriter(w) 401 return l.writeTemplateConfig(fw, e) 402 }