The trick with printing debug output as a u64 got it in the wrong byte
order; fix that by swapping everything appropriately before printing. Also
add some more information to the drop debug print.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
There were a couple of issues with the IGMP and multicast handling: the
packet parsing checked the MAC address for whether it was a multicast
address before it looked at the IP header, which meant it never got to the
IGMP packets (because they are also sent as multicast). Also, we need to
redirect IGMP packets to the bond master on egress to make sure
subscriptions work as they're supposed to.
Fix the parsing, add the redirect, and also remove the explicit check for
IGMP packets on ingress, as that will already be matched by the multicast
check.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
This reverts commit d3aaec4bdd ("pkt-loop-filter: Check ifindex against
state before dropping packets") - we should not accept packets that are
looped back to the same port either.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
The exception for gratuitous ARPs are only supposed to be for entries that
would otherwise be dropped due to the loop filtering logic. In addition, we
should record egress gratuitous ARPs and make sure they don't trigger the
exception when looping back (this is 'rule 4' of the openvswitch SLB
bonding logic).
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
We were indiscriminately dropping packets when the map lookup succeeded,
let's actually check the ifindex first.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
We shouldn't be filtering incoming gratuitous ARPs based on the ifindex
learning. So parse ARP packets and allow them through if they have
identical source and destination IPs.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
When pinning of the bpf_link fails, we keep running to keep the PID alive.
However, staying in the foreground causes problems with scripts that
expects the setup to finish running; so fork into the background instead
and write a PID file so we can kill the running instance on unload.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
When running in the fallback mode where we keep running in the foreground
to keep the kprobe alive, we should unload the cls_bpf programs after being
interrupted instead of just exiting.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Support for bpf_link-based attaching of kprobes was added to kernel 5.15
with commit: b89fbfbb854c ("bpf: Implement minimal BPF perf link"). Prior
to this, it is not possible to pin kprobe attachments in bpffs, which
causes the pkt-loop-filter to fail. Add a fallback where we just keep
running in the foreground to keep the probe alive if bpf_link pinning
fails.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
The type of the net->net_cookie field member was changed in kernel 5.12
with commit 3d368ab87cf6 ("net: initialize net->net_cookie at netns setup").
Older versions of the kernel devices net->net_cookie as an atomic64_t
instead of a u64. This causes CO-RE reading of the field to fail due to the
type mismatch. Handle this by adding CO-RE checks for the old type as well
and using the CO-RE facility to check for the right type at load time.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
The ktime_get_coarse_ns() helper function was not backported to RHEL8, so
just switch to using ktime_get_boot_ns() instead.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
The previous commit working around missing SO_NETNS_COOKIE failed to reset
the err variable, which means things still failed.
Reported-by: Hangbin Liu <haliu@redhat.com>
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
The SO_NETNS_COOKIE sockopt is fairly new; make sure we can compile the
program without it being defined, and fall back (with a warning) to just
always returning 1 as the netns cookie if the option doesn't work, which
should keep things working in the init namespace at least.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Instead of having to pass the component interfaces to the userspace
program, we can just pass the bond ifname, and have the loader detect which
bond component interfaces are in the bond, and automatically load the BPF
program on each one. Reusing the active bond detection code from the
previous commit also allows us to automatically detect the right initial
active interface, and keep this up-to-date by hooking into the bonding code
that changes it when an iface goes down, instead of naively rotating
between active interfaces.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Add a small utility that uses a kprobe to extract the currently active
slave ifindex from a bond interface. This value is normally only exported
to userspace for bond types where it can be explicitly set, but the bond
driver has an internal notion of an active interface regardless of the bond
type. We can extract this value with a kprobe by attaching to a function in
the bond driver and triggering an operation that causes this function to be
called.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Filter not only the multicast packets themselves, but also any IGMP (and
ICMPv6 MLD) packets coming in on multiple interfaces.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Add a debug mode to pkt-loop-filter that outputs debug messages for every
dropped packet (with the reason it was dropped). Also add a small script to
read the kernel trace pipe, after making sure tracing is active (otherwise
there will be no output in the pipe).
The source MAC address+VLAN is squeezed into a single u64 when printing as
a quick workaround to the lack of MAC address printing in BPF printk.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Multicast, which also includes broadcast, frames can be identified by
looking at the LSB of the first octet of the destination MAC address.
Original-patch-by: Jonathan Toppins <jtoppins@redhat.com>
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
This adds filtering of multicast traffic to the set of interfaces. The
filtering works by marking one of the interfaces as "primary" (which is
just the first interface name that is supplied on the command line) and
filtering everything with an all-ones destination MAC address if it's
coming in on any interface that's not the primary one.
To handle interfaces going down, we actually supply all the ifindexes to
the BPF program, and also install a tracing hook that listens to ifdown
events and switches the logic to the next ifindex in the sequence if the
primary one goes down. This is a bit rudimentary but should at least
provide basic filtering.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
This makes it easier to populate the global variables we'll need for
handling multicast, and also means we don't have to worry about keeping the
BPF object file around (since it'll be statically linked).
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
This is needed to be able to react to interfaces going down so we can
allow multicast on a secondary interface if the primary goes down. We don't
actually react to the event yet, just print it; handling this will be added
in a subsequent commit.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Add an example to filter looping packets on (for instance) a bond
interface, by recording the egress MAC+VLAN and dropping any packets that
come in on other (related) interfaces with the same MAC+VLAN.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>