2019-05-31 11:09:32 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2006-08-04 14:39:02 +04:00
/*
* net / ipv6 / fib6_rules . c IPv6 Routing Policy Rules
*
* Copyright ( C ) 2003 - 2006 Helsinki University of Technology
* Copyright ( C ) 2003 - 2006 USAGI / WIDE Project
*
* Authors
* Thomas Graf < tgraf @ suug . ch >
* Ville Nuorvala < vnuorval @ tcs . hut . fi >
*/
# include <linux/netdevice.h>
2017-08-03 14:28:18 +03:00
# include <linux/notifier.h>
2011-07-15 19:47:34 +04:00
# include <linux/export.h>
2020-07-27 01:48:16 +03:00
# include <linux/indirect_call_wrapper.h>
2006-08-04 14:39:02 +04:00
# include <net/fib_rules.h>
# include <net/ipv6.h>
2007-04-06 22:45:39 +04:00
# include <net/addrconf.h>
2006-08-04 14:39:02 +04:00
# include <net/ip6_route.h>
# include <net/netlink.h>
2012-04-01 11:49:06 +04:00
struct fib6_rule {
2006-08-04 14:39:02 +04:00
struct fib_rule common ;
struct rt6key src ;
struct rt6key dst ;
u8 tclass ;
} ;
2017-08-03 14:28:15 +03:00
static bool fib6_rule_matchall ( const struct fib_rule * rule )
{
struct fib6_rule * r = container_of ( rule , struct fib6_rule , common ) ;
if ( r - > dst . plen | | r - > src . plen | | r - > tclass )
return false ;
return fib_rule_matchall ( rule ) ;
}
bool fib6_rule_default ( const struct fib_rule * rule )
{
if ( ! fib6_rule_matchall ( rule ) | | rule - > action ! = FR_ACT_TO_TBL | |
rule - > l3mdev )
return false ;
if ( rule - > table ! = RT6_TABLE_LOCAL & & rule - > table ! = RT6_TABLE_MAIN )
return false ;
return true ;
}
EXPORT_SYMBOL_GPL ( fib6_rule_default ) ;
2019-10-03 12:49:30 +03:00
int fib6_rules_dump ( struct net * net , struct notifier_block * nb ,
struct netlink_ext_ack * extack )
2017-08-03 14:28:18 +03:00
{
2019-10-03 12:49:30 +03:00
return fib_rules_dump ( net , nb , AF_INET6 , extack ) ;
2017-08-03 14:28:18 +03:00
}
unsigned int fib6_rules_seq_read ( struct net * net )
{
return fib_rules_seq_read ( net , AF_INET6 ) ;
}
2018-05-10 06:34:23 +03:00
/* called with rcu lock held; no reference taken on fib6_info */
2019-04-17 00:36:10 +03:00
int fib6_lookup ( struct net * net , int oif , struct flowi6 * fl6 ,
struct fib6_result * res , int flags )
2018-05-10 06:34:23 +03:00
{
int err ;
if ( net - > ipv6 . fib6_has_custom_rules ) {
struct fib_lookup_arg arg = {
. lookup_ptr = fib6_table_lookup ,
. lookup_data = & oif ,
2019-04-17 00:36:10 +03:00
. result = res ,
2018-05-10 06:34:23 +03:00
. flags = FIB_LOOKUP_NOREF ,
} ;
l3mdev_update_flow ( net , flowi6_to_flowi ( fl6 ) ) ;
err = fib_rules_lookup ( net - > ipv6 . fib6_rules_ops ,
flowi6_to_flowi ( fl6 ) , flags , & arg ) ;
} else {
2019-04-17 00:36:10 +03:00
err = fib6_table_lookup ( net , net - > ipv6 . fib6_local_tbl , oif ,
fl6 , res , flags ) ;
if ( err | | res - > f6i = = net - > ipv6 . fib6_null_entry )
err = fib6_table_lookup ( net , net - > ipv6 . fib6_main_tbl ,
oif , fl6 , res , flags ) ;
2018-05-10 06:34:23 +03:00
}
2019-04-17 00:36:10 +03:00
return err ;
2018-05-10 06:34:23 +03:00
}
2011-03-13 00:22:43 +03:00
struct dst_entry * fib6_rule_lookup ( struct net * net , struct flowi6 * fl6 ,
2018-03-02 19:32:17 +03:00
const struct sk_buff * skb ,
2008-03-04 10:25:27 +03:00
int flags , pol_lookup_t lookup )
2006-08-04 14:39:02 +04:00
{
2017-08-08 21:23:49 +03:00
if ( net - > ipv6 . fib6_has_custom_rules ) {
2019-04-24 04:05:33 +03:00
struct fib6_result res = { } ;
2017-08-08 21:23:49 +03:00
struct fib_lookup_arg arg = {
. lookup_ptr = lookup ,
2018-03-02 19:32:17 +03:00
. lookup_data = skb ,
2019-04-24 04:05:33 +03:00
. result = & res ,
2017-08-08 21:23:49 +03:00
. flags = FIB_LOOKUP_NOREF ,
} ;
/* update flow if oif or iif point to device enslaved to l3mdev */
l3mdev_update_flow ( net , flowi6_to_flowi ( fl6 ) ) ;
fib_rules_lookup ( net - > ipv6 . fib6_rules_ops ,
flowi6_to_flowi ( fl6 ) , flags , & arg ) ;
2019-04-24 04:05:33 +03:00
if ( res . rt6 )
return & res . rt6 - > dst ;
2017-08-08 21:23:49 +03:00
} else {
struct rt6_info * rt ;
2020-06-23 19:42:32 +03:00
rt = pol_lookup_func ( lookup ,
net , net - > ipv6 . fib6_local_tbl , fl6 , skb , flags ) ;
2017-08-08 21:23:49 +03:00
if ( rt ! = net - > ipv6 . ip6_null_entry & & rt - > dst . error ! = - EAGAIN )
return & rt - > dst ;
2019-06-21 03:36:39 +03:00
ip6_rt_put_flags ( rt , flags ) ;
2020-06-23 19:42:32 +03:00
rt = pol_lookup_func ( lookup ,
net , net - > ipv6 . fib6_main_tbl , fl6 , skb , flags ) ;
2017-08-08 21:23:49 +03:00
if ( rt - > dst . error ! = - EAGAIN )
return & rt - > dst ;
2019-06-21 03:36:39 +03:00
ip6_rt_put_flags ( rt , flags ) ;
2017-08-08 21:23:49 +03:00
}
2006-08-09 03:44:17 +04:00
2019-06-21 03:36:39 +03:00
if ( ! ( flags & RT6_LOOKUP_F_DST_NOREF ) )
dst_hold ( & net - > ipv6 . ip6_null_entry - > dst ) ;
2017-06-20 13:29:25 +03:00
return & net - > ipv6 . ip6_null_entry - > dst ;
2006-08-04 14:39:02 +04:00
}
2018-05-10 06:34:22 +03:00
static int fib6_rule_saddr ( struct net * net , struct fib_rule * rule , int flags ,
struct flowi6 * flp6 , const struct net_device * dev )
{
struct fib6_rule * r = ( struct fib6_rule * ) rule ;
/* If we need to find a source address for this traffic,
* we check the result if it meets requirement of the rule .
*/
if ( ( rule - > flags & FIB_RULE_FIND_SADDR ) & &
r - > src . plen & & ! ( flags & RT6_LOOKUP_F_HAS_SADDR ) ) {
struct in6_addr saddr ;
if ( ipv6_dev_get_saddr ( net , dev , & flp6 - > daddr ,
rt6_flags2srcprefs ( flags ) , & saddr ) )
return - EAGAIN ;
if ( ! ipv6_prefix_equal ( & saddr , & r - > src . addr , r - > src . plen ) )
return - EAGAIN ;
flp6 - > saddr = saddr ;
}
return 0 ;
}
2018-05-10 06:34:23 +03:00
static int fib6_rule_action_alt ( struct fib_rule * rule , struct flowi * flp ,
int flags , struct fib_lookup_arg * arg )
{
2019-04-17 00:36:10 +03:00
struct fib6_result * res = arg - > result ;
2018-05-10 06:34:23 +03:00
struct flowi6 * flp6 = & flp - > u . ip6 ;
struct net * net = rule - > fr_net ;
struct fib6_table * table ;
2019-04-24 04:06:30 +03:00
int err , * oif ;
2018-05-10 06:34:23 +03:00
u32 tb_id ;
switch ( rule - > action ) {
case FR_ACT_TO_TBL :
break ;
case FR_ACT_UNREACHABLE :
return - ENETUNREACH ;
case FR_ACT_PROHIBIT :
return - EACCES ;
case FR_ACT_BLACKHOLE :
default :
return - EINVAL ;
}
tb_id = fib_rule_get_table ( rule , arg ) ;
table = fib6_get_table ( net , tb_id ) ;
if ( ! table )
return - EAGAIN ;
oif = ( int * ) arg - > lookup_data ;
2019-04-17 00:36:10 +03:00
err = fib6_table_lookup ( net , table , * oif , flp6 , res , flags ) ;
if ( ! err & & res - > f6i ! = net - > ipv6 . fib6_null_entry )
2018-05-10 06:34:23 +03:00
err = fib6_rule_saddr ( net , rule , flags , flp6 ,
2019-04-17 00:36:10 +03:00
res - > nh - > fib_nh_dev ) ;
2019-04-24 04:06:30 +03:00
else
err = - EAGAIN ;
2018-05-10 06:34:23 +03:00
return err ;
}
static int __fib6_rule_action ( struct fib_rule * rule , struct flowi * flp ,
int flags , struct fib_lookup_arg * arg )
2006-08-04 14:39:02 +04:00
{
2019-04-24 04:05:33 +03:00
struct fib6_result * res = arg - > result ;
2011-03-13 00:22:43 +03:00
struct flowi6 * flp6 = & flp - > u . ip6 ;
2006-08-04 14:39:02 +04:00
struct rt6_info * rt = NULL ;
struct fib6_table * table ;
2008-03-05 00:48:30 +03:00
struct net * net = rule - > fr_net ;
2006-08-04 14:39:02 +04:00
pol_lookup_t lookup = arg - > lookup_ptr ;
2013-08-01 10:54:47 +04:00
int err = 0 ;
2016-06-08 20:55:39 +03:00
u32 tb_id ;
2006-08-04 14:39:02 +04:00
switch ( rule - > action ) {
case FR_ACT_TO_TBL :
break ;
case FR_ACT_UNREACHABLE :
2013-08-01 10:54:47 +04:00
err = - ENETUNREACH ;
2008-03-05 00:48:30 +03:00
rt = net - > ipv6 . ip6_null_entry ;
2006-08-04 14:39:02 +04:00
goto discard_pkt ;
default :
case FR_ACT_BLACKHOLE :
2013-08-01 10:54:47 +04:00
err = - EINVAL ;
2008-03-05 00:48:30 +03:00
rt = net - > ipv6 . ip6_blk_hole_entry ;
2006-08-04 14:39:02 +04:00
goto discard_pkt ;
case FR_ACT_PROHIBIT :
2013-08-01 10:54:47 +04:00
err = - EACCES ;
2008-03-05 00:48:30 +03:00
rt = net - > ipv6 . ip6_prohibit_entry ;
2006-08-04 14:39:02 +04:00
goto discard_pkt ;
}
2016-06-08 20:55:39 +03:00
tb_id = fib_rule_get_table ( rule , arg ) ;
table = fib6_get_table ( net , tb_id ) ;
2013-08-01 10:54:47 +04:00
if ( ! table ) {
err = - EAGAIN ;
goto out ;
}
2006-08-04 14:39:02 +04:00
2020-06-23 19:42:32 +03:00
rt = pol_lookup_func ( lookup ,
net , table , flp6 , arg - > lookup_data , flags ) ;
2008-03-05 00:48:30 +03:00
if ( rt ! = net - > ipv6 . ip6_null_entry ) {
2018-05-10 06:34:22 +03:00
err = fib6_rule_saddr ( net , rule , flags , flp6 ,
ip6_dst_idev ( & rt - > dst ) - > dev ) ;
if ( err = = - EAGAIN )
goto again ;
2015-03-19 18:16:04 +03:00
err = rt - > dst . error ;
2017-06-20 13:29:25 +03:00
if ( err ! = - EAGAIN )
goto out ;
2007-04-06 22:45:39 +04:00
}
again :
2019-06-21 03:36:39 +03:00
ip6_rt_put_flags ( rt , flags ) ;
2013-08-01 10:54:47 +04:00
err = - EAGAIN ;
2006-08-07 09:24:08 +04:00
rt = NULL ;
goto out ;
2006-08-04 14:39:02 +04:00
discard_pkt :
2019-06-21 03:36:39 +03:00
if ( ! ( flags & RT6_LOOKUP_F_DST_NOREF ) )
dst_hold ( & rt - > dst ) ;
2006-08-04 14:39:02 +04:00
out :
2019-04-24 04:05:33 +03:00
res - > rt6 = rt ;
2013-08-01 10:54:47 +04:00
return err ;
2006-08-04 14:39:02 +04:00
}
2020-07-27 01:48:16 +03:00
INDIRECT_CALLABLE_SCOPE int fib6_rule_action ( struct fib_rule * rule ,
struct flowi * flp , int flags ,
struct fib_lookup_arg * arg )
2018-05-10 06:34:23 +03:00
{
if ( arg - > lookup_ptr = = fib6_table_lookup )
return fib6_rule_action_alt ( rule , flp , flags , arg ) ;
return __fib6_rule_action ( rule , flp , flags , arg ) ;
}
2020-07-27 01:48:16 +03:00
INDIRECT_CALLABLE_SCOPE bool fib6_rule_suppress ( struct fib_rule * rule ,
struct fib_lookup_arg * arg )
2013-08-01 04:17:15 +04:00
{
2019-04-24 04:05:33 +03:00
struct fib6_result * res = arg - > result ;
struct rt6_info * rt = res - > rt6 ;
2013-12-11 02:21:25 +04:00
struct net_device * dev = NULL ;
2019-04-24 04:05:33 +03:00
if ( ! rt )
return false ;
2013-12-11 02:21:25 +04:00
if ( rt - > rt6i_idev )
dev = rt - > rt6i_idev - > dev ;
2013-08-01 04:17:15 +04:00
/* do not accept result if the route does
* not meet the required prefix length
*/
2013-08-03 16:14:43 +04:00
if ( rt - > rt6i_dst . plen < = rule - > suppress_prefixlen )
2013-08-02 19:19:56 +04:00
goto suppress_route ;
/* do not accept result if the route uses a device
* belonging to a forbidden interface group
*/
if ( rule - > suppress_ifgroup ! = - 1 & & dev & & dev - > group = = rule - > suppress_ifgroup )
goto suppress_route ;
return false ;
suppress_route :
2019-09-24 17:01:28 +03:00
if ( ! ( arg - > flags & FIB_LOOKUP_NOREF ) )
ip6_rt_put ( rt ) ;
2013-09-08 19:09:43 +04:00
return true ;
2013-08-01 04:17:15 +04:00
}
2006-08-04 14:39:02 +04:00
2020-07-27 01:48:16 +03:00
INDIRECT_CALLABLE_SCOPE int fib6_rule_match ( struct fib_rule * rule ,
struct flowi * fl , int flags )
2006-08-04 14:39:02 +04:00
{
struct fib6_rule * r = ( struct fib6_rule * ) rule ;
2011-03-13 00:22:43 +03:00
struct flowi6 * fl6 = & fl - > u . ip6 ;
2006-08-04 14:39:02 +04:00
2006-10-14 02:01:03 +04:00
if ( r - > dst . plen & &
2011-03-13 00:22:43 +03:00
! ipv6_prefix_equal ( & fl6 - > daddr , & r - > dst . addr , r - > dst . plen ) )
2006-08-04 14:39:02 +04:00
return 0 ;
2007-04-06 22:45:39 +04:00
/*
* If FIB_RULE_FIND_SADDR is set and we do not have a
* source address for the traffic , we defer check for
* source address .
*/
2006-10-14 02:01:03 +04:00
if ( r - > src . plen ) {
2007-04-06 22:45:39 +04:00
if ( flags & RT6_LOOKUP_F_HAS_SADDR ) {
2011-03-13 00:22:43 +03:00
if ( ! ipv6_prefix_equal ( & fl6 - > saddr , & r - > src . addr ,
2007-04-06 22:45:39 +04:00
r - > src . plen ) )
return 0 ;
} else if ( ! ( r - > common . flags & FIB_RULE_FIND_SADDR ) )
2006-10-14 02:01:03 +04:00
return 0 ;
}
2006-08-04 14:39:02 +04:00
2014-01-15 13:03:30 +04:00
if ( r - > tclass & & r - > tclass ! = ip6_tclass ( fl6 - > flowlabel ) )
2006-08-21 14:18:57 +04:00
return 0 ;
2018-03-01 06:41:37 +03:00
if ( rule - > ip_proto & & ( rule - > ip_proto ! = fl6 - > flowi6_proto ) )
return 0 ;
if ( fib_rule_port_range_set ( & rule - > sport_range ) & &
! fib_rule_port_inrange ( & rule - > sport_range , fl6 - > fl6_sport ) )
return 0 ;
if ( fib_rule_port_range_set ( & rule - > dport_range ) & &
! fib_rule_port_inrange ( & rule - > dport_range , fl6 - > fl6_dport ) )
return 0 ;
2006-08-04 14:39:02 +04:00
return 1 ;
}
2007-06-05 23:38:30 +04:00
static const struct nla_policy fib6_rule_policy [ FRA_MAX + 1 ] = {
2006-11-10 02:22:48 +03:00
FRA_GENERIC_POLICY ,
2006-08-04 14:39:02 +04:00
} ;
static int fib6_rule_configure ( struct fib_rule * rule , struct sk_buff * skb ,
2009-05-11 09:52:49 +04:00
struct fib_rule_hdr * frh ,
2018-04-21 19:41:31 +03:00
struct nlattr * * tb ,
struct netlink_ext_ack * extack )
2006-08-04 14:39:02 +04:00
{
int err = - EINVAL ;
2008-03-25 20:26:21 +03:00
struct net * net = sock_net ( skb - > sk ) ;
2006-08-04 14:39:02 +04:00
struct fib6_rule * rule6 = ( struct fib6_rule * ) rule ;
2016-06-08 20:55:39 +03:00
if ( rule - > action = = FR_ACT_TO_TBL & & ! rule - > l3mdev ) {
2018-04-21 19:41:31 +03:00
if ( rule - > table = = RT6_TABLE_UNSPEC ) {
NL_SET_ERR_MSG ( extack , " Invalid table " ) ;
2006-08-04 14:39:02 +04:00
goto errout ;
2018-04-21 19:41:31 +03:00
}
2006-08-04 14:39:02 +04:00
2008-03-04 10:33:08 +03:00
if ( fib6_new_table ( net , rule - > table ) = = NULL ) {
2006-08-04 14:39:02 +04:00
err = - ENOBUFS ;
goto errout ;
}
}
2007-03-24 22:46:02 +03:00
if ( frh - > src_len )
2015-03-29 17:59:26 +03:00
rule6 - > src . addr = nla_get_in6_addr ( tb [ FRA_SRC ] ) ;
2006-08-04 14:39:02 +04:00
2007-03-24 22:46:02 +03:00
if ( frh - > dst_len )
2015-03-29 17:59:26 +03:00
rule6 - > dst . addr = nla_get_in6_addr ( tb [ FRA_DST ] ) ;
2006-08-04 14:39:02 +04:00
rule6 - > src . plen = frh - > src_len ;
rule6 - > dst . plen = frh - > dst_len ;
rule6 - > tclass = frh - > tos ;
2018-03-01 06:43:22 +03:00
if ( fib_rule_requires_fldissect ( rule ) )
net - > ipv6 . fib6_rules_require_fldissect + + ;
2017-08-08 21:23:49 +03:00
net - > ipv6 . fib6_has_custom_rules = true ;
2006-08-04 14:39:02 +04:00
err = 0 ;
errout :
return err ;
}
2018-03-01 06:43:22 +03:00
static int fib6_rule_delete ( struct fib_rule * rule )
{
struct net * net = rule - > fr_net ;
if ( net - > ipv6 . fib6_rules_require_fldissect & &
fib_rule_requires_fldissect ( rule ) )
net - > ipv6 . fib6_rules_require_fldissect - - ;
return 0 ;
}
2006-08-04 14:39:02 +04:00
static int fib6_rule_compare ( struct fib_rule * rule , struct fib_rule_hdr * frh ,
struct nlattr * * tb )
{
struct fib6_rule * rule6 = ( struct fib6_rule * ) rule ;
if ( frh - > src_len & & ( rule6 - > src . plen ! = frh - > src_len ) )
return 0 ;
if ( frh - > dst_len & & ( rule6 - > dst . plen ! = frh - > dst_len ) )
return 0 ;
if ( frh - > tos & & ( rule6 - > tclass ! = frh - > tos ) )
return 0 ;
2007-03-24 22:46:02 +03:00
if ( frh - > src_len & &
2006-08-04 14:39:02 +04:00
nla_memcmp ( tb [ FRA_SRC ] , & rule6 - > src . addr , sizeof ( struct in6_addr ) ) )
return 0 ;
2007-03-24 22:46:02 +03:00
if ( frh - > dst_len & &
2006-08-04 14:39:02 +04:00
nla_memcmp ( tb [ FRA_DST ] , & rule6 - > dst . addr , sizeof ( struct in6_addr ) ) )
return 0 ;
return 1 ;
}
static int fib6_rule_fill ( struct fib_rule * rule , struct sk_buff * skb ,
2009-05-21 04:26:23 +04:00
struct fib_rule_hdr * frh )
2006-08-04 14:39:02 +04:00
{
struct fib6_rule * rule6 = ( struct fib6_rule * ) rule ;
frh - > dst_len = rule6 - > dst . plen ;
frh - > src_len = rule6 - > src . plen ;
frh - > tos = rule6 - > tclass ;
2012-04-02 04:27:33 +04:00
if ( ( rule6 - > dst . plen & &
2015-03-29 17:59:25 +03:00
nla_put_in6_addr ( skb , FRA_DST , & rule6 - > dst . addr ) ) | |
2012-04-02 04:27:33 +04:00
( rule6 - > src . plen & &
2015-03-29 17:59:25 +03:00
nla_put_in6_addr ( skb , FRA_SRC , & rule6 - > src . addr ) ) )
2012-04-02 04:27:33 +04:00
goto nla_put_failure ;
2006-08-04 14:39:02 +04:00
return 0 ;
nla_put_failure :
return - ENOBUFS ;
}
2006-11-11 01:10:15 +03:00
static size_t fib6_rule_nlmsg_payload ( struct fib_rule * rule )
{
return nla_total_size ( 16 ) /* dst */
+ nla_total_size ( 16 ) ; /* src */
}
2012-10-05 04:12:11 +04:00
static const struct fib_rules_ops __net_initconst fib6_rules_ops_template = {
2010-04-26 18:02:05 +04:00
. family = AF_INET6 ,
2006-08-04 14:39:02 +04:00
. rule_size = sizeof ( struct fib6_rule ) ,
2007-03-24 22:46:02 +03:00
. addr_size = sizeof ( struct in6_addr ) ,
2006-08-04 14:39:02 +04:00
. action = fib6_rule_action ,
. match = fib6_rule_match ,
2013-08-01 04:17:15 +04:00
. suppress = fib6_rule_suppress ,
2006-08-04 14:39:02 +04:00
. configure = fib6_rule_configure ,
2018-03-01 06:43:22 +03:00
. delete = fib6_rule_delete ,
2006-08-04 14:39:02 +04:00
. compare = fib6_rule_compare ,
. fill = fib6_rule_fill ,
2006-11-11 01:10:15 +03:00
. nlmsg_payload = fib6_rule_nlmsg_payload ,
2006-08-04 14:39:02 +04:00
. nlgroup = RTNLGRP_IPV6_RULE ,
. policy = fib6_rule_policy ,
. owner = THIS_MODULE ,
2008-01-21 03:46:01 +03:00
. fro_net = & init_net ,
2006-08-04 14:39:02 +04:00
} ;
2010-01-17 06:35:32 +03:00
static int __net_init fib6_rules_net_init ( struct net * net )
2006-08-04 14:39:02 +04:00
{
2009-12-03 23:22:55 +03:00
struct fib_rules_ops * ops ;
2008-03-04 10:33:08 +03:00
int err = - ENOMEM ;
2007-11-11 09:12:03 +03:00
2009-12-03 23:22:55 +03:00
ops = fib_rules_register ( & fib6_rules_ops_template , net ) ;
if ( IS_ERR ( ops ) )
return PTR_ERR ( ops ) ;
2008-03-04 10:32:30 +03:00
2015-03-26 00:45:02 +03:00
err = fib_default_rule_add ( ops , 0 , RT6_TABLE_LOCAL , 0 ) ;
2008-03-04 10:33:08 +03:00
if ( err )
goto out_fib6_rules_ops ;
2007-12-07 11:42:52 +03:00
2015-03-26 00:45:02 +03:00
err = fib_default_rule_add ( ops , 0x7FFE , RT6_TABLE_MAIN , 0 ) ;
2008-03-04 10:33:08 +03:00
if ( err )
2009-12-03 23:22:55 +03:00
goto out_fib6_rules_ops ;
2007-12-07 11:42:52 +03:00
2015-03-26 00:45:02 +03:00
net - > ipv6 . fib6_rules_ops = ops ;
2018-03-01 06:43:22 +03:00
net - > ipv6 . fib6_rules_require_fldissect = 0 ;
2007-12-07 11:42:52 +03:00
out :
2008-03-04 10:33:08 +03:00
return err ;
2007-12-07 11:42:52 +03:00
2008-03-04 10:33:08 +03:00
out_fib6_rules_ops :
2009-12-03 23:22:55 +03:00
fib_rules_unregister ( ops ) ;
2007-12-07 11:42:52 +03:00
goto out ;
2006-08-04 14:39:02 +04:00
}
2010-01-17 06:35:32 +03:00
static void __net_exit fib6_rules_net_exit ( struct net * net )
2008-03-04 10:33:08 +03:00
{
2015-03-31 21:01:46 +03:00
rtnl_lock ( ) ;
2008-03-04 10:33:08 +03:00
fib_rules_unregister ( net - > ipv6 . fib6_rules_ops ) ;
2015-03-31 21:01:46 +03:00
rtnl_unlock ( ) ;
2008-03-04 10:33:08 +03:00
}
static struct pernet_operations fib6_rules_net_ops = {
. init = fib6_rules_net_init ,
. exit = fib6_rules_net_exit ,
} ;
int __init fib6_rules_init ( void )
{
return register_pernet_subsys ( & fib6_rules_net_ops ) ;
}
2006-08-04 14:39:02 +04:00
void fib6_rules_cleanup ( void )
{
2008-04-10 10:41:28 +04:00
unregister_pernet_subsys ( & fib6_rules_net_ops ) ;
2006-08-04 14:39:02 +04:00
}