8
8
#include <linux/nexthop.h>
9
9
#include <linux/rtnetlink.h>
10
10
#include <linux/slab.h>
11
+ #include <net/ipv6_stubs.h>
11
12
#include <net/nexthop.h>
12
13
#include <net/route.h>
13
14
#include <net/sock.h>
@@ -61,6 +62,9 @@ void nexthop_free_rcu(struct rcu_head *head)
61
62
case AF_INET :
62
63
fib_nh_release (nh -> net , & nhi -> fib_nh );
63
64
break ;
65
+ case AF_INET6 :
66
+ ipv6_stub -> fib6_nh_release (& nhi -> fib6_nh );
67
+ break ;
64
68
}
65
69
kfree (nhi );
66
70
@@ -127,6 +131,7 @@ static u32 nh_find_unused_id(struct net *net)
127
131
static int nh_fill_node (struct sk_buff * skb , struct nexthop * nh ,
128
132
int event , u32 portid , u32 seq , unsigned int nlflags )
129
133
{
134
+ struct fib6_nh * fib6_nh ;
130
135
struct fib_nh * fib_nh ;
131
136
struct nlmsghdr * nlh ;
132
137
struct nh_info * nhi ;
@@ -168,6 +173,13 @@ static int nh_fill_node(struct sk_buff *skb, struct nexthop *nh,
168
173
nla_put_u32 (skb , NHA_GATEWAY , fib_nh -> fib_nh_gw4 ))
169
174
goto nla_put_failure ;
170
175
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 ;
171
183
}
172
184
173
185
out :
@@ -193,6 +205,12 @@ static size_t nh_nlmsg_size(struct nexthop *nh)
193
205
if (nhi -> fib_nh .fib_nh_gw_family )
194
206
sz += nla_total_size (4 ); /* NHA_GATEWAY */
195
207
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 ;
196
214
}
197
215
198
216
return sz ;
@@ -374,6 +392,33 @@ static int nh_create_ipv4(struct net *net, struct nexthop *nh,
374
392
return err ;
375
393
}
376
394
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
+
377
422
static struct nexthop * nexthop_create (struct net * net , struct nh_config * cfg ,
378
423
struct netlink_ext_ack * extack )
379
424
{
@@ -407,6 +452,9 @@ static struct nexthop *nexthop_create(struct net *net, struct nh_config *cfg,
407
452
case AF_INET :
408
453
err = nh_create_ipv4 (net , nh , nhi , cfg , extack );
409
454
break ;
455
+ case AF_INET6 :
456
+ err = nh_create_ipv6 (net , nh , nhi , cfg , extack );
457
+ break ;
410
458
}
411
459
412
460
if (err ) {
@@ -487,6 +535,7 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
487
535
488
536
switch (nhm -> nh_family ) {
489
537
case AF_INET :
538
+ case AF_INET6 :
490
539
break ;
491
540
default :
492
541
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,
556
605
}
557
606
cfg -> gw .ipv4 = nla_get_be32 (gwa );
558
607
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 ;
559
615
default :
560
616
NL_SET_ERR_MSG (extack ,
561
617
"Unknown address family for gateway" );
0 commit comments