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  }