Skip to content

Commit 53010f9

Browse files
dsaherndavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 597cfe4 commit 53010f9

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

include/net/nexthop.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/netdevice.h>
1313
#include <linux/types.h>
1414
#include <net/ip_fib.h>
15+
#include <net/ip6_fib.h>
1516
#include <net/netlink.h>
1617

1718
#define NEXTHOP_VALID_USER_FLAGS RTNH_F_ONLINK
@@ -31,6 +32,7 @@ struct nh_config {
3132

3233
union {
3334
__be32 ipv4;
35+
struct in6_addr ipv6;
3436
} gw;
3537

3638
u32 nlflags;
@@ -47,6 +49,7 @@ struct nh_info {
4749
union {
4850
struct fib_nh_common fib_nhc;
4951
struct fib_nh fib_nh;
52+
struct fib6_nh fib6_nh;
5053
};
5154
};
5255

net/ipv4/nexthop.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/nexthop.h>
99
#include <linux/rtnetlink.h>
1010
#include <linux/slab.h>
11+
#include <net/ipv6_stubs.h>
1112
#include <net/nexthop.h>
1213
#include <net/route.h>
1314
#include <net/sock.h>
@@ -61,6 +62,9 @@ void nexthop_free_rcu(struct rcu_head *head)
6162
case AF_INET:
6263
fib_nh_release(nh->net, &nhi->fib_nh);
6364
break;
65+
case AF_INET6:
66+
ipv6_stub->fib6_nh_release(&nhi->fib6_nh);
67+
break;
6468
}
6569
kfree(nhi);
6670

@@ -127,6 +131,7 @@ static u32 nh_find_unused_id(struct net *net)
127131
static int nh_fill_node(struct sk_buff *skb, struct nexthop *nh,
128132
int event, u32 portid, u32 seq, unsigned int nlflags)
129133
{
134+
struct fib6_nh *fib6_nh;
130135
struct fib_nh *fib_nh;
131136
struct nlmsghdr *nlh;
132137
struct nh_info *nhi;
@@ -168,6 +173,13 @@ static int nh_fill_node(struct sk_buff *skb, struct nexthop *nh,
168173
nla_put_u32(skb, NHA_GATEWAY, fib_nh->fib_nh_gw4))
169174
goto nla_put_failure;
170175
break;
176+
177+
case AF_INET6:
178+
fib6_nh = &nhi->fib6_nh;
179+
if (fib6_nh->fib_nh_gw_family &&
180+
nla_put_in6_addr(skb, NHA_GATEWAY, &fib6_nh->fib_nh_gw6))
181+
goto nla_put_failure;
182+
break;
171183
}
172184

173185
out:
@@ -193,6 +205,12 @@ static size_t nh_nlmsg_size(struct nexthop *nh)
193205
if (nhi->fib_nh.fib_nh_gw_family)
194206
sz += nla_total_size(4); /* NHA_GATEWAY */
195207
break;
208+
209+
case AF_INET6:
210+
/* NHA_GATEWAY */
211+
if (nhi->fib6_nh.fib_nh_gw_family)
212+
sz += nla_total_size(sizeof(const struct in6_addr));
213+
break;
196214
}
197215

198216
return sz;
@@ -374,6 +392,33 @@ static int nh_create_ipv4(struct net *net, struct nexthop *nh,
374392
return err;
375393
}
376394

395+
static int nh_create_ipv6(struct net *net, struct nexthop *nh,
396+
struct nh_info *nhi, struct nh_config *cfg,
397+
struct netlink_ext_ack *extack)
398+
{
399+
struct fib6_nh *fib6_nh = &nhi->fib6_nh;
400+
struct fib6_config fib6_cfg = {
401+
.fc_table = l3mdev_fib_table(cfg->dev),
402+
.fc_ifindex = cfg->nh_ifindex,
403+
.fc_gateway = cfg->gw.ipv6,
404+
.fc_flags = cfg->nh_flags,
405+
};
406+
int err = -EINVAL;
407+
408+
if (!ipv6_addr_any(&cfg->gw.ipv6))
409+
fib6_cfg.fc_flags |= RTF_GATEWAY;
410+
411+
/* sets nh_dev if successful */
412+
err = ipv6_stub->fib6_nh_init(net, fib6_nh, &fib6_cfg, GFP_KERNEL,
413+
extack);
414+
if (err)
415+
ipv6_stub->fib6_nh_release(fib6_nh);
416+
else
417+
nh->nh_flags = fib6_nh->fib_nh_flags;
418+
419+
return err;
420+
}
421+
377422
static struct nexthop *nexthop_create(struct net *net, struct nh_config *cfg,
378423
struct netlink_ext_ack *extack)
379424
{
@@ -407,6 +452,9 @@ static struct nexthop *nexthop_create(struct net *net, struct nh_config *cfg,
407452
case AF_INET:
408453
err = nh_create_ipv4(net, nh, nhi, cfg, extack);
409454
break;
455+
case AF_INET6:
456+
err = nh_create_ipv6(net, nh, nhi, cfg, extack);
457+
break;
410458
}
411459

412460
if (err) {
@@ -487,6 +535,7 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
487535

488536
switch (nhm->nh_family) {
489537
case AF_INET:
538+
case AF_INET6:
490539
break;
491540
default:
492541
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,
556605
}
557606
cfg->gw.ipv4 = nla_get_be32(gwa);
558607
break;
608+
case AF_INET6:
609+
if (nla_len(gwa) != sizeof(struct in6_addr)) {
610+
NL_SET_ERR_MSG(extack, "Invalid gateway");
611+
goto out;
612+
}
613+
cfg->gw.ipv6 = nla_get_in6_addr(gwa);
614+
break;
559615
default:
560616
NL_SET_ERR_MSG(extack,
561617
"Unknown address family for gateway");

0 commit comments

Comments
 (0)