github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/datapath/loader/template.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 loader 16 17 import ( 18 "fmt" 19 "reflect" 20 21 "github.com/cilium/cilium/common/addressing" 22 "github.com/cilium/cilium/pkg/bpf" 23 "github.com/cilium/cilium/pkg/byteorder" 24 "github.com/cilium/cilium/pkg/datapath" 25 "github.com/cilium/cilium/pkg/identity" 26 "github.com/cilium/cilium/pkg/mac" 27 bpfconfig "github.com/cilium/cilium/pkg/maps/configmap" 28 "github.com/cilium/cilium/pkg/maps/ctmap" 29 "github.com/cilium/cilium/pkg/maps/policymap" 30 ) 31 32 var ( 33 TemplateSecurityID = identity.ReservedIdentityWorld 34 TemplateLxcID = uint16(65535) 35 TemplateMAC = mac.MAC([]byte{0x02, 0x00, 0x60, 0x0D, 0xF0, 0x0D}) 36 TemplateIPv4 = []byte{192, 0, 2, 3} 37 TemplateIPv6 = []byte{0x20, 0x01, 0xdb, 0x8, 0x0b, 0xad, 0xca, 0xfe, 0x60, 0x0d, 0xbe, 0xe2, 0x0b, 0xad, 0xca, 0xfe} 38 39 CallsMapName = "cilium_calls_" 40 elfMapPrefixes = []string{ 41 policymap.MapName, 42 CallsMapName, 43 bpfconfig.MapNamePrefix, 44 } 45 elfCtMapPrefixes = []string{ 46 ctmap.MapNameTCP4, 47 ctmap.MapNameAny4, 48 ctmap.MapNameTCP6, 49 ctmap.MapNameAny6, 50 } 51 ) 52 53 // templateCfg wraps a real configuration from an endpoint to pass through its 54 // configuration of conditional branches in the datapath, but to mock out dummy 55 // values for static data. 56 // 57 // Note that the static data dummy values must be non-zero in every 32-bit 58 // section of the data to ensure that during compilation, the compiler reserves 59 // space in the .data section of the ELF for the value of the data, rather than 60 // generating a reference to the .bss section (which is what it will typically 61 // do if a static integer is initialized to zero). 62 // 63 // Ideally we also statically configure the values used in the template in such 64 // a way that if ever someone managed to inadvertently attach the template 65 // program directly to a device, that there are no unintended consequences such 66 // as allowing traffic to leak out with routable addresses. 67 type templateCfg struct { 68 datapath.EndpointConfiguration 69 stats *SpanStat 70 } 71 72 // GetID returns a uint64, but in practice on the datapath side it is 73 // guaranteed to be 16-bit; it is used to generate map names, so we need to 74 // ensure that the template generates map names that are as long as the longest 75 // possible name, which would be guaranteed with a 5-digit output. 76 // 77 // In practice, attempts to load an endpoint with the ID 65535 will fail which 78 // means that the calling code must approprately substitute the ID in the ELF 79 // prior to load, or it will fail with a relatively obvious error. 80 func (t *templateCfg) GetID() uint64 { 81 return uint64(TemplateLxcID) 82 } 83 84 // StringID returns the string form of the ID returned by GetID(). 85 func (t *templateCfg) StringID() string { 86 return fmt.Sprintf("%d", t.GetID()) 87 } 88 89 // GetIdentity treats the template program as part of the world, so if there's 90 // ever some weird bug that causes the template value here to be used, it will 91 // be in the least privileged security context. 92 func (t *templateCfg) GetIdentity() identity.NumericIdentity { 93 return TemplateSecurityID 94 } 95 96 // GetNodeMAC returns a well-known dummy MAC address which may be later 97 // substituted in the ELF. 98 func (t *templateCfg) GetNodeMAC() mac.MAC { 99 return TemplateMAC 100 } 101 102 // IPv4Address always returns an IP in the documentation prefix (RFC5737) as 103 // a nonsense address that should typically not be routable. 104 func (t *templateCfg) IPv4Address() addressing.CiliumIPv4 { 105 return addressing.CiliumIPv4(TemplateIPv4) 106 } 107 108 // IPv6Address returns an IP in the documentation prefix (RFC3849) to ensure 109 // that each 32-bit segment of the address is non-zero as per the requirements 110 // described in the structure definition. This can't be guaranteed while using 111 // a more appropriate prefix such as the discard prefix (RFC6666). 112 func (t *templateCfg) IPv6Address() addressing.CiliumIPv6 { 113 return addressing.CiliumIPv6(TemplateIPv6) 114 } 115 116 // wrap takes an endpoint configuration and optional stats tracker and wraps 117 // it inside a templateCfg which hides static data from callers that wish to 118 // generate header files based on the configuration, substituting it for 119 // template data. 120 func wrap(cfg datapath.EndpointConfiguration, stats *SpanStat) *templateCfg { 121 if stats == nil { 122 stats = &SpanStat{} 123 } 124 return &templateCfg{ 125 EndpointConfiguration: cfg, 126 stats: stats, 127 } 128 } 129 130 // elfMapSubstitutions returns the set of map substitutions that must occur in 131 // an ELF template object file to update map references for the specified 132 // endpoint. 133 func elfMapSubstitutions(ep endpoint) map[string]string { 134 result := make(map[string]string) 135 136 epID := uint16(ep.GetID()) 137 for _, name := range elfMapPrefixes { 138 templateStr := bpf.LocalMapName(name, TemplateLxcID) 139 desiredStr := bpf.LocalMapName(name, epID) 140 result[templateStr] = desiredStr 141 } 142 if ep.ConntrackLocalLocked() { 143 for _, name := range elfCtMapPrefixes { 144 templateStr := bpf.LocalMapName(name, TemplateLxcID) 145 desiredStr := bpf.LocalMapName(name, epID) 146 result[templateStr] = desiredStr 147 } 148 } 149 150 result[policymap.CallString(TemplateLxcID)] = policymap.CallString(epID) 151 return result 152 } 153 154 // sliceToU16 converts the input slice of two bytes to a uint16. 155 func sliceToU16(input []byte) uint16 { 156 result := uint16(input[0]) << 8 157 result |= uint16(input[1]) 158 return result 159 } 160 161 // sliceToBe16 converts the input slice of two bytes to a big-endian uint16. 162 func sliceToBe16(input []byte) uint16 { 163 return byteorder.HostToNetwork(sliceToU16(input)).(uint16) 164 } 165 166 // sliceToU32 converts the input slice of four bytes to a uint32. 167 func sliceToU32(input []byte) uint32 { 168 result := uint32(input[0]) << 24 169 result |= uint32(input[1]) << 16 170 result |= uint32(input[2]) << 8 171 result |= uint32(input[3]) 172 return result 173 } 174 175 // sliceToBe32 converts the input slice of four bytes to a big-endian uint32. 176 func sliceToBe32(input []byte) uint32 { 177 return byteorder.HostToNetwork(sliceToU32(input)).(uint32) 178 } 179 180 // elfVariableSubstitutions returns the set of data substitutions that must 181 // occur in an ELF template object file to update static data for the specified 182 // endpoint. 183 func elfVariableSubstitutions(ep endpoint) map[string]uint32 { 184 result := make(map[string]uint32) 185 186 if ipv6 := ep.IPv6Address(); ipv6 != nil { 187 // Corresponds to DEFINE_IPV6() in bpf/lib/utils.h 188 result["LXC_IP_1"] = sliceToBe32(ipv6[0:4]) 189 result["LXC_IP_2"] = sliceToBe32(ipv6[4:8]) 190 result["LXC_IP_3"] = sliceToBe32(ipv6[8:12]) 191 result["LXC_IP_4"] = sliceToBe32(ipv6[12:16]) 192 } 193 if ipv4 := ep.IPv4Address(); ipv4 != nil { 194 result["LXC_IPV4"] = byteorder.HostSliceToNetwork(ipv4, reflect.Uint32).(uint32) 195 } 196 197 mac := ep.GetNodeMAC() 198 result["NODE_MAC_1"] = sliceToBe32(mac[0:4]) 199 result["NODE_MAC_2"] = uint32(sliceToBe16(mac[4:6])) 200 result["LXC_ID"] = uint32(ep.GetID()) 201 identity := ep.GetIdentity().Uint32() 202 result["SECLABEL"] = identity 203 result["SECLABEL_NB"] = byteorder.HostToNetwork(identity).(uint32) 204 205 return result 206 207 } 208 209 // ELFSubstitutions fetches the set of variable and map substitutions that 210 // must be implemented against an ELF template to configure the datapath for 211 // the specified endpoint. 212 func ELFSubstitutions(ep endpoint) (map[string]uint32, map[string]string) { 213 return elfVariableSubstitutions(ep), elfMapSubstitutions(ep) 214 }