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)
127131static 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
173185out :
@@ -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+
377422static 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