[PATCH] net/ipv6/ip6_gre.c NBMA support
From: Aleksey Shumnik <hidden>
Date: 2022-08-30 15:21:05
Subsystem:
networking [general], networking [ipv4/ipv6], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Linus Torvalds
Dear Maintainers,
While I was studying the capabilities of the ip6_gre driver to support
NBMA networks, I found a bug:
When sending a packet over the NBMA network, the following sequence of
functions occurs:
ip6gre_tunnel_xmit() -> ip6_tnl_xmit_ctl() -> ip6_tnl_get_cap() ->
...
if (ltype == IPV6_ADDR_ANY || rtype == IPV6_ADDR_ANY) {
flags = IP6_TNL_F_CAP_PER_PACKET;
...
After that, the packages are dropped, but if skip ip6_tnl_xmit_ctl()
ip6gre_tunnel_xmit() -> ip6gre_xmit_ipv4() / ip6gre_xmit_ipv6() /
ip6gre_xmit_other() -> __gre6_xmit() -> ip6_tnl_xmit() ->
...
/* NBMA tunnel */
if (ipv6_addr_any(&t->parms.raddr)) {
...
It is strange that at first when checking addr_type == IPV6_ADDR_ANY
packages are dropped, but after that there is ipv6_addr_any(addr)
which leads to neigh_lookup() end etc.
It turns out that the same check leads to different actions. In
addition, due to the fact that the package is dropped, there is no
neighbor_lookup and the package will not be sent.
It looks like ip6_gre supports NBMA, but does not allow it to work,
because of this and other possible bugs.
This is most likely not the final patch, but for now I offer such a
patch to solve the problem.
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index a9051df..34c6c5b 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c@@ -896,8 +896,14 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb, if (!pskb_inet_may_pull(skb)) goto tx_err; - if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr)) - goto tx_err; + if (dev->header_ops) { + const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb->data; + if (!ip6_tnl_xmit_ctl(t, &ipv6h->saddr, &ipv6h->daddr)) + goto tx_err; + } else { + if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr)) + goto tx_err; + } switch (skb->protocol) { case htons(ETH_P_IP):
If the network is NBMA, then the remote address is not set in the tunnel parameters, and then the packets will always drop on the ip6_tnl_xmit_ctl() function, I propose a solution, if there is an ipv6 header in skb, then take the destination and source addresses from skb, and not from the tunnel parameters.