1169689Skan#include <uapi/linux/bpf.h> 2169689Skan#include <uapi/linux/in.h> 3169689Skan#include <uapi/linux/if.h> 4169689Skan#include <uapi/linux/if_ether.h> 5169689Skan#include <uapi/linux/ip.h> 6169689Skan#include <uapi/linux/ipv6.h> 7169689Skan#include <uapi/linux/if_tunnel.h> 8169689Skan#include <bpf/bpf_helpers.h> 9169689Skan#include "bpf_legacy.h" 10169689Skan#define IP_MF 0x2000 11169689Skan#define IP_OFFSET 0x1FFF 12169689Skan 13169689Skanstruct vlan_hdr { 14169689Skan __be16 h_vlan_TCI; 15169689Skan __be16 h_vlan_encapsulated_proto; 16169689Skan}; 17169689Skan 18169689Skanstruct flow_key_record { 19169689Skan __be32 src; 20169689Skan __be32 dst; 21169689Skan union { 22169689Skan __be32 ports; 23169689Skan __be16 port16[2]; 24169689Skan }; 25169689Skan __u16 thoff; 26169689Skan __u8 ip_proto; 27169689Skan}; 28169689Skan 29169689Skanstatic inline int proto_ports_offset(__u64 proto) 30169689Skan{ 31169689Skan switch (proto) { 32169689Skan case IPPROTO_TCP: 33169689Skan case IPPROTO_UDP: 34169689Skan case IPPROTO_DCCP: 35169689Skan case IPPROTO_ESP: 36169689Skan case IPPROTO_SCTP: 37169689Skan case IPPROTO_UDPLITE: 38169689Skan return 0; 39169689Skan case IPPROTO_AH: 40169689Skan return 4; 41169689Skan default: 42169689Skan return 0; 43169689Skan } 44169689Skan} 45169689Skan 46169689Skanstatic inline int ip_is_fragment(struct __sk_buff *ctx, __u64 nhoff) 47169689Skan{ 48169689Skan return load_half(ctx, nhoff + offsetof(struct iphdr, frag_off)) 49169689Skan & (IP_MF | IP_OFFSET); 50169689Skan} 51169689Skan 52169689Skanstatic inline __u32 ipv6_addr_hash(struct __sk_buff *ctx, __u64 off) 53169689Skan{ 54169689Skan __u64 w0 = load_word(ctx, off); 55169689Skan __u64 w1 = load_word(ctx, off + 4); 56169689Skan __u64 w2 = load_word(ctx, off + 8); 57169689Skan __u64 w3 = load_word(ctx, off + 12); 58169689Skan 59169689Skan return (__u32)(w0 ^ w1 ^ w2 ^ w3); 60169689Skan} 61169689Skan 62169689Skanstatic inline __u64 parse_ip(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto, 63169689Skan struct flow_key_record *flow) 64169689Skan{ 65169689Skan __u64 verlen; 66169689Skan 67169689Skan if (unlikely(ip_is_fragment(skb, nhoff))) 68169689Skan *ip_proto = 0; 69169689Skan else 70169689Skan *ip_proto = load_byte(skb, nhoff + offsetof(struct iphdr, protocol)); 71169689Skan 72169689Skan if (*ip_proto != IPPROTO_GRE) { 73169689Skan flow->src = load_word(skb, nhoff + offsetof(struct iphdr, saddr)); 74169689Skan flow->dst = load_word(skb, nhoff + offsetof(struct iphdr, daddr)); 75169689Skan } 76169689Skan 77169689Skan verlen = load_byte(skb, nhoff + 0/*offsetof(struct iphdr, ihl)*/); 78169689Skan if (likely(verlen == 0x45)) 79169689Skan nhoff += 20; 80169689Skan else 81169689Skan nhoff += (verlen & 0xF) << 2; 82169689Skan 83169689Skan return nhoff; 84169689Skan} 85169689Skan 86169689Skanstatic inline __u64 parse_ipv6(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto, 87169689Skan struct flow_key_record *flow) 88169689Skan{ 89169689Skan *ip_proto = load_byte(skb, 90169689Skan nhoff + offsetof(struct ipv6hdr, nexthdr)); 91169689Skan flow->src = ipv6_addr_hash(skb, 92169689Skan nhoff + offsetof(struct ipv6hdr, saddr)); 93169689Skan flow->dst = ipv6_addr_hash(skb, 94169689Skan nhoff + offsetof(struct ipv6hdr, daddr)); 95169689Skan nhoff += sizeof(struct ipv6hdr); 96169689Skan 97169689Skan return nhoff; 98169689Skan} 99169689Skan 100169689Skanstatic inline bool flow_dissector(struct __sk_buff *skb, 101169689Skan struct flow_key_record *flow) 102169689Skan{ 103169689Skan __u64 nhoff = ETH_HLEN; 104169689Skan __u64 ip_proto; 105169689Skan __u64 proto = load_half(skb, 12); 106169689Skan int poff; 107169689Skan 108169689Skan if (proto == ETH_P_8021AD) { 109169689Skan proto = load_half(skb, nhoff + offsetof(struct vlan_hdr, 110169689Skan h_vlan_encapsulated_proto)); 111169689Skan nhoff += sizeof(struct vlan_hdr); 112169689Skan } 113169689Skan 114169689Skan if (proto == ETH_P_8021Q) { 115169689Skan proto = load_half(skb, nhoff + offsetof(struct vlan_hdr, 116169689Skan h_vlan_encapsulated_proto)); 117169689Skan nhoff += sizeof(struct vlan_hdr); 118169689Skan } 119169689Skan 120169689Skan if (likely(proto == ETH_P_IP)) 121169689Skan nhoff = parse_ip(skb, nhoff, &ip_proto, flow); 122169689Skan else if (proto == ETH_P_IPV6) 123169689Skan nhoff = parse_ipv6(skb, nhoff, &ip_proto, flow); 124169689Skan else 125169689Skan return false; 126169689Skan 127169689Skan switch (ip_proto) { 128169689Skan case IPPROTO_GRE: { 129169689Skan struct gre_hdr { 130169689Skan __be16 flags; 131169689Skan __be16 proto; 132169689Skan }; 133169689Skan 134169689Skan __u64 gre_flags = load_half(skb, 135169689Skan nhoff + offsetof(struct gre_hdr, flags)); 136169689Skan __u64 gre_proto = load_half(skb, 137169689Skan nhoff + offsetof(struct gre_hdr, proto)); 138169689Skan 139169689Skan if (gre_flags & (GRE_VERSION|GRE_ROUTING)) 140169689Skan break; 141169689Skan 142169689Skan proto = gre_proto; 143169689Skan nhoff += 4; 144169689Skan if (gre_flags & GRE_CSUM) 145169689Skan nhoff += 4; 146169689Skan if (gre_flags & GRE_KEY) 147169689Skan nhoff += 4; 148169689Skan if (gre_flags & GRE_SEQ) 149169689Skan nhoff += 4; 150169689Skan 151169689Skan if (proto == ETH_P_8021Q) { 152169689Skan proto = load_half(skb, 153169689Skan nhoff + offsetof(struct vlan_hdr, 154169689Skan h_vlan_encapsulated_proto)); 155169689Skan nhoff += sizeof(struct vlan_hdr); 156169689Skan } 157169689Skan 158169689Skan if (proto == ETH_P_IP) 159169689Skan nhoff = parse_ip(skb, nhoff, &ip_proto, flow); 160169689Skan else if (proto == ETH_P_IPV6) 161169689Skan nhoff = parse_ipv6(skb, nhoff, &ip_proto, flow); 162169689Skan else 163169689Skan return false; 164169689Skan break; 165169689Skan } 166169689Skan case IPPROTO_IPIP: 167169689Skan nhoff = parse_ip(skb, nhoff, &ip_proto, flow); 168169689Skan break; 169169689Skan case IPPROTO_IPV6: 170169689Skan nhoff = parse_ipv6(skb, nhoff, &ip_proto, flow); 171169689Skan break; 172169689Skan default: 173169689Skan break; 174169689Skan } 175169689Skan 176169689Skan flow->ip_proto = ip_proto; 177169689Skan poff = proto_ports_offset(ip_proto); 178169689Skan if (poff >= 0) { 179169689Skan nhoff += poff; 180169689Skan flow->ports = load_word(skb, nhoff); 181169689Skan } 182169689Skan 183169689Skan flow->thoff = (__u16) nhoff; 184169689Skan 185169689Skan return true; 186169689Skan} 187169689Skan 188169689Skanstruct pair { 189169689Skan long packets; 190169689Skan long bytes; 191169689Skan}; 192169689Skan 193169689Skanstruct { 194169689Skan __uint(type, BPF_MAP_TYPE_HASH); 195169689Skan __type(key, __be32); 196169689Skan __type(value, struct pair); 197169689Skan __uint(max_entries, 1024); 198169689Skan} hash_map SEC(".maps"); 199169689Skan 200169689SkanSEC("socket2") 201169689Skanint bpf_prog2(struct __sk_buff *skb) 202169689Skan{ 203169689Skan struct flow_key_record flow = {}; 204169689Skan struct pair *value; 205169689Skan u32 key; 206169689Skan 207169689Skan if (!flow_dissector(skb, &flow)) 208169689Skan return 0; 209169689Skan 210169689Skan key = flow.dst; 211169689Skan value = bpf_map_lookup_elem(&hash_map, &key); 212169689Skan if (value) { 213169689Skan __sync_fetch_and_add(&value->packets, 1); 214169689Skan __sync_fetch_and_add(&value->bytes, skb->len); 215169689Skan } else { 216169689Skan struct pair val = {1, skb->len}; 217169689Skan 218169689Skan bpf_map_update_elem(&hash_map, &key, &val, BPF_ANY); 219169689Skan } 220169689Skan return 0; 221169689Skan} 222169689Skan 223169689Skanchar _license[] SEC("license") = "GPL"; 224169689Skan