github.com/imran-kn/cilium-fork@v1.6.9/bpf/bpf_xdp.c (about)

     1  /*
     2   *  Copyright (C) 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  #define SKIP_CALLS_MAP
    19  
    20  #include <node_config.h>
    21  #include <netdev_config.h>
    22  #include <filter_config.h>
    23  
    24  #include <bpf/api.h>
    25  
    26  #include <stdint.h>
    27  #include <stdio.h>
    28  
    29  #include <linux/bpf.h>
    30  #include <linux/if_ether.h>
    31  
    32  #include "lib/utils.h"
    33  #include "lib/common.h"
    34  #include "lib/maps.h"
    35  #include "lib/xdp.h"
    36  #include "lib/eps.h"
    37  #include "lib/events.h"
    38  
    39  #ifndef HAVE_LPM_MAP_TYPE
    40  # undef CIDR4_LPM_PREFILTER
    41  # undef CIDR6_LPM_PREFILTER
    42  #endif
    43  
    44  #ifdef CIDR4_FILTER
    45  struct bpf_elf_map __section_maps CIDR4_HMAP_NAME = {
    46  	.type		= BPF_MAP_TYPE_HASH,
    47  	.size_key	= sizeof(struct lpm_v4_key),
    48  	.size_value	= sizeof(struct lpm_val),
    49  	.flags		= BPF_F_NO_PREALLOC,
    50  	.pinning	= PIN_GLOBAL_NS,
    51  	.max_elem	= CIDR4_HMAP_ELEMS,
    52  };
    53  
    54  #ifdef CIDR4_LPM_PREFILTER
    55  struct bpf_elf_map __section_maps CIDR4_LMAP_NAME = {
    56  	.type		= BPF_MAP_TYPE_LPM_TRIE,
    57  	.size_key	= sizeof(struct lpm_v4_key),
    58  	.size_value	= sizeof(struct lpm_val),
    59  	.flags		= BPF_F_NO_PREALLOC,
    60  	.pinning	= PIN_GLOBAL_NS,
    61  	.max_elem	= CIDR4_LMAP_ELEMS,
    62  };
    63  #endif /* CIDR4_LPM_PREFILTER */
    64  #endif /* CIDR4_FILTER */
    65  
    66  #ifdef CIDR6_FILTER
    67  struct bpf_elf_map __section_maps CIDR6_HMAP_NAME = {
    68  	.type		= BPF_MAP_TYPE_HASH,
    69  	.size_key	= sizeof(struct lpm_v6_key),
    70  	.size_value	= sizeof(struct lpm_val),
    71  	.flags		= BPF_F_NO_PREALLOC,
    72  	.pinning	= PIN_GLOBAL_NS,
    73  	.max_elem	= CIDR4_HMAP_ELEMS,
    74  };
    75  
    76  #ifdef CIDR6_LPM_PREFILTER
    77  struct bpf_elf_map __section_maps CIDR6_LMAP_NAME = {
    78  	.type		= BPF_MAP_TYPE_LPM_TRIE,
    79  	.size_key	= sizeof(struct lpm_v6_key),
    80  	.size_value	= sizeof(struct lpm_val),
    81  	.flags		= BPF_F_NO_PREALLOC,
    82  	.pinning	= PIN_GLOBAL_NS,
    83  	.max_elem	= CIDR4_LMAP_ELEMS,
    84  };
    85  #endif /* CIDR6_LPM_PREFILTER */
    86  #endif /* CIDR6_FILTER */
    87  
    88  static __always_inline int check_v4_endpoint(struct xdp_md *xdp,
    89  					     struct iphdr *ipv4_hdr)
    90  {
    91  	if (lookup_ip4_endpoint(ipv4_hdr))
    92  		return XDP_PASS;
    93  
    94  	return XDP_DROP;
    95  }
    96  
    97  static __always_inline int check_v4(struct xdp_md *xdp)
    98  {
    99  	void *data_end = xdp_data_end(xdp);
   100  	void *data = xdp_data(xdp);
   101  	struct iphdr *ipv4_hdr = data + sizeof(struct ethhdr);
   102  	struct lpm_v4_key pfx __maybe_unused;
   103  
   104  	if (xdp_no_room(ipv4_hdr + 1, data_end))
   105  		return XDP_DROP;
   106  
   107  #ifdef CIDR4_FILTER
   108  	__builtin_memcpy(pfx.lpm.data, &ipv4_hdr->saddr, sizeof(pfx.addr));
   109  	pfx.lpm.prefixlen = 32;
   110  
   111  #ifdef CIDR4_LPM_PREFILTER
   112  	if (map_lookup_elem(&CIDR4_LMAP_NAME, &pfx))
   113  		return XDP_DROP;
   114  	else
   115  #endif /* CIDR4_LPM_PREFILTER */
   116  		return map_lookup_elem(&CIDR4_HMAP_NAME, &pfx) ?
   117  		       XDP_DROP : check_v4_endpoint(xdp, ipv4_hdr);
   118  #else
   119  	return check_v4_endpoint(xdp, ipv4_hdr);
   120  #endif /* CIDR4_FILTER */
   121  }
   122  
   123  static __always_inline int check_v6_endpoint(struct xdp_md *xdp,
   124  					     struct ipv6hdr *ipv6_hdr)
   125  {
   126  	if (lookup_ip6_endpoint(ipv6_hdr))
   127  		return XDP_PASS;
   128  
   129  	return XDP_DROP;
   130  }
   131  
   132  static __always_inline int check_v6(struct xdp_md *xdp)
   133  {
   134  	void *data_end = xdp_data_end(xdp);
   135  	void *data = xdp_data(xdp);
   136  	struct ipv6hdr *ipv6_hdr = data + sizeof(struct ethhdr);
   137  	struct lpm_v6_key pfx __maybe_unused;
   138  
   139  	if (xdp_no_room(ipv6_hdr + 1, data_end))
   140  		return XDP_DROP;
   141  
   142  #ifdef CIDR6_FILTER
   143  	__builtin_memcpy(pfx.lpm.data, &ipv6_hdr->saddr, sizeof(pfx.addr));
   144  	pfx.lpm.prefixlen = 128;
   145  
   146  #ifdef CIDR6_LPM_PREFILTER
   147  	if (map_lookup_elem(&CIDR6_LMAP_NAME, &pfx))
   148  		return XDP_DROP;
   149  	else
   150  #endif /* CIDR6_LPM_PREFILTER */
   151  		return map_lookup_elem(&CIDR6_HMAP_NAME, &pfx) ?
   152  		       XDP_DROP : check_v6_endpoint(xdp, ipv6_hdr);
   153  #else
   154  	return check_v6_endpoint(xdp, ipv6_hdr);
   155  #endif /* CIDR6_FILTER */
   156  }
   157  
   158  static __always_inline int check_filters(struct xdp_md *xdp)
   159  {
   160  	void *data_end = xdp_data_end(xdp);
   161  	void *data = xdp_data(xdp);
   162  	struct ethhdr *eth = data;
   163  	__u16 proto;
   164  
   165  	if (xdp_no_room(eth + 1, data_end))
   166  		return XDP_DROP;
   167  
   168  	proto = eth->h_proto;
   169  	if (proto == bpf_htons(ETH_P_IP))
   170  		return check_v4(xdp);
   171  	else if (proto == bpf_htons(ETH_P_IPV6))
   172  		return check_v6(xdp);
   173  	else
   174  		/* Pass the rest to stack, we might later do more
   175  		 * fine-grained filtering here.
   176  		 */
   177  		return XDP_PASS;
   178  }
   179  
   180  __section("from-netdev")
   181  int xdp_start(struct xdp_md *xdp)
   182  {
   183  	return check_filters(xdp);
   184  }
   185  
   186  BPF_LICENSE("GPL");