diff options
Diffstat (limited to 'src/xdp/xdp_prog_kern.c')
-rw-r--r-- | src/xdp/xdp_prog_kern.c | 347 |
1 files changed, 0 insertions, 347 deletions
diff --git a/src/xdp/xdp_prog_kern.c b/src/xdp/xdp_prog_kern.c deleted file mode 100644 index 59308325d..000000000 --- a/src/xdp/xdp_prog_kern.c +++ /dev/null @@ -1,347 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include <linux/bpf.h> -#include <linux/in.h> -#include <bpf/bpf_helpers.h> -#include <bpf/bpf_endian.h> - -// The parsing helper functions from the packet01 lesson have moved here -#include "common/parsing_helpers.h" -#include "common/rewrite_helpers.h" - -/* Defines xdp_stats_map */ -#include "common/xdp_stats_kern_user.h" -#include "common/xdp_stats_kern.h" - -#ifndef memcpy -#define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n)) -#endif - -struct { - __uint(type, BPF_MAP_TYPE_DEVMAP); - __type(key, int); - __type(value, int); - __uint(max_entries, 256); -} tx_port SEC(".maps"); - -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __type(key, ETH_ALEN); - __type(value, ETH_ALEN); - __uint(max_entries, 1); -} redirect_params SEC(".maps"); - -static __always_inline __u16 csum_fold_helper(__u32 csum) -{ - return ~((csum & 0xffff) + (csum >> 16)); -} - -/* - * The icmp_checksum_diff function takes pointers to old and new structures and - * the old checksum and returns the new checksum. It uses the bpf_csum_diff - * helper to compute the checksum difference. Note that the sizes passed to the - * bpf_csum_diff helper should be multiples of 4, as it operates on 32-bit - * words. - */ -static __always_inline __u16 icmp_checksum_diff( - __u16 seed, - struct icmphdr_common *icmphdr_new, - struct icmphdr_common *icmphdr_old) -{ - __u32 csum, size = sizeof(struct icmphdr_common); - - csum = bpf_csum_diff((__be32 *)icmphdr_old, size, (__be32 *)icmphdr_new, size, seed); - return csum_fold_helper(csum); -} - -/* Solution to packet03/assignment-1 */ -SEC("xdp_icmp_echo") -int xdp_icmp_echo_func(struct xdp_md *ctx) -{ - void *data_end = (void *)(long)ctx->data_end; - void *data = (void *)(long)ctx->data; - struct hdr_cursor nh; - struct ethhdr *eth; - int eth_type; - int ip_type; - int icmp_type; - struct iphdr *iphdr; - struct ipv6hdr *ipv6hdr; - __u16 echo_reply, old_csum; - struct icmphdr_common *icmphdr; - struct icmphdr_common icmphdr_old; - __u32 action = XDP_PASS; - - /* These keep track of the next header type and iterator pointer */ - nh.pos = data; - - /* Parse Ethernet and IP/IPv6 headers */ - eth_type = parse_ethhdr(&nh, data_end, ð); - if (eth_type == bpf_htons(ETH_P_IP)) { - ip_type = parse_iphdr(&nh, data_end, &iphdr); - if (ip_type != IPPROTO_ICMP) - goto out; - } else if (eth_type == bpf_htons(ETH_P_IPV6)) { - ip_type = parse_ip6hdr(&nh, data_end, &ipv6hdr); - if (ip_type != IPPROTO_ICMPV6) - goto out; - } else { - goto out; - } - - /* - * We are using a special parser here which returns a stucture - * containing the "protocol-independent" part of an ICMP or ICMPv6 - * header. For purposes of this Assignment we are not interested in - * the rest of the structure. - */ - icmp_type = parse_icmphdr_common(&nh, data_end, &icmphdr); - if (eth_type == bpf_htons(ETH_P_IP) && icmp_type == ICMP_ECHO) { - /* Swap IP source and destination */ - swap_src_dst_ipv4(iphdr); - echo_reply = ICMP_ECHOREPLY; - } else if (eth_type == bpf_htons(ETH_P_IPV6) - && icmp_type == ICMPV6_ECHO_REQUEST) { - /* Swap IPv6 source and destination */ - swap_src_dst_ipv6(ipv6hdr); - echo_reply = ICMPV6_ECHO_REPLY; - } else { - goto out; - } - - /* Swap Ethernet source and destination */ - swap_src_dst_mac(eth); - - - /* Patch the packet and update the checksum.*/ - old_csum = icmphdr->cksum; - icmphdr->cksum = 0; - icmphdr_old = *icmphdr; - icmphdr->type = echo_reply; - icmphdr->cksum = icmp_checksum_diff(~old_csum, icmphdr, &icmphdr_old); - - /* Another, less generic, but a bit more efficient way to update the - * checksum is listed below. As only one 16-bit word changed, the sum - * can be patched using this formula: sum' = ~(~sum + ~m0 + m1), where - * sum' is a new sum, sum is an old sum, m0 and m1 are the old and new - * 16-bit words, correspondingly. In the formula above the + operation - * is defined as the following function: - * - * static __always_inline __u16 csum16_add(__u16 csum, __u16 addend) - * { - * csum += addend; - * return csum + (csum < addend); - * } - * - * So an alternative code to update the checksum might look like this: - * - * __u16 m0 = * (__u16 *) icmphdr; - * icmphdr->type = echo_reply; - * __u16 m1 = * (__u16 *) icmphdr; - * icmphdr->checksum = ~(csum16_add(csum16_add(~icmphdr->checksum, ~m0), m1)); - */ - - action = XDP_TX; - -out: - return xdp_stats_record_action(ctx, action); -} - -/* Solution to packet03/assignment-2 */ -SEC("xdp_redirect") -int xdp_redirect_func(struct xdp_md *ctx) -{ - void *data_end = (void *)(long)ctx->data_end; - void *data = (void *)(long)ctx->data; - struct hdr_cursor nh; - struct ethhdr *eth; - int eth_type; - int action = XDP_PASS; - unsigned char dst[ETH_ALEN] = { /* TODO: put your values here */ }; - unsigned ifindex = 0/* TODO: put your values here */; - - /* These keep track of the next header type and iterator pointer */ - nh.pos = data; - - /* Parse Ethernet and IP/IPv6 headers */ - eth_type = parse_ethhdr(&nh, data_end, ð); - if (eth_type == -1) - goto out; - - /* Set a proper destination address */ - memcpy(eth->h_dest, dst, ETH_ALEN); - action = bpf_redirect(ifindex, 0); - -out: - return xdp_stats_record_action(ctx, action); -} - -/* Solution to packet03/assignment-3 */ -SEC("xdp_redirect_map") -int xdp_redirect_map_func(struct xdp_md *ctx) -{ - void *data_end = (void *)(long)ctx->data_end; - void *data = (void *)(long)ctx->data; - struct hdr_cursor nh; - struct ethhdr *eth; - int eth_type; - int action = XDP_PASS; - unsigned char *dst; - - /* These keep track of the next header type and iterator pointer */ - nh.pos = data; - - /* Parse Ethernet and IP/IPv6 headers */ - eth_type = parse_ethhdr(&nh, data_end, ð); - if (eth_type == -1) - goto out; - - /* Do we know where to redirect this packet? */ - dst = bpf_map_lookup_elem(&redirect_params, eth->h_source); - if (!dst) - goto out; - - /* Set a proper destination address */ - memcpy(eth->h_dest, dst, ETH_ALEN); - action = bpf_redirect_map(&tx_port, 0, 0); - -out: - return xdp_stats_record_action(ctx, action); -} - -#ifndef AF_INET -#define AF_INET 2 -#endif -#ifndef AF_INET6 -#define AF_INET6 10 -#endif -#define IPV6_FLOWINFO_MASK bpf_htonl(0x0FFFFFFF) - -/* from include/net/ip.h */ -static __always_inline int ip_decrease_ttl(struct iphdr *iph) -{ - __u32 check = iph->check; - check += bpf_htons(0x0100); - iph->check = (__u16)(check + (check >= 0xFFFF)); - return --iph->ttl; -} - -/* Solution to packet03/assignment-4 */ -/* xdp_router is the name of the xdp program */ -SEC("xdp_router") -int xdp_router_func(struct xdp_md *ctx) -{ - /* this is the packet context*/ - void *data_end = (void *)(long)ctx->data_end; - void *data = (void *)(long)ctx->data; - struct bpf_fib_lookup fib_params = {}; - struct ethhdr *eth = data; - struct ipv6hdr *ip6h; - struct iphdr *iph; - __u16 h_proto; - __u64 nh_off; - int rc; - /* default action is to pass */ - int action = XDP_PASS; - - nh_off = sizeof(*eth); - if (data + nh_off > data_end) { - action = XDP_DROP; - goto out; - } - - /* determine if this is IP4 or IPv6 by looking at the Ethernet protocol field */ - h_proto = eth->h_proto; - if (h_proto == bpf_htons(ETH_P_IP)) { - /* IPv4 part of the code */ - iph = data + nh_off; - - if (iph + 1 > data_end) { - action = XDP_DROP; - goto out; - } - /* as a real router, we need to check the TTL to prevent never ending loops*/ - if (iph->ttl <= 1) - goto out; - - /* populate the fib_params fields to prepare for the lookup */ - fib_params.family = AF_INET; - fib_params.tos = iph->tos; - fib_params.l4_protocol = iph->protocol; - fib_params.sport = 0; - fib_params.dport = 0; - fib_params.tot_len = bpf_ntohs(iph->tot_len); - fib_params.ipv4_src = iph->saddr; - fib_params.ipv4_dst = iph->daddr; - } else if (h_proto == bpf_htons(ETH_P_IPV6)) { - /* IPv6 part of the code */ - struct in6_addr *src = (struct in6_addr *) fib_params.ipv6_src; - struct in6_addr *dst = (struct in6_addr *) fib_params.ipv6_dst; - - ip6h = data + nh_off; - if (ip6h + 1 > data_end) { - action = XDP_DROP; - goto out; - } - /* as a real router, we need to check the TTL to prevent never ending loops*/ - if (ip6h->hop_limit <= 1) - goto out; - - /* populate the fib_params fields to prepare for the lookup */ - fib_params.family = AF_INET6; - fib_params.flowinfo = *(__be32 *) ip6h & IPV6_FLOWINFO_MASK; - fib_params.l4_protocol = ip6h->nexthdr; - fib_params.sport = 0; - fib_params.dport = 0; - fib_params.tot_len = bpf_ntohs(ip6h->payload_len); - *src = ip6h->saddr; - *dst = ip6h->daddr; - } else { - goto out; - } - - fib_params.ifindex = ctx->ingress_ifindex; - - /* this is where the FIB lookup happens. If the lookup is successful */ - /* it will populate the fib_params.ifindex with the egress interface index */ - - rc = bpf_fib_lookup(ctx, &fib_params, sizeof(fib_params), 0); - switch (rc) { - case BPF_FIB_LKUP_RET_SUCCESS: /* lookup successful */ - /* we are a router, so we need to decrease the ttl */ - if (h_proto == bpf_htons(ETH_P_IP)) - ip_decrease_ttl(iph); - else if (h_proto == bpf_htons(ETH_P_IPV6)) - ip6h->hop_limit--; - /* set the correct new source and destionation mac addresses */ - /* can be found in fib_params.dmac and fib_params.smac */ - memcpy(eth->h_dest, fib_params.dmac, ETH_ALEN); - memcpy(eth->h_source, fib_params.smac, ETH_ALEN); - /* and done, now we set the action to bpf_redirect_map with fib_params.ifindex which is the egress port as paramater */ - action = bpf_redirect_map(&tx_port, fib_params.ifindex, 0); - break; - case BPF_FIB_LKUP_RET_BLACKHOLE: /* dest is blackholed; can be dropped */ - case BPF_FIB_LKUP_RET_UNREACHABLE: /* dest is unreachable; can be dropped */ - case BPF_FIB_LKUP_RET_PROHIBIT: /* dest not allowed; can be dropped */ - action = XDP_DROP; - break; - case BPF_FIB_LKUP_RET_NOT_FWDED: /* packet is not forwarded */ - case BPF_FIB_LKUP_RET_FWD_DISABLED: /* fwding is not enabled on ingress */ - case BPF_FIB_LKUP_RET_UNSUPP_LWT: /* fwd requires encapsulation */ - case BPF_FIB_LKUP_RET_NO_NEIGH: /* no neighbor entry for nh */ - case BPF_FIB_LKUP_RET_FRAG_NEEDED: /* fragmentation required to fwd */ - /* PASS */ - break; - } - -out: - /* and done, update stats and return action */ - return xdp_stats_record_action(ctx, action); -} - -SEC("xdp_pass") -int xdp_pass_func(struct xdp_md *ctx) -{ - return xdp_stats_record_action(ctx, XDP_PASS); -} - -char _license[] SEC("license") = "GPL"; |