mirror of
https://github.com/netdata/libbpf.git
synced 2026-11-05 17:30:15 +08:00
bpf: Add BPF_FIB_LOOKUP_VLAN_INPUT flag to bpf_fib_lookup() helper
BPF_FIB_LOOKUP_VLAN resolves a VLAN egress. The reverse is also useful: an XDP program receiving a VLAN-tagged frame on a physical device wants the lookup to behave as if the packet had arrived on the corresponding VLAN subinterface, so iif-based policy routing and VRF table selection use the right ingress. Add BPF_FIB_LOOKUP_VLAN_INPUT. When set, params->h_vlan_proto and params->h_vlan_TCI are read as an input VLAN tag and the matching VLAN device of params->ifindex is resolved with __vlan_find_dev_deep_rcu(). The device must be up and in the same network namespace as params->ifindex (a VLAN device can be moved to another netns while registered on its parent; receive would deliver into that other namespace, which a lookup here cannot represent). If params->ifindex is itself a VLAN device, its inner (QinQ) subinterface is matched. For a bond or team, a tag on a port matches no device and returns NOT_FWDED; pass the master's ifindex. The lookup then runs with the resolved device as the ingress; params->ifindex itself is not modified on the input side. When the resolved device is enslaved to a VRF, both the full lookup (via the l3mdev rule) and BPF_FIB_LOOKUP_DIRECT (via l3mdev_fib_table_rcu()) select the VRF's table from the resolved ingress. That follows from feeding the resolved device to the flow as the ingress (fl4.flowi4_iif = dev->ifindex), which is what makes l3mdev resolve the VRF master from the subinterface rather than from params->ifindex. The two failure classes get different treatment on purpose. A h_vlan_proto other than 802.1Q/802.1ad is API misuse and returns -EINVAL, since it would otherwise reach the WARN in vlan_proto_idx() with a program-controlled value. An unmatched VID, a device that is down, or one in another namespace is a data outcome and returns BPF_FIB_LKUP_RET_NOT_FWDED, matching the DIRECT path when fib_get_table() finds no table and mirroring real ingress, where the receive path drops such frames. A VID of 0 (a priority tag) is looked up literally and normally fails the same way; receive instead processes such frames untagged, so callers should not set the flag for priority tags. Proceeding on the physical device for any of these would be fail-open for the policy-routing cases above. The h_vlan fields share a union with tbid, so the flag cannot be combined with BPF_FIB_LOOKUP_TBID. It describes ingress, so it also cannot be combined with BPF_FIB_LOOKUP_OUTPUT. Both combinations return -EINVAL; restricting now keeps a later relaxation backward compatible. Combining with BPF_FIB_LOOKUP_VLAN is allowed: the tag is consumed on the ingress side and the egress tag is written on success. Under !CONFIG_VLAN_8021Q the __vlan_find_dev_deep_rcu() stub returns NULL, so every lookup with a valid proto returns NOT_FWDED, which is correct since no VLAN device can exist. Suggested-by: Toke Høiland-Jørgensen <toke@redhat.com> Signed-off-by: Avinash Duduskar <avinash.duduskar@gmail.com> Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com> Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com> Link: https://lore.kernel.org/bpf/20260713162305.1237211-3-avinash.duduskar@gmail.com Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
1 parent
a432251e60
commit
1810ef6cdb
1 file changed
+20
-1
@@ -3557,6 +3557,22 @@ union bpf_attr {
|
||||
* This flag is only valid for XDP programs; tc programs
|
||||
* receive -EINVAL since they can redirect to the VLAN
|
||||
* device directly.
|
||||
* **BPF_FIB_LOOKUP_VLAN_INPUT**
|
||||
* Treat *params*->h_vlan_proto and *params*->h_vlan_TCI
|
||||
* as an input VLAN tag and run the lookup as if ingress
|
||||
* had happened on the VLAN subinterface carrying that tag
|
||||
* on *params*->ifindex. The VID is the low 12 bits of
|
||||
* *params*->h_vlan_TCI; *params*->h_vlan_proto must be
|
||||
* ETH_P_8021Q or ETH_P_8021AD in network byte order, else
|
||||
* **-EINVAL**. If *params*->ifindex is itself a VLAN
|
||||
* device, its inner (QinQ) subinterface is matched; for a
|
||||
* bond or team, pass the master's ifindex. An unmatched
|
||||
* tag, a down device, or one in another namespace returns
|
||||
* **BPF_FIB_LKUP_RET_NOT_FWDED**, mirroring real ingress.
|
||||
* A VID of 0 is looked up literally, so do not set this
|
||||
* flag for priority-tagged frames. Cannot be combined with
|
||||
* **BPF_FIB_LOOKUP_TBID** or **BPF_FIB_LOOKUP_OUTPUT**
|
||||
* (returns **-EINVAL**).
|
||||
*
|
||||
* *ctx* is either **struct xdp_md** for XDP programs or
|
||||
* **struct sk_buff** tc cls_act programs.
|
||||
@@ -7365,6 +7381,7 @@ enum {
|
||||
BPF_FIB_LOOKUP_SRC = (1U << 4),
|
||||
BPF_FIB_LOOKUP_MARK = (1U << 5),
|
||||
BPF_FIB_LOOKUP_VLAN = (1U << 6),
|
||||
BPF_FIB_LOOKUP_VLAN_INPUT = (1U << 7),
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -7435,7 +7452,9 @@ struct bpf_fib_lookup {
|
||||
/*
|
||||
* output with BPF_FIB_LOOKUP_VLAN: set from the
|
||||
* resolved egress VLAN device (see the flag); zeroed
|
||||
* on other successful lookups.
|
||||
* on other successful lookups. input with
|
||||
* BPF_FIB_LOOKUP_VLAN_INPUT: the VLAN tag to scope
|
||||
* the lookup by.
|
||||
*/
|
||||
__be16 h_vlan_proto;
|
||||
__be16 h_vlan_TCI;
|
||||
|
||||
Reference in new issue
Block a user