github.com/cilium/cilium@v1.16.2/bpf/lib/identity.h (about) 1 /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 /* Copyright Authors of Cilium */ 3 4 #pragma once 5 6 #include "dbg.h" 7 8 static __always_inline bool identity_in_range(__u32 identity, __u32 range_start, __u32 range_end) 9 { 10 return range_start <= identity && identity <= range_end; 11 } 12 13 #define IDENTITY_LOCAL_SCOPE_MASK 0xFF000000 14 #define IDENTITY_LOCAL_SCOPE_REMOTE_NODE 0x02000000 15 16 static __always_inline bool identity_is_host(__u32 identity) 17 { 18 return identity == HOST_ID; 19 } 20 21 static __always_inline bool identity_is_remote_node(__u32 identity) 22 { 23 /* KUBE_APISERVER_NODE_ID is the reserved identity that corresponds to 24 * the labels 'reserved:remote-node' and 'reserved:kube-apiserver'. As 25 * such, if it is ever used for determining the identity of a node in 26 * the cluster, then routing decisions and so on should be made the 27 * same way as for REMOTE_NODE_ID. If we ever assign unique identities 28 * to each node in the cluster, then we'll probably need to convert 29 * the implementation here into a map to select any of the possible 30 * identities. But for now, this is good enough to capture the notion 31 * of 'remote nodes in the cluster' for routing decisions. 32 * 33 * Remote nodes may also have, instead, an identity allocated from the 34 * remote node identity scope, which is identified by the top 8 bits 35 * being 0x02. 36 * 37 * Note that kube-apiserver policy is handled entirely separately by 38 * the standard policymap enforcement logic and has no relationship to 39 * the identity as used here. If the apiserver is outside the cluster, 40 * then the KUBE_APISERVER_NODE_ID case should not ever be hit. 41 */ 42 return identity == REMOTE_NODE_ID || 43 identity == KUBE_APISERVER_NODE_ID || 44 (identity & IDENTITY_LOCAL_SCOPE_MASK) == IDENTITY_LOCAL_SCOPE_REMOTE_NODE; 45 } 46 47 static __always_inline bool identity_is_node(__u32 identity) 48 { 49 return identity_is_host(identity) || identity_is_remote_node(identity); 50 } 51 52 /** 53 * identity_is_reserved is used to determine whether an identity is one of the 54 * reserved identities that are not handed out to endpoints. 55 * 56 * Specifically, it should return true if the identity is one of these: 57 * - IdentityUnknown 58 * - ReservedIdentityHost 59 * - ReservedIdentityWorld 60 * - ReservedIdentityWorldIPv4 61 * - ReservedIdentityWorldIPv6 62 * - ReservedIdentityRemoteNode 63 * - ReservedIdentityKubeAPIServer 64 * 65 * The following identities are given to endpoints so return false for these: 66 * - ReservedIdentityUnmanaged 67 * - ReservedIdentityHealth 68 * - ReservedIdentityInit 69 * 70 * Identities 128 and higher are guaranteed to be generated based on user input. 71 */ 72 static __always_inline bool identity_is_reserved(__u32 identity) 73 { 74 #if defined ENABLE_IPV4 && defined ENABLE_IPV6 75 return identity < UNMANAGED_ID || identity_is_remote_node(identity) || 76 identity == WORLD_IPV4_ID || identity == WORLD_IPV6_ID; 77 #else 78 return identity < UNMANAGED_ID || identity_is_remote_node(identity); 79 #endif 80 } 81 82 /** 83 * identity_is_world_ipv4 is used to determine whether an identity is the world-ipv4 84 * reserved identity. 85 * 86 * Specifically, it should return true if the identity is one of these: 87 * - ReservedIdentityWorld 88 * - ReservedIdentityWorldIPv4 89 */ 90 static __always_inline bool identity_is_world_ipv4(__u32 identity) 91 { 92 #if defined ENABLE_IPV4 && defined ENABLE_IPV6 93 return identity == WORLD_ID || identity == WORLD_IPV4_ID; 94 #else 95 return identity == WORLD_ID; 96 #endif 97 } 98 99 /** 100 * identity_is_world_ipv6 is used to determine whether an identity is the world-ipv6 101 * reserved identity. 102 * 103 * Specifically, it should return true if the identity is one of these: 104 * - ReservedIdentityWorld 105 * - ReservedIdentityWorldIPv6 106 */ 107 static __always_inline bool identity_is_world_ipv6(__u32 identity) 108 { 109 #if defined ENABLE_IPV4 && defined ENABLE_IPV6 110 return identity == WORLD_ID || identity == WORLD_IPV6_ID; 111 #else 112 return identity == WORLD_ID; 113 #endif 114 } 115 116 /** 117 * identity_is_cidr_range is used to determine whether an identity is assigned 118 * to a CIDR range. 119 */ 120 static __always_inline bool identity_is_cidr_range(__u32 identity) 121 { 122 return identity_in_range(identity, CIDR_IDENTITY_RANGE_START, CIDR_IDENTITY_RANGE_END); 123 } 124 125 /** 126 * identity_is_cluster is used to determine whether an identity is assigned to 127 * an entity inside the cluster. 128 * 129 * This function will return false for: 130 * - ReservedIdentityWorld 131 * - ReservedIdentityWorldIPv4 132 * - ReservedIdentityWorldIPv6 133 * - an identity in the CIDR range 134 * 135 * This function will return true for: 136 * - ReservedIdentityHost 137 * - ReservedIdentityUnmanaged 138 * - ReservedIdentityHealth 139 * - ReservedIdentityInit 140 * - ReservedIdentityRemoteNode 141 * - ReservedIdentityKubeAPIServer 142 * - ReservedIdentityIngress 143 * - all other identifies 144 */ 145 static __always_inline bool identity_is_cluster(__u32 identity) 146 { 147 #if defined ENABLE_IPV4 && defined ENABLE_IPV6 148 if (identity == WORLD_ID || identity == WORLD_IPV4_ID || identity == WORLD_IPV6_ID) 149 return false; 150 #else 151 if (identity == WORLD_ID) 152 return false; 153 #endif 154 155 if (identity_is_cidr_range(identity)) 156 return false; 157 158 return true; 159 } 160 161 #if __ctx_is == __ctx_skb 162 static __always_inline __u32 inherit_identity_from_host(struct __ctx_buff *ctx, __u32 *identity) 163 { 164 __u32 magic = ctx->mark & MARK_MAGIC_HOST_MASK; 165 166 /* Packets from the ingress proxy must skip the proxy when the 167 * destination endpoint evaluates the policy. As the packet would loop 168 * and/or the connection be reset otherwise. 169 */ 170 if (magic == MARK_MAGIC_PROXY_INGRESS) { 171 *identity = get_identity(ctx); 172 ctx->tc_index |= TC_INDEX_F_FROM_INGRESS_PROXY; 173 /* (Return) packets from the egress proxy must skip the redirection to 174 * the proxy, as the packet would loop and/or the connection be reset 175 * otherwise. 176 */ 177 } else if (magic == MARK_MAGIC_PROXY_EGRESS) { 178 *identity = get_identity(ctx); 179 ctx->tc_index |= TC_INDEX_F_FROM_EGRESS_PROXY; 180 } else if (magic == MARK_MAGIC_IDENTITY) { 181 *identity = get_identity(ctx); 182 } else if (magic == MARK_MAGIC_HOST) { 183 *identity = HOST_ID; 184 } else if (magic == MARK_MAGIC_ENCRYPT) { 185 *identity = ctx_load_meta(ctx, CB_ENCRYPT_IDENTITY); 186 187 /* Special case needed to handle upgrades. Can be removed in v1.15. 188 * Before the upgrade, bpf_lxc will write the tunnel endpoint in 189 * skb->cb[4]. After the upgrade, it will write the security identity. 190 * For the upgrade to happen without drops, bpf_host thus needs to 191 * handle both cases. 192 * We can distinguish between the two cases by looking at the first 193 * byte. Identities are on 24-bits so the first byte will be zero; 194 * conversely, tunnel endpoint addresses within the range 0.0.0.0/8 195 * (first byte is zero) are impossible because special purpose 196 * (RFC6890). 197 */ 198 if ((*identity & 0xFF000000) != 0) { 199 /* skb->cb[4] was actually carrying the tunnel endpoint and the 200 * security identity is in the mark. 201 */ 202 *identity = get_identity(ctx); 203 } 204 #if defined(ENABLE_L7_LB) 205 } else if (magic == MARK_MAGIC_PROXY_EGRESS_EPID) { 206 *identity = get_epid(ctx); /* endpoint identity, not security identity! */ 207 #endif 208 } else { 209 #if defined ENABLE_IPV4 && defined ENABLE_IPV6 210 __u16 proto = ctx_get_protocol(ctx); 211 212 if (proto == bpf_htons(ETH_P_IP)) 213 *identity = WORLD_IPV4_ID; 214 else if (proto == bpf_htons(ETH_P_IPV6)) 215 *identity = WORLD_IPV6_ID; 216 else 217 *identity = WORLD_ID; 218 #else 219 *identity = WORLD_ID; 220 #endif 221 } 222 223 /* Reset packet mark to avoid hitting routing rules again */ 224 ctx->mark = 0; 225 226 #if defined(ENABLE_L7_LB) 227 /* Caller tail calls back to source endpoint egress in this case, 228 * do not log the (world) identity. 229 */ 230 if (magic != MARK_MAGIC_PROXY_EGRESS_EPID) 231 #endif 232 cilium_dbg(ctx, DBG_INHERIT_IDENTITY, *identity, 0); 233 234 return magic; 235 } 236 #endif /* __ctx_is == __ctx_skb */ 237 238 /** 239 * identity_is_local is used to determine whether an identity is locally 240 * allocated. 241 */ 242 static __always_inline bool identity_is_local(__u32 identity) 243 { 244 return (identity & IDENTITY_LOCAL_SCOPE_MASK) != 0; 245 }