]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
ebpf: improve parsing in filter.bpf
authorEric Leblond <eric@regit.org>
Wed, 19 Jun 2019 07:57:38 +0000 (09:57 +0200)
committerVictor Julien <victor@inliniac.net>
Fri, 23 Aug 2019 11:42:08 +0000 (13:42 +0200)
Parse VLAN and only filter on IPv4. This patch also change the type
of the counter to get a per CPU hash.

ebpf/filter.c

index 32a44314315ba75f6b4570f3a939ff195c9ab61d..38aeb701a3b431072400f573a8d43f557c5458e1 100644 (file)
 #define LINUX_VERSION_CODE 263682
 
 struct bpf_map_def SEC("maps") ipv4_drop = {
-    .type = BPF_MAP_TYPE_HASH,
+    .type = BPF_MAP_TYPE_PERCPU_HASH,
     .key_size = sizeof(__u32),
     .value_size = sizeof(__u32),
     .max_entries = 32768,
 };
 
-int SEC("filter") hashfilter(struct __sk_buff *skb) {
-    __u32 nhoff = ETH_HLEN;
-    __u32 ip = 0;
+struct vlan_hdr {
+    __u16   h_vlan_TCI;
+    __u16   h_vlan_encapsulated_proto;
+};
+
+static __always_inline int ipv4_filter(struct __sk_buff *skb)
+{
+    __u32 nhoff;
     __u32 *value;
+    __u32 ip = 0;
+
+    nhoff = skb->cb[0];
 
     ip = load_word(skb, nhoff + offsetof(struct iphdr, saddr));
     value = bpf_map_lookup_elem(&ipv4_drop, &ip);
@@ -50,7 +58,7 @@ int SEC("filter") hashfilter(struct __sk_buff *skb) {
         char fmt[] = "Found value for saddr: %u\n";
         bpf_trace_printk(fmt, sizeof(fmt), value);
 #endif
-        __sync_fetch_and_add(value, 1);
+        *value = *value + 1;
         return 0;
     }
 
@@ -61,7 +69,7 @@ int SEC("filter") hashfilter(struct __sk_buff *skb) {
         char fmt[] = "Found value for daddr: %u\n";
         bpf_trace_printk(fmt, sizeof(fmt), value);
 #endif
-        __sync_fetch_and_add(value, 1);
+        *value = *value + 1;
         return 0;
     }
 
@@ -72,6 +80,35 @@ int SEC("filter") hashfilter(struct __sk_buff *skb) {
     return -1;
 }
 
+static __always_inline int ipv6_filter(struct __sk_buff *skb)
+{
+    return -1;
+}
+
+int SEC("filter") hashfilter(struct __sk_buff *skb)
+{
+    __u32 nhoff = ETH_HLEN;
+
+    __u16 proto = load_half(skb, offsetof(struct ethhdr, h_proto));
+
+    if (proto == ETH_P_8021AD || proto == ETH_P_8021Q) {
+        proto = load_half(skb, nhoff + offsetof(struct vlan_hdr,
+                          h_vlan_encapsulated_proto));
+        nhoff += sizeof(struct vlan_hdr);
+    }
+
+    skb->cb[0] = nhoff;
+    switch (proto) {
+        case ETH_P_IP:
+            return ipv4_filter(skb);
+        case ETH_P_IPV6:
+            return ipv6_filter(skb);
+        default:
+            break;
+    }
+    return -1;
+}
+
 char __license[] SEC("license") = "GPL";
 
 __u32 __version SEC("version") = LINUX_VERSION_CODE;