summaryrefslogtreecommitdiff
path: root/src/xdp/xdp_prog_kern.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xdp/xdp_prog_kern.c')
-rw-r--r--src/xdp/xdp_prog_kern.c343
1 files changed, 0 insertions, 343 deletions
diff --git a/src/xdp/xdp_prog_kern.c b/src/xdp/xdp_prog_kern.c
deleted file mode 100644
index a1eb395af..000000000
--- a/src/xdp/xdp_prog_kern.c
+++ /dev/null
@@ -1,343 +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 bpf_map_def SEC("maps") tx_port = {
- .type = BPF_MAP_TYPE_DEVMAP,
- .key_size = sizeof(int),
- .value_size = sizeof(int),
- .max_entries = 256,
-};
-
-struct bpf_map_def SEC("maps") redirect_params = {
- .type = BPF_MAP_TYPE_HASH,
- .key_size = ETH_ALEN,
- .value_size = ETH_ALEN,
- .max_entries = 1,
-};
-
-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, &eth);
- 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, &eth);
- 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, &eth);
- 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);
-}
-
-#define AF_INET 2
-#define AF_INET6 10
-#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";