18c2ecf20Sopenharmony_ci/* Copyright (c) 2016 PLUMgrid 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 48c2ecf20Sopenharmony_ci * modify it under the terms of version 2 of the GNU General Public 58c2ecf20Sopenharmony_ci * License as published by the Free Software Foundation. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#define KBUILD_MODNAME "foo" 88c2ecf20Sopenharmony_ci#include <uapi/linux/bpf.h> 98c2ecf20Sopenharmony_ci#include <linux/in.h> 108c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 118c2ecf20Sopenharmony_ci#include <linux/if_packet.h> 128c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 138c2ecf20Sopenharmony_ci#include <linux/ip.h> 148c2ecf20Sopenharmony_ci#include <linux/ipv6.h> 158c2ecf20Sopenharmony_ci#include <bpf/bpf_helpers.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct { 188c2ecf20Sopenharmony_ci __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); 198c2ecf20Sopenharmony_ci __type(key, u32); 208c2ecf20Sopenharmony_ci __type(value, long); 218c2ecf20Sopenharmony_ci __uint(max_entries, 256); 228c2ecf20Sopenharmony_ci} rxcnt SEC(".maps"); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic void swap_src_dst_mac(void *data) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci unsigned short *p = data; 278c2ecf20Sopenharmony_ci unsigned short dst[3]; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci dst[0] = p[0]; 308c2ecf20Sopenharmony_ci dst[1] = p[1]; 318c2ecf20Sopenharmony_ci dst[2] = p[2]; 328c2ecf20Sopenharmony_ci p[0] = p[3]; 338c2ecf20Sopenharmony_ci p[1] = p[4]; 348c2ecf20Sopenharmony_ci p[2] = p[5]; 358c2ecf20Sopenharmony_ci p[3] = dst[0]; 368c2ecf20Sopenharmony_ci p[4] = dst[1]; 378c2ecf20Sopenharmony_ci p[5] = dst[2]; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int parse_ipv4(void *data, u64 nh_off, void *data_end) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct iphdr *iph = data + nh_off; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (iph + 1 > data_end) 458c2ecf20Sopenharmony_ci return 0; 468c2ecf20Sopenharmony_ci return iph->protocol; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int parse_ipv6(void *data, u64 nh_off, void *data_end) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct ipv6hdr *ip6h = data + nh_off; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (ip6h + 1 > data_end) 548c2ecf20Sopenharmony_ci return 0; 558c2ecf20Sopenharmony_ci return ip6h->nexthdr; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ciSEC("xdp1") 598c2ecf20Sopenharmony_ciint xdp_prog1(struct xdp_md *ctx) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci void *data_end = (void *)(long)ctx->data_end; 628c2ecf20Sopenharmony_ci void *data = (void *)(long)ctx->data; 638c2ecf20Sopenharmony_ci struct ethhdr *eth = data; 648c2ecf20Sopenharmony_ci int rc = XDP_DROP; 658c2ecf20Sopenharmony_ci long *value; 668c2ecf20Sopenharmony_ci u16 h_proto; 678c2ecf20Sopenharmony_ci u64 nh_off; 688c2ecf20Sopenharmony_ci u32 ipproto; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci nh_off = sizeof(*eth); 718c2ecf20Sopenharmony_ci if (data + nh_off > data_end) 728c2ecf20Sopenharmony_ci return rc; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci h_proto = eth->h_proto; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) { 778c2ecf20Sopenharmony_ci struct vlan_hdr *vhdr; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci vhdr = data + nh_off; 808c2ecf20Sopenharmony_ci nh_off += sizeof(struct vlan_hdr); 818c2ecf20Sopenharmony_ci if (data + nh_off > data_end) 828c2ecf20Sopenharmony_ci return rc; 838c2ecf20Sopenharmony_ci h_proto = vhdr->h_vlan_encapsulated_proto; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci if (h_proto == htons(ETH_P_8021Q) || h_proto == htons(ETH_P_8021AD)) { 868c2ecf20Sopenharmony_ci struct vlan_hdr *vhdr; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci vhdr = data + nh_off; 898c2ecf20Sopenharmony_ci nh_off += sizeof(struct vlan_hdr); 908c2ecf20Sopenharmony_ci if (data + nh_off > data_end) 918c2ecf20Sopenharmony_ci return rc; 928c2ecf20Sopenharmony_ci h_proto = vhdr->h_vlan_encapsulated_proto; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (h_proto == htons(ETH_P_IP)) 968c2ecf20Sopenharmony_ci ipproto = parse_ipv4(data, nh_off, data_end); 978c2ecf20Sopenharmony_ci else if (h_proto == htons(ETH_P_IPV6)) 988c2ecf20Sopenharmony_ci ipproto = parse_ipv6(data, nh_off, data_end); 998c2ecf20Sopenharmony_ci else 1008c2ecf20Sopenharmony_ci ipproto = 0; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci value = bpf_map_lookup_elem(&rxcnt, &ipproto); 1038c2ecf20Sopenharmony_ci if (value) 1048c2ecf20Sopenharmony_ci *value += 1; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (ipproto == IPPROTO_UDP) { 1078c2ecf20Sopenharmony_ci swap_src_dst_mac(data); 1088c2ecf20Sopenharmony_ci rc = XDP_TX; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return rc; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cichar _license[] SEC("license") = "GPL"; 115