|
@@ -13,6 +13,7 @@
|
|
|
|
|
|
#include <uapi/linux/bpf.h>
|
|
|
#include "bpf_helpers.h"
|
|
|
+#include "hash_func01.h"
|
|
|
|
|
|
#define MAX_CPUS 12 /* WARNING - sync with _user.c */
|
|
|
|
|
@@ -461,6 +462,108 @@ int xdp_prognum4_ddos_filter_pktgen(struct xdp_md *ctx)
|
|
|
return bpf_redirect_map(&cpu_map, cpu_dest, 0);
|
|
|
}
|
|
|
|
|
|
+/* Hashing initval */
|
|
|
+#define INITVAL 15485863
|
|
|
+
|
|
|
+static __always_inline
|
|
|
+u32 get_ipv4_hash_ip_pair(struct xdp_md *ctx, u64 nh_off)
|
|
|
+{
|
|
|
+ void *data_end = (void *)(long)ctx->data_end;
|
|
|
+ void *data = (void *)(long)ctx->data;
|
|
|
+ struct iphdr *iph = data + nh_off;
|
|
|
+ u32 cpu_hash;
|
|
|
+
|
|
|
+ if (iph + 1 > data_end)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ cpu_hash = iph->saddr + iph->daddr;
|
|
|
+ cpu_hash = SuperFastHash((char *)&cpu_hash, 4, INITVAL + iph->protocol);
|
|
|
+
|
|
|
+ return cpu_hash;
|
|
|
+}
|
|
|
+
|
|
|
+static __always_inline
|
|
|
+u32 get_ipv6_hash_ip_pair(struct xdp_md *ctx, u64 nh_off)
|
|
|
+{
|
|
|
+ void *data_end = (void *)(long)ctx->data_end;
|
|
|
+ void *data = (void *)(long)ctx->data;
|
|
|
+ struct ipv6hdr *ip6h = data + nh_off;
|
|
|
+ u32 cpu_hash;
|
|
|
+
|
|
|
+ if (ip6h + 1 > data_end)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ cpu_hash = ip6h->saddr.s6_addr32[0] + ip6h->daddr.s6_addr32[0];
|
|
|
+ cpu_hash += ip6h->saddr.s6_addr32[1] + ip6h->daddr.s6_addr32[1];
|
|
|
+ cpu_hash += ip6h->saddr.s6_addr32[2] + ip6h->daddr.s6_addr32[2];
|
|
|
+ cpu_hash += ip6h->saddr.s6_addr32[3] + ip6h->daddr.s6_addr32[3];
|
|
|
+ cpu_hash = SuperFastHash((char *)&cpu_hash, 4, INITVAL + ip6h->nexthdr);
|
|
|
+
|
|
|
+ return cpu_hash;
|
|
|
+}
|
|
|
+
|
|
|
+/* Load-Balance traffic based on hashing IP-addrs + L4-proto. The
|
|
|
+ * hashing scheme is symmetric, meaning swapping IP src/dest still hit
|
|
|
+ * same CPU.
|
|
|
+ */
|
|
|
+SEC("xdp_cpu_map5_lb_hash_ip_pairs")
|
|
|
+int xdp_prognum5_lb_hash_ip_pairs(struct xdp_md *ctx)
|
|
|
+{
|
|
|
+ void *data_end = (void *)(long)ctx->data_end;
|
|
|
+ void *data = (void *)(long)ctx->data;
|
|
|
+ struct ethhdr *eth = data;
|
|
|
+ u8 ip_proto = IPPROTO_UDP;
|
|
|
+ struct datarec *rec;
|
|
|
+ u16 eth_proto = 0;
|
|
|
+ u64 l3_offset = 0;
|
|
|
+ u32 cpu_dest = 0;
|
|
|
+ u32 cpu_idx = 0;
|
|
|
+ u32 *cpu_lookup;
|
|
|
+ u32 *cpu_max;
|
|
|
+ u32 cpu_hash;
|
|
|
+ u32 key = 0;
|
|
|
+
|
|
|
+ /* Count RX packet in map */
|
|
|
+ rec = bpf_map_lookup_elem(&rx_cnt, &key);
|
|
|
+ if (!rec)
|
|
|
+ return XDP_ABORTED;
|
|
|
+ rec->processed++;
|
|
|
+
|
|
|
+ cpu_max = bpf_map_lookup_elem(&cpus_count, &key);
|
|
|
+ if (!cpu_max)
|
|
|
+ return XDP_ABORTED;
|
|
|
+
|
|
|
+ if (!(parse_eth(eth, data_end, ð_proto, &l3_offset)))
|
|
|
+ return XDP_PASS; /* Just skip */
|
|
|
+
|
|
|
+ /* Hash for IPv4 and IPv6 */
|
|
|
+ switch (eth_proto) {
|
|
|
+ case ETH_P_IP:
|
|
|
+ cpu_hash = get_ipv4_hash_ip_pair(ctx, l3_offset);
|
|
|
+ break;
|
|
|
+ case ETH_P_IPV6:
|
|
|
+ cpu_hash = get_ipv6_hash_ip_pair(ctx, l3_offset);
|
|
|
+ break;
|
|
|
+ case ETH_P_ARP: /* ARP packet handled on CPU idx 0 */
|
|
|
+ default:
|
|
|
+ cpu_hash = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Choose CPU based on hash */
|
|
|
+ cpu_idx = cpu_hash % *cpu_max;
|
|
|
+
|
|
|
+ cpu_lookup = bpf_map_lookup_elem(&cpus_available, &cpu_idx);
|
|
|
+ if (!cpu_lookup)
|
|
|
+ return XDP_ABORTED;
|
|
|
+ cpu_dest = *cpu_lookup;
|
|
|
+
|
|
|
+ if (cpu_dest >= MAX_CPUS) {
|
|
|
+ rec->issue++;
|
|
|
+ return XDP_ABORTED;
|
|
|
+ }
|
|
|
+
|
|
|
+ return bpf_redirect_map(&cpu_map, cpu_dest, 0);
|
|
|
+}
|
|
|
|
|
|
char _license[] SEC("license") = "GPL";
|
|
|
|