Implement both IP and flow-based rate limiting.
This commit is contained in:
@@ -14,14 +14,16 @@
|
||||
* @param dst_port The destination port.
|
||||
* @param protocol The protocol.
|
||||
* @param now The timestamp.
|
||||
* @param pps The current PPS rate.
|
||||
* @param bps The current BPS rate.
|
||||
* @param ip_pps The current IP PPS rate.
|
||||
* @param ip_bps The current IP BPS rate.
|
||||
* @param flow_pps The current flow PPS rate.
|
||||
* @param flow_bps The current flow BPS rate.
|
||||
* @param pkt_len The full packet length.
|
||||
* @param filter_id The filter ID that matched.
|
||||
*
|
||||
* @return always 0
|
||||
*/
|
||||
static __always_inline int log_filter_msg(struct iphdr* iph, struct ipv6hdr* iph6, u16 src_port, u16 dst_port, u8 protocol, u64 now, u64 pps, u64 bps, int pkt_len, int filter_id)
|
||||
static __always_inline int log_filter_msg(struct iphdr* iph, struct ipv6hdr* iph6, u16 src_port, u16 dst_port, u8 protocol, u64 now, u64 ip_pps, u64 ip_bps, u64 flow_pps, u64 flow_bps, int pkt_len, int filter_id)
|
||||
{
|
||||
filter_log_event_t* e = bpf_ringbuf_reserve(&map_filter_log, sizeof(*e), 0);
|
||||
|
||||
@@ -45,8 +47,11 @@ static __always_inline int log_filter_msg(struct iphdr* iph, struct ipv6hdr* iph
|
||||
|
||||
e->protocol = protocol;
|
||||
|
||||
e->pps = pps;
|
||||
e->bps = bps;
|
||||
e->ip_pps = ip_pps;
|
||||
e->ip_bps = ip_bps;
|
||||
|
||||
e->flow_pps = flow_pps;
|
||||
e->flow_bps = flow_bps;
|
||||
|
||||
e->length = pkt_len;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <xdp/prog_dispatcher.h>
|
||||
|
||||
#if defined(ENABLE_FILTERS) && defined(ENABLE_FILTER_LOGGING)
|
||||
static __always_inline int log_filter_msg(struct iphdr* iph, struct ipv6hdr* iph6, u16 src_port, u16 dst_port, u8 protocol, u64 now, u64 pps, u64 bps, int pkt_len, int filter_id);
|
||||
static __always_inline int log_filter_msg(struct iphdr* iph, struct ipv6hdr* iph6, u16 src_port, u16 dst_port, u8 protocol, u64 now, u64 ip_pps, u64 ip_bps, u64 flow_pps, u64 flow_bps, int pkt_len, int filter_id);
|
||||
#endif
|
||||
|
||||
// The source file is included directly below instead of compiled and linked as an object because when linking, there is no guarantee the compiler will inline the function (which is crucial for performance).
|
||||
|
||||
@@ -16,7 +16,7 @@ struct
|
||||
struct
|
||||
{
|
||||
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
||||
__uint(max_entries, MAX_TRACK_IPS);
|
||||
__uint(max_entries, MAX_BLOCK);
|
||||
__type(key, u32);
|
||||
__type(value, u64);
|
||||
} map_block SEC(".maps");
|
||||
@@ -24,7 +24,7 @@ struct
|
||||
struct
|
||||
{
|
||||
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
||||
__uint(max_entries, MAX_TRACK_IPS);
|
||||
__uint(max_entries, MAX_BLOCK);
|
||||
__type(key, u128);
|
||||
__type(value, u64);
|
||||
} map_block6 SEC(".maps");
|
||||
@@ -41,29 +41,41 @@ struct
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FILTERS
|
||||
#ifdef ENABLE_RL_IP
|
||||
struct
|
||||
{
|
||||
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
||||
__uint(max_entries, MAX_TRACK_IPS);
|
||||
#ifdef USE_FLOW_RL
|
||||
__type(key, flow_t);
|
||||
#else
|
||||
__uint(max_entries, MAX_RL_IP);
|
||||
__type(key, u32);
|
||||
#endif
|
||||
__type(value, ip_stats_t);
|
||||
__type(value, cl_stats_t);
|
||||
} map_ip_stats SEC(".maps");
|
||||
|
||||
struct
|
||||
{
|
||||
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
||||
__uint(max_entries, MAX_TRACK_IPS);
|
||||
#ifdef USE_FLOW_RL
|
||||
__type(key, flow6_t);
|
||||
#else
|
||||
__uint(max_entries, MAX_RL_IP);
|
||||
__type(key, u128);
|
||||
#endif
|
||||
__type(value, ip_stats_t);
|
||||
__type(value, cl_stats_t);
|
||||
} map_ip6_stats SEC(".maps");
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_RL_FLOW
|
||||
struct
|
||||
{
|
||||
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
||||
__uint(max_entries, MAX_RL_FLOW);
|
||||
__type(key, flow_t);
|
||||
__type(value, cl_stats_t);
|
||||
} map_flow_stats SEC(".maps");
|
||||
|
||||
struct
|
||||
{
|
||||
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
||||
__uint(max_entries, MAX_RL_FLOW);
|
||||
__type(key, flow6_t);
|
||||
__type(value, cl_stats_t);
|
||||
} map_flow6_stats SEC(".maps");
|
||||
#endif
|
||||
|
||||
struct
|
||||
{
|
||||
|
||||
@@ -1,8 +1,116 @@
|
||||
#include <xdp/utils/rl.h>
|
||||
|
||||
#ifdef ENABLE_FILTERS
|
||||
|
||||
#ifdef ENABLE_RL_IP
|
||||
/**
|
||||
* Updates IPv4 client stats.
|
||||
* Updates source IPv4 address stats.
|
||||
*
|
||||
* @param pps A pointer to the PPS integer.
|
||||
* @param bps A pointer to the BPS integer.
|
||||
* @param ip The client's source IP.
|
||||
* @param pkt_len The total packet length.
|
||||
* @param now The current time since boot in nanoseconds.alignas
|
||||
*
|
||||
* @return always 0
|
||||
*/
|
||||
static __always_inline int update_ip_stats(u64 *pps, u64 *bps, u32 ip, u16 pkt_len, u64 now)
|
||||
{
|
||||
cl_stats_t* stats = bpf_map_lookup_elem(&map_ip_stats, &ip);
|
||||
|
||||
if (stats)
|
||||
{
|
||||
// Check for next update.
|
||||
if (now > stats->next_update)
|
||||
{
|
||||
stats->pps = 1;
|
||||
stats->bps = pkt_len;
|
||||
stats->next_update = now + NANO_TO_SEC;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Increment PPS and BPS using built-in functions.
|
||||
__sync_fetch_and_add(&stats->pps, 1);
|
||||
__sync_fetch_and_add(&stats->bps, pkt_len);
|
||||
}
|
||||
|
||||
*pps = stats->pps;
|
||||
*bps = stats->bps;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create new entry.
|
||||
cl_stats_t new = {0};
|
||||
|
||||
new.pps = 1;
|
||||
new.bps = pkt_len;
|
||||
new.next_update = now + NANO_TO_SEC;
|
||||
|
||||
*pps = new.pps;
|
||||
*bps = new.bps;
|
||||
|
||||
bpf_map_update_elem(&map_ip_stats, &ip, &new, BPF_ANY);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates source IPv6 address stats.
|
||||
*
|
||||
* @param pps A pointer to the PPS integer.
|
||||
* @param bps A pointer to the BPS integer.
|
||||
* @param ip The client's source IP.
|
||||
* @param pkt_len The total packet length.
|
||||
* @param now The current time since boot in nanoseconds.alignas
|
||||
*
|
||||
* @return always 0
|
||||
*/
|
||||
static __always_inline int update_ip6_stats(u64 *pps, u64 *bps, u128 *ip, u16 pkt_len, u64 now)
|
||||
{
|
||||
cl_stats_t* stats = bpf_map_lookup_elem(&map_ip6_stats, ip);
|
||||
|
||||
if (stats)
|
||||
{
|
||||
// Check for next update.
|
||||
if (now > stats->next_update)
|
||||
{
|
||||
stats->pps = 1;
|
||||
stats->bps = pkt_len;
|
||||
stats->next_update = now + NANO_TO_SEC;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Increment PPS and BPS using built-in functions.
|
||||
__sync_fetch_and_add(&stats->pps, 1);
|
||||
__sync_fetch_and_add(&stats->bps, pkt_len);
|
||||
}
|
||||
|
||||
*pps = stats->pps;
|
||||
*bps = stats->bps;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create new entry.
|
||||
cl_stats_t new = {0};
|
||||
|
||||
new.pps = 1;
|
||||
new.bps = pkt_len;
|
||||
new.next_update = now + NANO_TO_SEC;
|
||||
|
||||
*pps = new.pps;
|
||||
*bps = new.bps;
|
||||
|
||||
bpf_map_update_elem(&map_ip6_stats, ip, &new, BPF_ANY);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_RL_FLOW
|
||||
/**
|
||||
* Updates IPv4 flow stats.
|
||||
*
|
||||
* @param pps A pointer to the PPS integer.
|
||||
* @param bps A pointer to the BPS integer.
|
||||
@@ -10,46 +118,42 @@
|
||||
* @param port The client's source port.
|
||||
* @param protocol The client's protocol.
|
||||
* @param pkt_len The total packet length.
|
||||
* @param now The current time since boot in nanoseconds.alignas
|
||||
* @param now The current time since boot in nanoseconds.
|
||||
*
|
||||
* @return void
|
||||
* @return always 0
|
||||
*/
|
||||
static __always_inline void update_ip_stats(u64 *pps, u64 *bps, u32 ip, u16 port, u8 protocol, u16 pkt_len, u64 now)
|
||||
static __always_inline int update_flow_stats(u64 *pps, u64 *bps, u32 ip, u16 port, u8 protocol, u16 pkt_len, u64 now)
|
||||
{
|
||||
#ifdef USE_FLOW_RL
|
||||
flow_t key = {0};
|
||||
key.ip = ip;
|
||||
key.port = port;
|
||||
key.protocol = protocol;
|
||||
|
||||
ip_stats_t *ip_stats = bpf_map_lookup_elem(&map_ip_stats, &key);
|
||||
#else
|
||||
ip_stats_t *ip_stats = bpf_map_lookup_elem(&map_ip_stats, &ip);
|
||||
#endif
|
||||
cl_stats_t* stats = bpf_map_lookup_elem(&map_flow_stats, &key);
|
||||
|
||||
if (ip_stats)
|
||||
if (stats)
|
||||
{
|
||||
// Check for next update.
|
||||
if (now > ip_stats->next_update)
|
||||
if (now > stats->next_update)
|
||||
{
|
||||
ip_stats->pps = 1;
|
||||
ip_stats->bps = pkt_len;
|
||||
ip_stats->next_update = now + NANO_TO_SEC;
|
||||
stats->pps = 1;
|
||||
stats->bps = pkt_len;
|
||||
stats->next_update = now + NANO_TO_SEC;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Increment PPS and BPS using built-in functions.
|
||||
__sync_fetch_and_add(&ip_stats->pps, 1);
|
||||
__sync_fetch_and_add(&ip_stats->bps, pkt_len);
|
||||
__sync_fetch_and_add(&stats->pps, 1);
|
||||
__sync_fetch_and_add(&stats->bps, pkt_len);
|
||||
}
|
||||
|
||||
*pps = ip_stats->pps;
|
||||
*bps = ip_stats->bps;
|
||||
*pps = stats->pps;
|
||||
*bps = stats->bps;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create new entry.
|
||||
ip_stats_t new = {0};
|
||||
cl_stats_t new = {0};
|
||||
|
||||
new.pps = 1;
|
||||
new.bps = pkt_len;
|
||||
@@ -58,16 +162,14 @@ static __always_inline void update_ip_stats(u64 *pps, u64 *bps, u32 ip, u16 port
|
||||
*pps = new.pps;
|
||||
*bps = new.bps;
|
||||
|
||||
#ifdef USE_FLOW_RL
|
||||
bpf_map_update_elem(&map_ip_stats, &key, &new, BPF_ANY);
|
||||
#else
|
||||
bpf_map_update_elem(&map_ip_stats, &ip, &new, BPF_ANY);
|
||||
#endif
|
||||
bpf_map_update_elem(&map_flow_stats, &key, &new, BPF_ANY);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates IPv6 client stats.
|
||||
* Updates IPv6 flow stats.
|
||||
*
|
||||
* @param pps A pointer to the PPS integer.
|
||||
* @param bps A pointer to the BPS integer.
|
||||
@@ -75,46 +177,42 @@ static __always_inline void update_ip_stats(u64 *pps, u64 *bps, u32 ip, u16 port
|
||||
* @param port The client's source port.
|
||||
* @param protocol The client's protocol.
|
||||
* @param pkt_len The total packet length.
|
||||
* @param now The current time since boot in nanoseconds.alignas
|
||||
* @param now The current time since boot in nanoseconds.
|
||||
*
|
||||
* @return void
|
||||
* @return always 0
|
||||
*/
|
||||
static __always_inline void update_ip6_stats(u64 *pps, u64 *bps, u128 *ip, u16 port, u8 protocol, u16 pkt_len, u64 now)
|
||||
static __always_inline int update_flow6_stats(u64 *pps, u64 *bps, u128 *ip, u16 port, u8 protocol, u16 pkt_len, u64 now)
|
||||
{
|
||||
#ifdef USE_FLOW_RL
|
||||
flow6_t key = {0};
|
||||
key.ip = *ip;
|
||||
key.port = port;
|
||||
key.protocol = protocol;
|
||||
|
||||
ip_stats_t *ip_stats = bpf_map_lookup_elem(&map_ip6_stats, &key);
|
||||
#else
|
||||
ip_stats_t *ip_stats = bpf_map_lookup_elem(&map_ip6_stats, ip);
|
||||
#endif
|
||||
cl_stats_t* stats = bpf_map_lookup_elem(&map_flow6_stats, &key);
|
||||
|
||||
if (ip_stats)
|
||||
if (stats)
|
||||
{
|
||||
// Check for next update.
|
||||
if (now > ip_stats->next_update)
|
||||
if (now > stats->next_update)
|
||||
{
|
||||
ip_stats->pps = 1;
|
||||
ip_stats->bps = pkt_len;
|
||||
ip_stats->next_update = now + NANO_TO_SEC;
|
||||
stats->pps = 1;
|
||||
stats->bps = pkt_len;
|
||||
stats->next_update = now + NANO_TO_SEC;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Increment PPS and BPS using built-in functions.
|
||||
__sync_fetch_and_add(&ip_stats->pps, 1);
|
||||
__sync_fetch_and_add(&ip_stats->bps, pkt_len);
|
||||
__sync_fetch_and_add(&stats->pps, 1);
|
||||
__sync_fetch_and_add(&stats->bps, pkt_len);
|
||||
}
|
||||
|
||||
*pps = ip_stats->pps;
|
||||
*bps = ip_stats->bps;
|
||||
*pps = stats->pps;
|
||||
*bps = stats->bps;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create new entry.
|
||||
ip_stats_t new = {0};
|
||||
cl_stats_t new = {0};
|
||||
|
||||
new.pps = 1;
|
||||
new.bps = pkt_len;
|
||||
@@ -123,11 +221,10 @@ static __always_inline void update_ip6_stats(u64 *pps, u64 *bps, u128 *ip, u16 p
|
||||
*pps = new.pps;
|
||||
*bps = new.bps;
|
||||
|
||||
#ifdef USE_FLOW_RL
|
||||
bpf_map_update_elem(&map_ip6_stats, &key, &new, BPF_ANY);
|
||||
#else
|
||||
bpf_map_update_elem(&map_ip6_stats, ip, &new, BPF_ANY);
|
||||
#endif
|
||||
bpf_map_update_elem(&map_flow6_stats, &key, &new, BPF_ANY);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -7,8 +7,10 @@
|
||||
#include <xdp/utils/maps.h>
|
||||
|
||||
#ifdef ENABLE_FILTERS
|
||||
static __always_inline void update_ip_stats(u64 *pps, u64 *bps, u32 ip, u16 port, u8 protocol, u16 pkt_len, u64 now);
|
||||
static __always_inline void update_ip6_stats(u64 *pps, u64 *bps, u128 *ip, u16 port, u8 protocol, u16 pkt_len, u64 now);
|
||||
static __always_inline int update_ip_stats(u64 *pps, u64 *bps, u32 ip, u16 pkt_len, u64 now);
|
||||
static __always_inline int update_ip6_stats(u64 *pps, u64 *bps, u128 *ip, u16 pkt_len, u64 now);
|
||||
static __always_inline int update_flow_stats(u64 *pps, u64 *bps, u32 ip, u16 port, u8 protocol, u16 pkt_len, u64 now);
|
||||
static __always_inline int update_flow6_stats(u64 *pps, u64 *bps, u128 *ip, u16 port, u8 protocol, u16 pkt_len, u64 now);
|
||||
#endif
|
||||
|
||||
// The source file is included directly below instead of compiled and linked as an object because when linking, there is no guarantee the compiler will inline the function (which is crucial for performance).
|
||||
|
||||
Reference in New Issue
Block a user