Skip to content

Netstacklat: Add filtering and grouping #129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion headers/vmlinux/vmlinux_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@

typedef __u32 __wsum;

typedef struct {
struct net *net;
} possible_net_t;

struct net_device {
int ifindex;
possible_net_t nd_net;
};

typedef unsigned int sk_buff_data_t; // Assumes 64-bit. FIXME see below
/*
// BITS_PER_LONG can be wrong with -target bpf
Expand All @@ -17,6 +26,22 @@ typedef unsigned char *sk_buff_data_t;
#endif
*/

struct sk_buff_list {
struct sk_buff *next;
struct sk_buff *prev;
};

struct sk_buff_head {
union {
struct {
struct sk_buff *next;
struct sk_buff *prev;
};
struct sk_buff_list list;
};
__u32 qlen;
};

struct sk_buff {
union {
struct {
Expand Down Expand Up @@ -147,7 +172,28 @@ enum ip_conntrack_status {
};

struct scm_timestamping_internal {
struct timespec64 ts[3];
struct timespec64 ts[3];
};

struct ns_common {
struct dentry *stashed;
unsigned int inum;
};

struct net {
struct ns_common ns;
};

struct sock_common {
possible_net_t skc_net;
};

struct sock {
struct sock_common __sk_common;
struct sk_buff_head sk_receive_queue;
struct dst_entry *sk_rx_dst;
int sk_rx_dst_ifindex;
u32 sk_rx_dst_cookie;
};

#endif /* __VMLINUX_NET_H__ */
131 changes: 131 additions & 0 deletions netstacklat/fill_filter_maps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-or-later

declare -rA bpf_maps=(
[pid]="netstack_pidfil"
[iface]="netstack_ifinde"
[cgroup]="netstack_cgroup"
)

declare -rA key_converters=(
[pid]=pid_to_bpftool
[iface]=iface_to_bpftool
[cgroup]=cgroup_to_bpftool
)

print_usage()
{
echo "usage: $0 TYPE val1 [val2 val3 val4...]"
echo "TYPE: { $(echo "${!bpf_maps[@]}" | tr ' ' '\|') }"
}

pid_to_bpftool()
{
local val="$1"

uint_to_bpftool_u32 "$val"
}

# Supports ifname or ifindex
iface_to_bpftool()
{
local val="$1"

if ! is_uint "$val"; then
val="$(ifname_to_idx "$val")"
fi

uint_to_bpftool_u32 "$val"
}

# Supports full cgroup path or direct cgroup id (inode)
cgroup_to_bpftool()
{
local val="$1"

if ! is_uint "$val"; then
val="$(cgroup_path_to_id "$val")"
fi

uint_to_bpftool_u64 "$val"
}

is_uint()
{
local val="$1"

[[ "$val" == +([0-9]) ]]
}

ifname_to_idx()
{
local ifname="$1"
local ifindex=0

ifindex="$(ip address show "$ifname" | grep "[0-9]*: ${ifname}:")"
ifindex="${ifindex%%:*}"

if [[ -z "$ifindex" ]]; then
return 1
fi

echo "$ifindex"
}

cgroup_path_to_id()
{
local cpath="$1"

stat -L -c '%i' "$(realpath "$cpath")"
}

# When providing keys/values to bpftool map update, it basically wants one
# argument for each byte in the key/value. So if you have a u32 key (as in any
# array map) and you want to update key 1234, then you will have to provide
# key 0xd2 0x04 0x00 0x00 (1234 in hex split up as the 4 bytes in a u32 in
# little-endian order). These helpers assume you're on a little endian machine.
uint_to_bpftool_u32()
{
local val="$1"

printf "0x%02x 0x%02x 0x%02x 0x%02x\n" \
$((val & 0xff)) $(((val >> 8) & 0xff)) $(((val >> 16) & 0xff)) $(((val >> 24) & 0xff))
}

uint_to_bpftool_u64()
{
printf "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n" \
$((val & 0xff)) $(((val >> 8) & 0xff)) $(((val >> 16) & 0xff)) $(((val >> 24) & 0xff)) \
$(((val >> 32) & 0xff)) $(((val >> 40) & 0xff)) $(((val >> 48) & 0xff)) $(((val >> 56) & 0xff))
}

# All the filter maps use a u8 as the value, so just set that single byte to 1
add_to_filter_map()
{
local map="$1"
local key="$2"

bpftool map update name "$map" key $key value 1
}

if (( $# < 2 )); then
print_usage
exit 1
fi

type=$1
if [[ -z "${bpf_maps[$type]}" ]]; then
echo "Error: unrecognized type $type, must be one of: ${!bpf_maps[*]}"
exit 1
fi

map=${bpf_maps[$type]}
converter=${key_converters[$type]}

for val in "${@:2}"; do
key=$($converter "$val")
if ! add_to_filter_map "$map" "$key"; then
echo "Error adding $val ($key) to map $map"
exit 1
fi
done
Loading