diff options
author | David Ahern <dsahern@gmail.com> | 2019-05-24 14:43:06 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-05-28 21:37:30 -0700 |
commit | 53010f991a9f5e4ed2db705ddde6ff32709192a2 (patch) | |
tree | f53445ab858d6ad371aaa7b7a8b8c7e391d3f65b /net | |
parent | 597cfe4fc3390a055f42546c254e48601b37009f (diff) |
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/nexthop.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c index 79c7b3461e19..f2b237a6735c 100644 --- a/net/ipv4/nexthop.c +++ b/net/ipv4/nexthop.c @@ -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"); |