Commit 0f5f7d7b authored by David Ahern's avatar David Ahern Committed by David S. Miller
Browse files

ipv4: Add support to rtable for ipv6 gateway



Add support for an IPv6 gateway to rtable. Since a gateway is either
IPv4 or IPv6, make it a union with rt_gw4 where rt_gw_family decides
which address is in use.

When dumping the route data, encode an ipv6 nexthop using RTA_VIA.

Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Reviewed-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f35b794b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -318,6 +318,9 @@ mlxsw_sp_span_gretap4_route(const struct net_device *to_dev,
	*saddrp = fl4.saddr;
	if (rt->rt_gw_family == AF_INET)
		*daddrp = rt->rt_gw4;
	/* can not offload if route has an IPv6 gateway */
	else if (rt->rt_gw_family == AF_INET6)
		dev = NULL;

out:
	ip_rt_put(rt);
+4 −1
Original line number Diff line number Diff line
@@ -60,7 +60,10 @@ struct rtable {
	int			rt_iif;

	/* Info on neighbour */
	union {
		__be32		rt_gw4;
		struct in6_addr	rt_gw6;
	};

	/* Miscellaneous cached information */
	u32			rt_mtu_locked:1,
+26 −5
Original line number Diff line number Diff line
@@ -1535,14 +1535,20 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,

	if (fi) {
		struct fib_nh_common *nhc = FIB_RES_NHC(*res);
		struct fib_nh *nh = container_of(nhc, struct fib_nh, nh_common);
		struct fib_nh *nh;

		if (nh->fib_nh_gw4 && nh->fib_nh_scope == RT_SCOPE_LINK) {
			rt->rt_gw4 = nh->fib_nh_gw4;
			rt->rt_gw_family = AF_INET;
		if (nhc->nhc_gw_family && nhc->nhc_scope == RT_SCOPE_LINK) {
			rt->rt_gw_family = nhc->nhc_gw_family;
			/* only INET and INET6 are supported */
			if (likely(nhc->nhc_gw_family == AF_INET))
				rt->rt_gw4 = nhc->nhc_gw.ipv4;
			else
				rt->rt_gw6 = nhc->nhc_gw.ipv6;
		}

		ip_dst_init_metrics(&rt->dst, fi->fib_metrics);

		nh = container_of(nhc, struct fib_nh, nh_common);
#ifdef CONFIG_IP_ROUTE_CLASSID
		rt->dst.tclassid = nh->nh_tclassid;
#endif
@@ -2600,6 +2606,8 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
		rt->rt_gw_family = ort->rt_gw_family;
		if (rt->rt_gw_family == AF_INET)
			rt->rt_gw4 = ort->rt_gw4;
		else if (rt->rt_gw_family == AF_INET6)
			rt->rt_gw6 = ort->rt_gw6;

		INIT_LIST_HEAD(&rt->rt_uncached);
	}
@@ -2679,9 +2687,22 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
			goto nla_put_failure;
	}
	if (rt->rt_gw_family == AF_INET &&
	    nla_put_in_addr(skb, RTA_GATEWAY, rt->rt_gw4))
	    nla_put_in_addr(skb, RTA_GATEWAY, rt->rt_gw4)) {
		goto nla_put_failure;
	} else if (rt->rt_gw_family == AF_INET6) {
		int alen = sizeof(struct in6_addr);
		struct nlattr *nla;
		struct rtvia *via;

		nla = nla_reserve(skb, RTA_VIA, alen + 2);
		if (!nla)
			goto nla_put_failure;

		via = nla_data(nla);
		via->rtvia_family = AF_INET6;
		memcpy(via->rtvia_addr, &rt->rt_gw6, alen);
	}

	expires = rt->dst.expires;
	if (expires) {
		unsigned long now = jiffies;
+2 −0
Original line number Diff line number Diff line
@@ -100,6 +100,8 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
	xdst->u.rt.rt_gw_family = rt->rt_gw_family;
	if (rt->rt_gw_family == AF_INET)
		xdst->u.rt.rt_gw4 = rt->rt_gw4;
	else if (rt->rt_gw_family == AF_INET6)
		xdst->u.rt.rt_gw6 = rt->rt_gw6;
	xdst->u.rt.rt_pmtu = rt->rt_pmtu;
	xdst->u.rt.rt_mtu_locked = rt->rt_mtu_locked;
	INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);
+3 −2
Original line number Diff line number Diff line
@@ -141,8 +141,9 @@ static int mpls_xmit(struct sk_buff *skb)
		if (rt->rt_gw_family == AF_INET)
			err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt->rt_gw4,
					 skb);
		else
			err = -EAFNOSUPPORT;
		else if (rt->rt_gw_family == AF_INET6)
			err = neigh_xmit(NEIGH_ND_TABLE, out_dev, &rt->rt_gw6,
					 skb);
	} else if (rt6) {
		if (ipv6_addr_v4mapped(&rt6->rt6i_gateway)) {
			/* 6PE (RFC 4798) */