mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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: David Ahern <dsahern@gmail.com> Reviewed-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f35b794b3b
commit
0f5f7d7bf6
5 changed files with 38 additions and 8 deletions
|
@ -318,6 +318,9 @@ mlxsw_sp_span_gretap4_route(const struct net_device *to_dev,
|
||||||
*saddrp = fl4.saddr;
|
*saddrp = fl4.saddr;
|
||||||
if (rt->rt_gw_family == AF_INET)
|
if (rt->rt_gw_family == AF_INET)
|
||||||
*daddrp = rt->rt_gw4;
|
*daddrp = rt->rt_gw4;
|
||||||
|
/* can not offload if route has an IPv6 gateway */
|
||||||
|
else if (rt->rt_gw_family == AF_INET6)
|
||||||
|
dev = NULL;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
ip_rt_put(rt);
|
ip_rt_put(rt);
|
||||||
|
|
|
@ -60,7 +60,10 @@ struct rtable {
|
||||||
int rt_iif;
|
int rt_iif;
|
||||||
|
|
||||||
/* Info on neighbour */
|
/* Info on neighbour */
|
||||||
__be32 rt_gw4;
|
union {
|
||||||
|
__be32 rt_gw4;
|
||||||
|
struct in6_addr rt_gw6;
|
||||||
|
};
|
||||||
|
|
||||||
/* Miscellaneous cached information */
|
/* Miscellaneous cached information */
|
||||||
u32 rt_mtu_locked:1,
|
u32 rt_mtu_locked:1,
|
||||||
|
|
|
@ -1535,14 +1535,20 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
|
||||||
|
|
||||||
if (fi) {
|
if (fi) {
|
||||||
struct fib_nh_common *nhc = FIB_RES_NHC(*res);
|
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) {
|
if (nhc->nhc_gw_family && nhc->nhc_scope == RT_SCOPE_LINK) {
|
||||||
rt->rt_gw4 = nh->fib_nh_gw4;
|
rt->rt_gw_family = nhc->nhc_gw_family;
|
||||||
rt->rt_gw_family = AF_INET;
|
/* 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);
|
ip_dst_init_metrics(&rt->dst, fi->fib_metrics);
|
||||||
|
|
||||||
|
nh = container_of(nhc, struct fib_nh, nh_common);
|
||||||
#ifdef CONFIG_IP_ROUTE_CLASSID
|
#ifdef CONFIG_IP_ROUTE_CLASSID
|
||||||
rt->dst.tclassid = nh->nh_tclassid;
|
rt->dst.tclassid = nh->nh_tclassid;
|
||||||
#endif
|
#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;
|
rt->rt_gw_family = ort->rt_gw_family;
|
||||||
if (rt->rt_gw_family == AF_INET)
|
if (rt->rt_gw_family == AF_INET)
|
||||||
rt->rt_gw4 = ort->rt_gw4;
|
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);
|
INIT_LIST_HEAD(&rt->rt_uncached);
|
||||||
}
|
}
|
||||||
|
@ -2679,8 +2687,21 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src,
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
}
|
}
|
||||||
if (rt->rt_gw_family == AF_INET &&
|
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;
|
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;
|
expires = rt->dst.expires;
|
||||||
if (expires) {
|
if (expires) {
|
||||||
|
|
|
@ -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;
|
xdst->u.rt.rt_gw_family = rt->rt_gw_family;
|
||||||
if (rt->rt_gw_family == AF_INET)
|
if (rt->rt_gw_family == AF_INET)
|
||||||
xdst->u.rt.rt_gw4 = rt->rt_gw4;
|
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_pmtu = rt->rt_pmtu;
|
||||||
xdst->u.rt.rt_mtu_locked = rt->rt_mtu_locked;
|
xdst->u.rt.rt_mtu_locked = rt->rt_mtu_locked;
|
||||||
INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);
|
INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);
|
||||||
|
|
|
@ -141,8 +141,9 @@ static int mpls_xmit(struct sk_buff *skb)
|
||||||
if (rt->rt_gw_family == AF_INET)
|
if (rt->rt_gw_family == AF_INET)
|
||||||
err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt->rt_gw4,
|
err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt->rt_gw4,
|
||||||
skb);
|
skb);
|
||||||
else
|
else if (rt->rt_gw_family == AF_INET6)
|
||||||
err = -EAFNOSUPPORT;
|
err = neigh_xmit(NEIGH_ND_TABLE, out_dev, &rt->rt_gw6,
|
||||||
|
skb);
|
||||||
} else if (rt6) {
|
} else if (rt6) {
|
||||||
if (ipv6_addr_v4mapped(&rt6->rt6i_gateway)) {
|
if (ipv6_addr_v4mapped(&rt6->rt6i_gateway)) {
|
||||||
/* 6PE (RFC 4798) */
|
/* 6PE (RFC 4798) */
|
||||||
|
|
Loading…
Add table
Reference in a new issue