nexthop: Add support for IPv6 gateways
Handle IPv6 gateway in a nexthop spec. If nh_family is set to AF_INET6, NHA_GATEWAY is expected to be an IPv6 address. Add ipv6 option to gw in nh_config to hold the address, add fib6_nh to nh_info to leverage the ipv6 initialization and cleanup code. Update nh_fill_node to dump the v6 address. Signed-off-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
597cfe4fc3
commit
53010f991a
|
@ -12,6 +12,7 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/ip_fib.h>
|
||||
#include <net/ip6_fib.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#define NEXTHOP_VALID_USER_FLAGS RTNH_F_ONLINK
|
||||
|
@ -31,6 +32,7 @@ struct nh_config {
|
|||
|
||||
union {
|
||||
__be32 ipv4;
|
||||
struct in6_addr ipv6;
|
||||
} gw;
|
||||
|
||||
u32 nlflags;
|
||||
|
@ -47,6 +49,7 @@ struct nh_info {
|
|||
union {
|
||||
struct fib_nh_common fib_nhc;
|
||||
struct fib_nh fib_nh;
|
||||
struct fib6_nh fib6_nh;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/nexthop.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/ipv6_stubs.h>
|
||||
#include <net/nexthop.h>
|
||||
#include <net/route.h>
|
||||
#include <net/sock.h>
|
||||
|
@ -61,6 +62,9 @@ void nexthop_free_rcu(struct rcu_head *head)
|
|||
case AF_INET:
|
||||
fib_nh_release(nh->net, &nhi->fib_nh);
|
||||
break;
|
||||
case AF_INET6:
|
||||
ipv6_stub->fib6_nh_release(&nhi->fib6_nh);
|
||||
break;
|
||||
}
|
||||
kfree(nhi);
|
||||
|
||||
|
@ -127,6 +131,7 @@ static u32 nh_find_unused_id(struct net *net)
|
|||
static int nh_fill_node(struct sk_buff *skb, struct nexthop *nh,
|
||||
int event, u32 portid, u32 seq, unsigned int nlflags)
|
||||
{
|
||||
struct fib6_nh *fib6_nh;
|
||||
struct fib_nh *fib_nh;
|
||||
struct nlmsghdr *nlh;
|
||||
struct nh_info *nhi;
|
||||
|
@ -168,6 +173,13 @@ static int nh_fill_node(struct sk_buff *skb, struct nexthop *nh,
|
|||
nla_put_u32(skb, NHA_GATEWAY, fib_nh->fib_nh_gw4))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
fib6_nh = &nhi->fib6_nh;
|
||||
if (fib6_nh->fib_nh_gw_family &&
|
||||
nla_put_in6_addr(skb, NHA_GATEWAY, &fib6_nh->fib_nh_gw6))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -193,6 +205,12 @@ static size_t nh_nlmsg_size(struct nexthop *nh)
|
|||
if (nhi->fib_nh.fib_nh_gw_family)
|
||||
sz += nla_total_size(4); /* NHA_GATEWAY */
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
/* NHA_GATEWAY */
|
||||
if (nhi->fib6_nh.fib_nh_gw_family)
|
||||
sz += nla_total_size(sizeof(const struct in6_addr));
|
||||
break;
|
||||
}
|
||||
|
||||
return sz;
|
||||
|
@ -374,6 +392,33 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int nh_create_ipv6(struct net *net, struct nexthop *nh,
|
||||
struct nh_info *nhi, struct nh_config *cfg,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct fib6_nh *fib6_nh = &nhi->fib6_nh;
|
||||
struct fib6_config fib6_cfg = {
|
||||
.fc_table = l3mdev_fib_table(cfg->dev),
|
||||
.fc_ifindex = cfg->nh_ifindex,
|
||||
.fc_gateway = cfg->gw.ipv6,
|
||||
.fc_flags = cfg->nh_flags,
|
||||
};
|
||||
int err = -EINVAL;
|
||||
|
||||
if (!ipv6_addr_any(&cfg->gw.ipv6))
|
||||
fib6_cfg.fc_flags |= RTF_GATEWAY;
|
||||
|
||||
/* sets nh_dev if successful */
|
||||
err = ipv6_stub->fib6_nh_init(net, fib6_nh, &fib6_cfg, GFP_KERNEL,
|
||||
extack);
|
||||
if (err)
|
||||
ipv6_stub->fib6_nh_release(fib6_nh);
|
||||
else
|
||||
nh->nh_flags = fib6_nh->fib_nh_flags;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct nexthop *nexthop_create(struct net *net, struct nh_config *cfg,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
|
@ -407,6 +452,9 @@ static struct nexthop *nexthop_create(struct net *net, struct nh_config *cfg,
|
|||
case AF_INET:
|
||||
err = nh_create_ipv4(net, nh, nhi, cfg, extack);
|
||||
break;
|
||||
case AF_INET6:
|
||||
err = nh_create_ipv6(net, nh, nhi, cfg, extack);
|
||||
break;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
|
@ -487,6 +535,7 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
|
|||
|
||||
switch (nhm->nh_family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
break;
|
||||
default:
|
||||
NL_SET_ERR_MSG(extack, "Invalid address family");
|
||||
|
@ -556,6 +605,13 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
|
|||
}
|
||||
cfg->gw.ipv4 = nla_get_be32(gwa);
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (nla_len(gwa) != sizeof(struct in6_addr)) {
|
||||
NL_SET_ERR_MSG(extack, "Invalid gateway");
|
||||
goto out;
|
||||
}
|
||||
cfg->gw.ipv6 = nla_get_in6_addr(gwa);
|
||||
break;
|
||||
default:
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"Unknown address family for gateway");
|
||||
|
|
Loading…
Reference in New Issue