0001 #include <uapi/linux/bpf.h>
0002 #include <uapi/linux/in.h>
0003 #include <uapi/linux/if.h>
0004 #include <uapi/linux/if_ether.h>
0005 #include <uapi/linux/ip.h>
0006 #include <uapi/linux/ipv6.h>
0007 #include <uapi/linux/if_tunnel.h>
0008 #include <bpf/bpf_helpers.h>
0009 #include "bpf_legacy.h"
0010 #define IP_MF 0x2000
0011 #define IP_OFFSET 0x1FFF
0012
0013 struct vlan_hdr {
0014 __be16 h_vlan_TCI;
0015 __be16 h_vlan_encapsulated_proto;
0016 };
0017
0018 struct flow_key_record {
0019 __be32 src;
0020 __be32 dst;
0021 union {
0022 __be32 ports;
0023 __be16 port16[2];
0024 };
0025 __u16 thoff;
0026 __u8 ip_proto;
0027 };
0028
0029 static inline int proto_ports_offset(__u64 proto)
0030 {
0031 switch (proto) {
0032 case IPPROTO_TCP:
0033 case IPPROTO_UDP:
0034 case IPPROTO_DCCP:
0035 case IPPROTO_ESP:
0036 case IPPROTO_SCTP:
0037 case IPPROTO_UDPLITE:
0038 return 0;
0039 case IPPROTO_AH:
0040 return 4;
0041 default:
0042 return 0;
0043 }
0044 }
0045
0046 static inline int ip_is_fragment(struct __sk_buff *ctx, __u64 nhoff)
0047 {
0048 return load_half(ctx, nhoff + offsetof(struct iphdr, frag_off))
0049 & (IP_MF | IP_OFFSET);
0050 }
0051
0052 static inline __u32 ipv6_addr_hash(struct __sk_buff *ctx, __u64 off)
0053 {
0054 __u64 w0 = load_word(ctx, off);
0055 __u64 w1 = load_word(ctx, off + 4);
0056 __u64 w2 = load_word(ctx, off + 8);
0057 __u64 w3 = load_word(ctx, off + 12);
0058
0059 return (__u32)(w0 ^ w1 ^ w2 ^ w3);
0060 }
0061
0062 static inline __u64 parse_ip(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto,
0063 struct flow_key_record *flow)
0064 {
0065 __u64 verlen;
0066
0067 if (unlikely(ip_is_fragment(skb, nhoff)))
0068 *ip_proto = 0;
0069 else
0070 *ip_proto = load_byte(skb, nhoff + offsetof(struct iphdr, protocol));
0071
0072 if (*ip_proto != IPPROTO_GRE) {
0073 flow->src = load_word(skb, nhoff + offsetof(struct iphdr, saddr));
0074 flow->dst = load_word(skb, nhoff + offsetof(struct iphdr, daddr));
0075 }
0076
0077 verlen = load_byte(skb, nhoff + 0);
0078 if (likely(verlen == 0x45))
0079 nhoff += 20;
0080 else
0081 nhoff += (verlen & 0xF) << 2;
0082
0083 return nhoff;
0084 }
0085
0086 static inline __u64 parse_ipv6(struct __sk_buff *skb, __u64 nhoff, __u64 *ip_proto,
0087 struct flow_key_record *flow)
0088 {
0089 *ip_proto = load_byte(skb,
0090 nhoff + offsetof(struct ipv6hdr, nexthdr));
0091 flow->src = ipv6_addr_hash(skb,
0092 nhoff + offsetof(struct ipv6hdr, saddr));
0093 flow->dst = ipv6_addr_hash(skb,
0094 nhoff + offsetof(struct ipv6hdr, daddr));
0095 nhoff += sizeof(struct ipv6hdr);
0096
0097 return nhoff;
0098 }
0099
0100 static inline bool flow_dissector(struct __sk_buff *skb,
0101 struct flow_key_record *flow)
0102 {
0103 __u64 nhoff = ETH_HLEN;
0104 __u64 ip_proto;
0105 __u64 proto = load_half(skb, 12);
0106 int poff;
0107
0108 if (proto == ETH_P_8021AD) {
0109 proto = load_half(skb, nhoff + offsetof(struct vlan_hdr,
0110 h_vlan_encapsulated_proto));
0111 nhoff += sizeof(struct vlan_hdr);
0112 }
0113
0114 if (proto == ETH_P_8021Q) {
0115 proto = load_half(skb, nhoff + offsetof(struct vlan_hdr,
0116 h_vlan_encapsulated_proto));
0117 nhoff += sizeof(struct vlan_hdr);
0118 }
0119
0120 if (likely(proto == ETH_P_IP))
0121 nhoff = parse_ip(skb, nhoff, &ip_proto, flow);
0122 else if (proto == ETH_P_IPV6)
0123 nhoff = parse_ipv6(skb, nhoff, &ip_proto, flow);
0124 else
0125 return false;
0126
0127 switch (ip_proto) {
0128 case IPPROTO_GRE: {
0129 struct gre_hdr {
0130 __be16 flags;
0131 __be16 proto;
0132 };
0133
0134 __u64 gre_flags = load_half(skb,
0135 nhoff + offsetof(struct gre_hdr, flags));
0136 __u64 gre_proto = load_half(skb,
0137 nhoff + offsetof(struct gre_hdr, proto));
0138
0139 if (gre_flags & (GRE_VERSION|GRE_ROUTING))
0140 break;
0141
0142 proto = gre_proto;
0143 nhoff += 4;
0144 if (gre_flags & GRE_CSUM)
0145 nhoff += 4;
0146 if (gre_flags & GRE_KEY)
0147 nhoff += 4;
0148 if (gre_flags & GRE_SEQ)
0149 nhoff += 4;
0150
0151 if (proto == ETH_P_8021Q) {
0152 proto = load_half(skb,
0153 nhoff + offsetof(struct vlan_hdr,
0154 h_vlan_encapsulated_proto));
0155 nhoff += sizeof(struct vlan_hdr);
0156 }
0157
0158 if (proto == ETH_P_IP)
0159 nhoff = parse_ip(skb, nhoff, &ip_proto, flow);
0160 else if (proto == ETH_P_IPV6)
0161 nhoff = parse_ipv6(skb, nhoff, &ip_proto, flow);
0162 else
0163 return false;
0164 break;
0165 }
0166 case IPPROTO_IPIP:
0167 nhoff = parse_ip(skb, nhoff, &ip_proto, flow);
0168 break;
0169 case IPPROTO_IPV6:
0170 nhoff = parse_ipv6(skb, nhoff, &ip_proto, flow);
0171 break;
0172 default:
0173 break;
0174 }
0175
0176 flow->ip_proto = ip_proto;
0177 poff = proto_ports_offset(ip_proto);
0178 if (poff >= 0) {
0179 nhoff += poff;
0180 flow->ports = load_word(skb, nhoff);
0181 }
0182
0183 flow->thoff = (__u16) nhoff;
0184
0185 return true;
0186 }
0187
0188 struct pair {
0189 long packets;
0190 long bytes;
0191 };
0192
0193 struct {
0194 __uint(type, BPF_MAP_TYPE_HASH);
0195 __type(key, __be32);
0196 __type(value, struct pair);
0197 __uint(max_entries, 1024);
0198 } hash_map SEC(".maps");
0199
0200 SEC("socket2")
0201 int bpf_prog2(struct __sk_buff *skb)
0202 {
0203 struct flow_key_record flow = {};
0204 struct pair *value;
0205 u32 key;
0206
0207 if (!flow_dissector(skb, &flow))
0208 return 0;
0209
0210 key = flow.dst;
0211 value = bpf_map_lookup_elem(&hash_map, &key);
0212 if (value) {
0213 __sync_fetch_and_add(&value->packets, 1);
0214 __sync_fetch_and_add(&value->bytes, skb->len);
0215 } else {
0216 struct pair val = {1, skb->len};
0217
0218 bpf_map_update_elem(&hash_map, &key, &val, BPF_ANY);
0219 }
0220 return 0;
0221 }
0222
0223 char _license[] SEC("license") = "GPL";