cregit-Linux how code gets into the kernel

Release 4.16 samples/bpf/xdp_router_ipv4_kern.c

Directory: samples/bpf
/* Copyright (C) 2017 Cavium, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License
 * as published by the Free Software Foundation.
 */

#define KBUILD_MODNAME "foo"
#include <uapi/linux/bpf.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include "bpf_helpers.h"
#include <linux/slab.h>
#include <net/ip_fib.h>


struct trie_value {
	
__u8 prefix[4];
	
__be64 value;
	
int ifindex;
	
int metric;
	
__be32 gw;
};

/* Key for lpm_trie*/

union key_4 {
	
u32 b32[2];
	
u8 b8[8];
};


struct arp_entry {
	
__be64 mac;
	
__be32 dst;
};


struct direct_map {
	
struct arp_entry arp;
	
int ifindex;
	
__be64 mac;
};

/* Map for trie implementation*/
struct bpf_map_def SEC("maps") lpm_map = {
	.type = BPF_MAP_TYPE_LPM_TRIE,
	.key_size = 8,
	.value_size = sizeof(struct trie_value),
	.max_entries = 50,
	.map_flags = BPF_F_NO_PREALLOC,
};

/* Map for counter*/
struct bpf_map_def SEC("maps") rxcnt = {
	.type = BPF_MAP_TYPE_PERCPU_ARRAY,
	.key_size = sizeof(u32),
	.value_size = sizeof(u64),
	.max_entries = 256,
};

/* Map for ARP table*/
struct bpf_map_def SEC("maps") arp_table = {
	.type = BPF_MAP_TYPE_HASH,
	.key_size = sizeof(__be32),
	.value_size = sizeof(__be64),
	.max_entries = 50,
};

/* Map to keep the exact match entries in the route table*/
struct bpf_map_def SEC("maps") exact_match = {
	.type = BPF_MAP_TYPE_HASH,
	.key_size = sizeof(__be32),
	.value_size = sizeof(struct direct_map),
	.max_entries = 50,
};

struct bpf_map_def SEC("maps") tx_port = {
	.type = BPF_MAP_TYPE_DEVMAP,
	.key_size = sizeof(int),
	.value_size = sizeof(int),
	.max_entries = 100,
};

/* Function to set source and destination mac of the packet */

static inline void set_src_dst_mac(void *data, void *src, void *dst) { unsigned short *source = src; unsigned short *dest = dst; unsigned short *p = data; __builtin_memcpy(p, dest, 6); __builtin_memcpy(p + 3, source, 6); }

Contributors

PersonTokensPropCommitsCommitProp
Christina Jacob60100.00%1100.00%
Total60100.00%1100.00%

/* Parse IPV4 packet to get SRC, DST IP and protocol */
static inline int parse_ipv4(void *data, u64 nh_off, void *data_end, __be32 *src, __be32 *dest) { struct iphdr *iph = data + nh_off; if (iph + 1 > data_end) return 0; *src = iph->saddr; *dest = iph->daddr; return iph->protocol; }

Contributors

PersonTokensPropCommitsCommitProp
Christina Jacob65100.00%1100.00%
Total65100.00%1100.00%

SEC("xdp_router_ipv4")
int xdp_router_ipv4_prog(struct xdp_md *ctx) { void *data_end = (void *)(long)ctx->data_end; __be64 *dest_mac = NULL, *src_mac = NULL; void *data = (void *)(long)ctx->data; struct trie_value *prefix_value; int rc = XDP_DROP, forward_to; struct ethhdr *eth = data; union key_4 key4; long *value; u16 h_proto; u32 ipproto; u64 nh_off; nh_off = sizeof(*eth); if (data + nh_off > data_end) return rc; h_proto = eth->h_proto; if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) { struct vlan_hdr *vhdr; vhdr = data + nh_off; nh_off += sizeof(struct vlan_hdr); if (data + nh_off > data_end) return rc; h_proto = vhdr->h_vlan_encapsulated_proto; } if (h_proto == htons(ETH_P_ARP)) { return XDP_PASS; } else if (h_proto == htons(ETH_P_IP)) { struct direct_map *direct_entry; __be32 src_ip = 0, dest_ip = 0; ipproto = parse_ipv4(data, nh_off, data_end, &src_ip, &dest_ip); direct_entry = bpf_map_lookup_elem(&exact_match, &dest_ip); /* Check for exact match, this would give a faster lookup*/ if (direct_entry && direct_entry->mac && direct_entry->arp.mac) { src_mac = &direct_entry->mac; dest_mac = &direct_entry->arp.mac; forward_to = direct_entry->ifindex; } else { /* Look up in the trie for lpm*/ key4.b32[0] = 32; key4.b8[4] = dest_ip & 0xff; key4.b8[5] = (dest_ip >> 8) & 0xff; key4.b8[6] = (dest_ip >> 16) & 0xff; key4.b8[7] = (dest_ip >> 24) & 0xff; prefix_value = bpf_map_lookup_elem(&lpm_map, &key4); if (!prefix_value) return XDP_DROP; src_mac = &prefix_value->value; if (!src_mac) return XDP_DROP; dest_mac = bpf_map_lookup_elem(&arp_table, &dest_ip); if (!dest_mac) { if (!prefix_value->gw) return XDP_DROP; dest_ip = prefix_value->gw; dest_mac = bpf_map_lookup_elem(&arp_table, &dest_ip); } forward_to = prefix_value->ifindex; } } else { ipproto = 0; } if (src_mac && dest_mac) { set_src_dst_mac(data, src_mac, dest_mac); value = bpf_map_lookup_elem(&rxcnt, &ipproto); if (value) *value += 1; return bpf_redirect_map(&tx_port, forward_to, 0); } return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Christina Jacob485100.00%1100.00%
Total485100.00%1100.00%

char _license[] SEC("license") = "GPL";

Overall Contributors

PersonTokensPropCommitsCommitProp
Christina Jacob916100.00%1100.00%
Total916100.00%1100.00%
Directory: samples/bpf
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.