netlink icon indicating copy to clipboard operation
netlink copied to clipboard

gateway, source, and destination ip are not the same IP family

Open aep opened this issue 2 years ago • 5 comments

using a v6 gateway for a v4 route is legal

see https://datatracker.ietf.org/doc/html/rfc5549

iproute2 command:

ip route add 0.0.0.0/0 via inet6 fe80::f00

can we remove this check?

https://github.com/vishvananda/netlink/blob/6afddb37c1f00693528264222a57a3c08dccbab7/route_linux.go#L793

aep avatar Sep 02 '23 19:09 aep

As discussed in the linked issue, this is useful in many scenarios, especially in IPv6 datacenters

SkalaNetworks avatar Jan 06 '25 09:01 SkalaNetworks

@aep @SkalaNetworks Please push a PR for it.

aboch avatar Jan 06 '25 19:01 aboch

Will do

-------- Original Message -------- On 1/6/25 20:20, Alessandro Boch wrote:

@.(https://github.com/aep) @.(https://github.com/SkalaNetworks) Please push a PR for it.

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

SkalaNetworks avatar Jan 06 '25 19:01 SkalaNetworks

Ok @aboch, I played a bit with the Gw field of the route structure, first on a Linux kernel pre-version 5, and it wasn't working. I tried by hand and the kernel threw an exception about RT_VIA not being supported. So I retested on a newer kernel by hand, and it worked.

But the code still doesn't work. Apparently, digging into netlink, the GW attribute doesn't support anything else than the inet family of the destination.

I did manage to add an inet4 route with an inet6 nexthop using the following code:

        // for an IPv6 nexthop, we need a route to the nexthop
	routeToV6Gateway := &net.IPNet{
		IP: net.ParseIP("fd:1::"),
		Mask: net.CIDRMask(64, 128),
	}

	r := Route{LinkIndex: link.Attrs().Index, Dst: routeToV6Gateway}
	if err := RouteAdd(&r); err != nil {
		t.Fatal(err)
	}

	v := Via{
		AddrFamily: FAMILY_V6,
		Addr: net.ParseIP("fd:1::"),
	}

	route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Via: &v}
	if err := RouteAdd(&route); err != nil {
		t.Fatal(err)
	}
	routes, err := RouteList(link, FAMILY_V4)
	if err != nil {
		t.Fatal(err)
	}
	if len(routes) != 1 {
		t.Fatal("Route not added properly")
	}

	routes, err = RouteList(nil, FAMILY_V4)
	if err != nil {
		t.Fatal(err)
	}
	if len(routes) != 1 {
		t.Fatal("Route not listed properly")
	}

It uses the RTA_VIA attribute, which does support an inet6 nexthop. I need to run more tests, but from what I can gather, RTA_VIA is now the (default?) way to go when typing commands such as ip route add xxx via, and gw is a fallback.

If this is the case, and that's what the "ip route" command does, this usecase is under-tested in the current netlink implementation considering it is only used for multipath in the route_test.go file.

SkalaNetworks avatar Jan 06 '25 22:01 SkalaNetworks

Relevant 10 yo linux commit that added the RTA_VIA attribute: https://github.com/torvalds/linux/commit/03c0566542f4c7a45ce3193f27cbf5700b506c18

Relevant part of the commit message:

RTA_VIA specifies the specifies the next machine to send a packet to
like RTA_GATEWAY.  RTA_VIA differs from RTA_GATEWAY in that it
includes the address family of the address of the next machine to send
a packet to.

rtnetlink(7) manual: RTA_VIA struct rtvia Gateway in different AF (see below)

Also just checked the code of iproute2, it uses RTA_VIA attribute when specifying the "via" token in the command line. So every example in the code where the comments say something like "add route via XXX" while using the RTA_GATEWAY attribute are kinda confusing. Gotta keep in mind that "via" =/= "gw" in behaviour.

SkalaNetworks avatar Jan 06 '25 23:01 SkalaNetworks