Extend the bpf_fib_lookup() helper by making it to return the source IPv4/IPv6 address if the BPF_FIB_LOOKUP_SRC flag is set. For example, the following snippet can be used to derive the desired source IP address: struct bpf_fib_lookup p = { .ipv4_dst = ip4->daddr }; ret = bpf_skb_fib_lookup(skb, p, sizeof(p), BPF_FIB_LOOKUP_SRC | BPF_FIB_LOOKUP_SKIP_NEIGH); if (ret != BPF_FIB_LKUP_RET_SUCCESS) return TC_ACT_SHOT; /* the p.ipv4_src now contains the source address */ The inability to derive the proper source address may cause malfunctions in BPF-based dataplanes for hosts containing netdevs with more than one routable IP address or for multi-homed hosts. For example, Cilium implements packet masquerading in BPF. If an egressing netdev to which the Cilium's BPF prog is attached has multiple IP addresses, then only one [hardcoded] IP address can be used for masquerading. This breaks connectivity if any other IP address should have been selected instead, for example, when a public and private addresses are attached to the same egress interface. The change was tested with Cilium [1]. Nikolay Aleksandrov helped to figure out the IPv6 addr selection. [1]: https://github.com/cilium/cilium/pull/28283
Showing the changes to include/uapi (1 of 5 files). Show all
Unified · Split
| @@ -3264,6 +3264,11 @@ union bpf_attr { · 3263 unmodified lines | ||
| 3264 | 3264 | * and *params*->smac will not be set as output. A common |
| 3265 | 3265 | * use case is to call **bpf_redirect_neigh**\ () after |
| 3266 | 3266 | * doing **bpf_fib_lookup**\ (). |
| 3267 | + * **BPF_FIB_LOOKUP_SRC** | |
| 3268 | + * Derive and set source IP addr in *params*->ipv{4,6}_src | |
| 3269 | + * for the nexthop. If the src addr cannot be derived, | |
| 3270 | + * **BPF_FIB_LKUP_RET_NO_SRC_ADDR** is returned. In this | |
| 3271 | + * case, *params*->dmac and *params*->smac are not set either. | |
| 3267 | 3272 | * |
| 3268 | 3273 | * *ctx* is either **struct xdp_md** for XDP programs or |
| 3269 | 3274 | * **struct sk_buff** tc cls_act programs. |
| @@ -6964,6 +6969,7 @@ enum { · 3694 unmodified lines | ||
| 6964 | 6969 | BPF_FIB_LOOKUP_OUTPUT = (1U << 1), |
| 6965 | 6970 | BPF_FIB_LOOKUP_SKIP_NEIGH = (1U << 2), |
| 6966 | 6971 | BPF_FIB_LOOKUP_TBID = (1U << 3), |
| 6972 | + BPF_FIB_LOOKUP_SRC = (1U << 4), | |
| 6967 | 6973 | }; |
| 6968 | 6974 | |
| 6969 | 6975 | enum { |
| @@ -6976,6 +6982,7 @@ enum { · 6 unmodified lines | ||
| 6976 | 6982 | BPF_FIB_LKUP_RET_UNSUPP_LWT, /* fwd requires encapsulation */ |
| 6977 | 6983 | BPF_FIB_LKUP_RET_NO_NEIGH, /* no neighbor entry for nh */ |
| 6978 | 6984 | BPF_FIB_LKUP_RET_FRAG_NEEDED, /* fragmentation required to fwd */ |
| 6985 | + BPF_FIB_LKUP_RET_NO_SRC_ADDR, /* failed to derive IP src addr */ | |
| 6979 | 6986 | }; |
| 6980 | 6987 | |
| 6981 | 6988 | struct bpf_fib_lookup { |
| @@ -7010,6 +7017,9 @@ struct bpf_fib_lookup { · 28 unmodified lines | ||
| 7010 | 7017 | __u32 rt_metric; |
| 7011 | 7018 | }; |
| 7012 | 7019 | |
| 7020 | + /* input: source address to consider for lookup | |
| 7021 | + * output: source address result from lookup | |
| 7022 | + */ | |
| 7013 | 7023 | union { |
| 7014 | 7024 | __be32 ipv4_src; |
| 7015 | 7025 | __u32 ipv6_src[4]; /* in6_addr; network order */ |