github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/bpf/lib/l3.h (about)

     1  /*
     2   *  Copyright (C) 2016-2017 Authors of Cilium
     3   *
     4   *  This program is free software; you can redistribute it and/or modify
     5   *  it under the terms of the GNU General Public License as published by
     6   *  the Free Software Foundation; either version 2 of the License, or
     7   *  (at your option) any later version.
     8   *
     9   *  This program is distributed in the hope that it will be useful,
    10   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   *  GNU General Public License for more details.
    13   *
    14   *  You should have received a copy of the GNU General Public License
    15   *  along with this program; if not, write to the Free Software
    16   *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    17   */
    18  #ifndef __LIB_L3_H_
    19  #define __LIB_L3_H_
    20  
    21  #include "common.h"
    22  #include "ipv6.h"
    23  #include "ipv4.h"
    24  #include "eps.h"
    25  #include "eth.h"
    26  #include "dbg.h"
    27  #include "l4.h"
    28  #include "icmp6.h"
    29  #include "csum.h"
    30  
    31  #ifdef ENABLE_IPV6
    32  static inline int __inline__ ipv6_l3(struct __sk_buff *skb, int l3_off,
    33  				     __u8 *smac, __u8 *dmac, __u8 direction)
    34  {
    35  	int ret;
    36  
    37  	ret = ipv6_dec_hoplimit(skb, l3_off);
    38  	if (IS_ERR(ret))
    39  		return ret;
    40  
    41  	if (ret > 0) {
    42  		/* Hoplimit was reached */
    43  		return icmp6_send_time_exceeded(skb, l3_off, direction);
    44  	}
    45  
    46  	if (smac && eth_store_saddr(skb, smac, 0) < 0)
    47  		return DROP_WRITE_ERROR;
    48  
    49  	if (eth_store_daddr(skb, dmac, 0) < 0)
    50  		return DROP_WRITE_ERROR;
    51  
    52  	return TC_ACT_OK;
    53  }
    54  #endif /* ENABLE_IPV6 */
    55  
    56  static inline int __inline__ ipv4_l3(struct __sk_buff *skb, int l3_off,
    57  				     __u8 *smac, __u8 *dmac, struct iphdr *ip4)
    58  {
    59  	if (ipv4_dec_ttl(skb, l3_off, ip4)) {
    60  		/* FIXME: Send ICMP TTL */
    61  		return DROP_INVALID;
    62  	}
    63  
    64  	if (smac && eth_store_saddr(skb, smac, 0) < 0)
    65  		return DROP_WRITE_ERROR;
    66  
    67  	if (eth_store_daddr(skb, dmac, 0) < 0)
    68  		return DROP_WRITE_ERROR;
    69  
    70  	return TC_ACT_OK;
    71  }
    72  
    73  #ifdef ENABLE_IPV6
    74  static inline int ipv6_local_delivery(struct __sk_buff *skb, int l3_off, int l4_off,
    75  				      __u32 seclabel, struct ipv6hdr *ip6, __u8 nexthdr,
    76  				      struct endpoint_info *ep, __u8 direction)
    77  {
    78  	int ret;
    79  
    80  	cilium_dbg(skb, DBG_LOCAL_DELIVERY, ep->lxc_id, seclabel);
    81  
    82  	mac_t lxc_mac = ep->mac;
    83  	mac_t router_mac = ep->node_mac;
    84  
    85  	/* This will invalidate the size check */
    86  	ret = ipv6_l3(skb, l3_off, (__u8 *) &router_mac, (__u8 *) &lxc_mac, direction);
    87  	if (ret != TC_ACT_OK)
    88  		return ret;
    89  
    90  #if defined LOCAL_DELIVERY_METRICS
    91  	/*
    92  	 * Special LXC case for updating egress forwarding metrics.
    93  	 * Note that the packet could still be dropped but it would show up
    94  	 * as an ingress drop counter in metrics.
    95  	 */
    96  	update_metrics(skb->len, direction, REASON_FORWARDED);
    97  #endif
    98  
    99  #if defined USE_BPF_PROG_FOR_INGRESS_POLICY && !defined FORCE_LOCAL_POLICY_EVAL_AT_SOURCE
   100  	skb->mark = (seclabel << 16) | MARK_MAGIC_IDENTITY;
   101  	return redirect_peer(ep->ifindex, 0);
   102  #else
   103  	skb->cb[CB_SRC_LABEL] = seclabel;
   104  	skb->cb[CB_IFINDEX] = ep->ifindex;
   105  	tail_call(skb, &POLICY_CALL_MAP, ep->lxc_id);
   106  	return DROP_MISSED_TAIL_CALL;
   107  #endif
   108  }
   109  #endif /* ENABLE_IPV6 */
   110  
   111  static inline int __inline__ ipv4_local_delivery(struct __sk_buff *skb, int l3_off, int l4_off,
   112  						 __u32 seclabel, struct iphdr *ip4,
   113  						 struct endpoint_info *ep, __u8 direction)
   114  {
   115  	int ret;
   116  
   117  	cilium_dbg(skb, DBG_LOCAL_DELIVERY, ep->lxc_id, seclabel);
   118  
   119  	mac_t lxc_mac = ep->mac;
   120  	mac_t router_mac = ep->node_mac;
   121  
   122  	ret = ipv4_l3(skb, l3_off, (__u8 *) &router_mac, (__u8 *) &lxc_mac, ip4);
   123  	if (ret != TC_ACT_OK)
   124  		return ret;
   125  
   126  #if defined LOCAL_DELIVERY_METRICS
   127  	/*
   128  	 * Special LXC case for updating egress forwarding metrics.
   129  	 * Note that the packet could still be dropped but it would show up
   130  	 * as an ingress drop counter in metrics.
   131  	 */
   132  	update_metrics(skb->len, direction, REASON_FORWARDED);
   133  #endif
   134  
   135  #if defined USE_BPF_PROG_FOR_INGRESS_POLICY && !defined FORCE_LOCAL_POLICY_EVAL_AT_SOURCE
   136  	skb->mark = (seclabel << 16) | MARK_MAGIC_IDENTITY;
   137  	return redirect_peer(ep->ifindex, 0);
   138  #else
   139  	skb->cb[CB_SRC_LABEL] = seclabel;
   140  	skb->cb[CB_IFINDEX] = ep->ifindex;
   141  	tail_call(skb, &POLICY_CALL_MAP, ep->lxc_id);
   142  	return DROP_MISSED_TAIL_CALL;
   143  #endif
   144  }
   145  
   146  static inline __u8 __inline__ get_encrypt_key(__u32 ctx)
   147  {
   148  	struct encrypt_key key = {.ctx = ctx};
   149  	struct encrypt_config *cfg;
   150  
   151  	cfg = map_lookup_elem(&ENCRYPT_MAP, &key);
   152  	/* Having no key info for a context is the same as no encryption */
   153  	if (!cfg)
   154  		return 0;
   155  	return cfg->encrypt_key;
   156  }
   157  
   158  static inline __u8 __inline__ get_min_encrypt_key(__u8 peer_key)
   159  {
   160  	__u8 local_key = get_encrypt_key(0);
   161  
   162  	/* If both ends can encrypt/decrypt use smaller of the two this
   163  	 * way both ends will have keys installed assuming key IDs are
   164  	 * always increasing. However, we have to handle roll-over case
   165  	 * and to do this safely we assume keys are no more than one ahead.
   166  	 * We expect user/control-place to accomplish this. Notice zero
   167  	 * will always be returned if either local or peer have the zero
   168  	 * key indicating no encryption.
   169  	 */
   170  	if (peer_key == MAX_KEY_INDEX)
   171  		return local_key == 1 ? peer_key : local_key;
   172  	if (local_key == MAX_KEY_INDEX)
   173  		return peer_key == 1 ? local_key : peer_key;
   174  	return local_key < peer_key ? local_key : peer_key;
   175  }
   176  
   177  #endif