LCOV - code coverage report
Current view: top level - net/ipv6 - fib6_rules.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_qemu_modules_combined.info Lines: 29 175 16.6 %
Date: 2020-09-30 20:25:01 Functions: 5 21 23.8 %
Branches: 9 160 5.6 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * net/ipv6/fib6_rules.c        IPv6 Routing Policy Rules
       4                 :            :  *
       5                 :            :  * Copyright (C)2003-2006 Helsinki University of Technology
       6                 :            :  * Copyright (C)2003-2006 USAGI/WIDE Project
       7                 :            :  *
       8                 :            :  * Authors
       9                 :            :  *      Thomas Graf             <tgraf@suug.ch>
      10                 :            :  *      Ville Nuorvala          <vnuorval@tcs.hut.fi>
      11                 :            :  */
      12                 :            : 
      13                 :            : #include <linux/netdevice.h>
      14                 :            : #include <linux/notifier.h>
      15                 :            : #include <linux/export.h>
      16                 :            : 
      17                 :            : #include <net/fib_rules.h>
      18                 :            : #include <net/ipv6.h>
      19                 :            : #include <net/addrconf.h>
      20                 :            : #include <net/ip6_route.h>
      21                 :            : #include <net/netlink.h>
      22                 :            : 
      23                 :            : struct fib6_rule {
      24                 :            :         struct fib_rule         common;
      25                 :            :         struct rt6key           src;
      26                 :            :         struct rt6key           dst;
      27                 :            :         u8                      tclass;
      28                 :            : };
      29                 :            : 
      30                 :          0 : static bool fib6_rule_matchall(const struct fib_rule *rule)
      31                 :            : {
      32                 :            :         struct fib6_rule *r = container_of(rule, struct fib6_rule, common);
      33                 :            : 
      34   [ #  #  #  #  :          0 :         if (r->dst.plen || r->src.plen || r->tclass)
                   #  # ]
      35                 :            :                 return false;
      36                 :          0 :         return fib_rule_matchall(rule);
      37                 :            : }
      38                 :            : 
      39                 :          0 : bool fib6_rule_default(const struct fib_rule *rule)
      40                 :            : {
      41   [ #  #  #  # ]:          0 :         if (!fib6_rule_matchall(rule) || rule->action != FR_ACT_TO_TBL ||
      42                 :            :             rule->l3mdev)
      43                 :            :                 return false;
      44         [ #  # ]:          0 :         if (rule->table != RT6_TABLE_LOCAL && rule->table != RT6_TABLE_MAIN)
      45                 :            :                 return false;
      46                 :          0 :         return true;
      47                 :            : }
      48                 :            : EXPORT_SYMBOL_GPL(fib6_rule_default);
      49                 :            : 
      50                 :          0 : int fib6_rules_dump(struct net *net, struct notifier_block *nb)
      51                 :            : {
      52                 :          0 :         return fib_rules_dump(net, nb, AF_INET6);
      53                 :            : }
      54                 :            : 
      55                 :          0 : unsigned int fib6_rules_seq_read(struct net *net)
      56                 :            : {
      57                 :          0 :         return fib_rules_seq_read(net, AF_INET6);
      58                 :            : }
      59                 :            : 
      60                 :            : /* called with rcu lock held; no reference taken on fib6_info */
      61                 :          0 : int fib6_lookup(struct net *net, int oif, struct flowi6 *fl6,
      62                 :            :                 struct fib6_result *res, int flags)
      63                 :            : {
      64                 :            :         int err;
      65                 :            : 
      66         [ #  # ]:          0 :         if (net->ipv6.fib6_has_custom_rules) {
      67                 :          0 :                 struct fib_lookup_arg arg = {
      68                 :            :                         .lookup_ptr = fib6_table_lookup,
      69                 :            :                         .lookup_data = &oif,
      70                 :            :                         .result = res,
      71                 :            :                         .flags = FIB_LOOKUP_NOREF,
      72                 :            :                 };
      73                 :            : 
      74                 :          0 :                 l3mdev_update_flow(net, flowi6_to_flowi(fl6));
      75                 :            : 
      76                 :          0 :                 err = fib_rules_lookup(net->ipv6.fib6_rules_ops,
      77                 :            :                                        flowi6_to_flowi(fl6), flags, &arg);
      78                 :            :         } else {
      79                 :          0 :                 err = fib6_table_lookup(net, net->ipv6.fib6_local_tbl, oif,
      80                 :            :                                         fl6, res, flags);
      81   [ #  #  #  # ]:          0 :                 if (err || res->f6i == net->ipv6.fib6_null_entry)
      82                 :          0 :                         err = fib6_table_lookup(net, net->ipv6.fib6_main_tbl,
      83                 :            :                                                 oif, fl6, res, flags);
      84                 :            :         }
      85                 :            : 
      86                 :          0 :         return err;
      87                 :            : }
      88                 :            : 
      89                 :       2790 : struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6,
      90                 :            :                                    const struct sk_buff *skb,
      91                 :            :                                    int flags, pol_lookup_t lookup)
      92                 :            : {
      93         [ -  + ]:       2790 :         if (net->ipv6.fib6_has_custom_rules) {
      94                 :          0 :                 struct fib6_result res = {};
      95                 :          0 :                 struct fib_lookup_arg arg = {
      96                 :            :                         .lookup_ptr = lookup,
      97                 :            :                         .lookup_data = skb,
      98                 :            :                         .result = &res,
      99                 :            :                         .flags = FIB_LOOKUP_NOREF,
     100                 :            :                 };
     101                 :            : 
     102                 :            :                 /* update flow if oif or iif point to device enslaved to l3mdev */
     103                 :          0 :                 l3mdev_update_flow(net, flowi6_to_flowi(fl6));
     104                 :            : 
     105                 :          0 :                 fib_rules_lookup(net->ipv6.fib6_rules_ops,
     106                 :            :                                  flowi6_to_flowi(fl6), flags, &arg);
     107                 :            : 
     108         [ #  # ]:          0 :                 if (res.rt6)
     109                 :          0 :                         return &res.rt6->dst;
     110                 :            :         } else {
     111                 :            :                 struct rt6_info *rt;
     112                 :            : 
     113                 :       2790 :                 rt = lookup(net, net->ipv6.fib6_local_tbl, fl6, skb, flags);
     114   [ +  +  +  - ]:       2788 :                 if (rt != net->ipv6.ip6_null_entry && rt->dst.error != -EAGAIN)
     115                 :       2484 :                         return &rt->dst;
     116                 :            :                 ip6_rt_put_flags(rt, flags);
     117                 :        306 :                 rt = lookup(net, net->ipv6.fib6_main_tbl, fl6, skb, flags);
     118         [ +  - ]:        306 :                 if (rt->dst.error != -EAGAIN)
     119                 :        306 :                         return &rt->dst;
     120                 :            :                 ip6_rt_put_flags(rt, flags);
     121                 :            :         }
     122                 :            : 
     123         [ #  # ]:          0 :         if (!(flags & RT6_LOOKUP_F_DST_NOREF))
     124                 :          0 :                 dst_hold(&net->ipv6.ip6_null_entry->dst);
     125                 :          0 :         return &net->ipv6.ip6_null_entry->dst;
     126                 :            : }
     127                 :            : 
     128                 :          0 : static int fib6_rule_saddr(struct net *net, struct fib_rule *rule, int flags,
     129                 :            :                            struct flowi6 *flp6, const struct net_device *dev)
     130                 :            : {
     131                 :            :         struct fib6_rule *r = (struct fib6_rule *)rule;
     132                 :            : 
     133                 :            :         /* If we need to find a source address for this traffic,
     134                 :            :          * we check the result if it meets requirement of the rule.
     135                 :            :          */
     136   [ #  #  #  # ]:          0 :         if ((rule->flags & FIB_RULE_FIND_SADDR) &&
     137         [ #  # ]:          0 :             r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) {
     138                 :            :                 struct in6_addr saddr;
     139                 :            : 
     140         [ #  # ]:          0 :                 if (ipv6_dev_get_saddr(net, dev, &flp6->daddr,
     141                 :            :                                        rt6_flags2srcprefs(flags), &saddr))
     142                 :          0 :                         return -EAGAIN;
     143                 :            : 
     144         [ #  # ]:          0 :                 if (!ipv6_prefix_equal(&saddr, &r->src.addr, r->src.plen))
     145                 :            :                         return -EAGAIN;
     146                 :            : 
     147                 :          0 :                 flp6->saddr = saddr;
     148                 :            :         }
     149                 :            : 
     150                 :            :         return 0;
     151                 :            : }
     152                 :            : 
     153                 :          0 : static int fib6_rule_action_alt(struct fib_rule *rule, struct flowi *flp,
     154                 :            :                                 int flags, struct fib_lookup_arg *arg)
     155                 :            : {
     156                 :          0 :         struct fib6_result *res = arg->result;
     157                 :          0 :         struct flowi6 *flp6 = &flp->u.ip6;
     158                 :          0 :         struct net *net = rule->fr_net;
     159                 :            :         struct fib6_table *table;
     160                 :            :         int err, *oif;
     161                 :            :         u32 tb_id;
     162                 :            : 
     163   [ #  #  #  # ]:          0 :         switch (rule->action) {
     164                 :            :         case FR_ACT_TO_TBL:
     165                 :            :                 break;
     166                 :            :         case FR_ACT_UNREACHABLE:
     167                 :            :                 return -ENETUNREACH;
     168                 :            :         case FR_ACT_PROHIBIT:
     169                 :          0 :                 return -EACCES;
     170                 :            :         case FR_ACT_BLACKHOLE:
     171                 :            :         default:
     172                 :          0 :                 return -EINVAL;
     173                 :            :         }
     174                 :            : 
     175                 :            :         tb_id = fib_rule_get_table(rule, arg);
     176                 :          0 :         table = fib6_get_table(net, tb_id);
     177         [ #  # ]:          0 :         if (!table)
     178                 :            :                 return -EAGAIN;
     179                 :            : 
     180                 :          0 :         oif = (int *)arg->lookup_data;
     181                 :          0 :         err = fib6_table_lookup(net, table, *oif, flp6, res, flags);
     182   [ #  #  #  # ]:          0 :         if (!err && res->f6i != net->ipv6.fib6_null_entry)
     183                 :          0 :                 err = fib6_rule_saddr(net, rule, flags, flp6,
     184                 :          0 :                                       res->nh->fib_nh_dev);
     185                 :            :         else
     186                 :            :                 err = -EAGAIN;
     187                 :            : 
     188                 :          0 :         return err;
     189                 :            : }
     190                 :            : 
     191                 :          0 : static int __fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
     192                 :            :                               int flags, struct fib_lookup_arg *arg)
     193                 :            : {
     194                 :          0 :         struct fib6_result *res = arg->result;
     195                 :          0 :         struct flowi6 *flp6 = &flp->u.ip6;
     196                 :            :         struct rt6_info *rt = NULL;
     197                 :            :         struct fib6_table *table;
     198                 :          0 :         struct net *net = rule->fr_net;
     199                 :          0 :         pol_lookup_t lookup = arg->lookup_ptr;
     200                 :            :         int err = 0;
     201                 :            :         u32 tb_id;
     202                 :            : 
     203   [ #  #  #  # ]:          0 :         switch (rule->action) {
     204                 :            :         case FR_ACT_TO_TBL:
     205                 :            :                 break;
     206                 :            :         case FR_ACT_UNREACHABLE:
     207                 :            :                 err = -ENETUNREACH;
     208                 :          0 :                 rt = net->ipv6.ip6_null_entry;
     209                 :          0 :                 goto discard_pkt;
     210                 :            :         default:
     211                 :            :         case FR_ACT_BLACKHOLE:
     212                 :            :                 err = -EINVAL;
     213                 :          0 :                 rt = net->ipv6.ip6_blk_hole_entry;
     214                 :          0 :                 goto discard_pkt;
     215                 :            :         case FR_ACT_PROHIBIT:
     216                 :            :                 err = -EACCES;
     217                 :          0 :                 rt = net->ipv6.ip6_prohibit_entry;
     218                 :          0 :                 goto discard_pkt;
     219                 :            :         }
     220                 :            : 
     221                 :            :         tb_id = fib_rule_get_table(rule, arg);
     222                 :          0 :         table = fib6_get_table(net, tb_id);
     223         [ #  # ]:          0 :         if (!table) {
     224                 :            :                 err = -EAGAIN;
     225                 :            :                 goto out;
     226                 :            :         }
     227                 :            : 
     228                 :          0 :         rt = lookup(net, table, flp6, arg->lookup_data, flags);
     229         [ #  # ]:          0 :         if (rt != net->ipv6.ip6_null_entry) {
     230                 :          0 :                 err = fib6_rule_saddr(net, rule, flags, flp6,
     231                 :          0 :                                       ip6_dst_idev(&rt->dst)->dev);
     232                 :            : 
     233         [ #  # ]:          0 :                 if (err == -EAGAIN)
     234                 :            :                         goto again;
     235                 :            : 
     236                 :          0 :                 err = rt->dst.error;
     237         [ #  # ]:          0 :                 if (err != -EAGAIN)
     238                 :            :                         goto out;
     239                 :            :         }
     240                 :            : again:
     241                 :            :         ip6_rt_put_flags(rt, flags);
     242                 :            :         err = -EAGAIN;
     243                 :            :         rt = NULL;
     244                 :            :         goto out;
     245                 :            : 
     246                 :            : discard_pkt:
     247         [ #  # ]:          0 :         if (!(flags & RT6_LOOKUP_F_DST_NOREF))
     248                 :          0 :                 dst_hold(&rt->dst);
     249                 :            : out:
     250                 :          0 :         res->rt6 = rt;
     251                 :          0 :         return err;
     252                 :            : }
     253                 :            : 
     254                 :          0 : static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
     255                 :            :                             int flags, struct fib_lookup_arg *arg)
     256                 :            : {
     257         [ #  # ]:          0 :         if (arg->lookup_ptr == fib6_table_lookup)
     258                 :          0 :                 return fib6_rule_action_alt(rule, flp, flags, arg);
     259                 :            : 
     260                 :          0 :         return __fib6_rule_action(rule, flp, flags, arg);
     261                 :            : }
     262                 :            : 
     263                 :          0 : static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg)
     264                 :            : {
     265                 :          0 :         struct fib6_result *res = arg->result;
     266                 :          0 :         struct rt6_info *rt = res->rt6;
     267                 :            :         struct net_device *dev = NULL;
     268                 :            : 
     269         [ #  # ]:          0 :         if (!rt)
     270                 :            :                 return false;
     271                 :            : 
     272         [ #  # ]:          0 :         if (rt->rt6i_idev)
     273                 :          0 :                 dev = rt->rt6i_idev->dev;
     274                 :            : 
     275                 :            :         /* do not accept result if the route does
     276                 :            :          * not meet the required prefix length
     277                 :            :          */
     278         [ #  # ]:          0 :         if (rt->rt6i_dst.plen <= rule->suppress_prefixlen)
     279                 :            :                 goto suppress_route;
     280                 :            : 
     281                 :            :         /* do not accept result if the route uses a device
     282                 :            :          * belonging to a forbidden interface group
     283                 :            :          */
     284   [ #  #  #  #  :          0 :         if (rule->suppress_ifgroup != -1 && dev && dev->group == rule->suppress_ifgroup)
                   #  # ]
     285                 :            :                 goto suppress_route;
     286                 :            : 
     287                 :            :         return false;
     288                 :            : 
     289                 :            : suppress_route:
     290         [ #  # ]:          0 :         if (!(arg->flags & FIB_LOOKUP_NOREF))
     291                 :            :                 ip6_rt_put(rt);
     292                 :            :         return true;
     293                 :            : }
     294                 :            : 
     295                 :          0 : static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
     296                 :            : {
     297                 :            :         struct fib6_rule *r = (struct fib6_rule *) rule;
     298                 :            :         struct flowi6 *fl6 = &fl->u.ip6;
     299                 :            : 
     300   [ #  #  #  # ]:          0 :         if (r->dst.plen &&
     301                 :          0 :             !ipv6_prefix_equal(&fl6->daddr, &r->dst.addr, r->dst.plen))
     302                 :            :                 return 0;
     303                 :            : 
     304                 :            :         /*
     305                 :            :          * If FIB_RULE_FIND_SADDR is set and we do not have a
     306                 :            :          * source address for the traffic, we defer check for
     307                 :            :          * source address.
     308                 :            :          */
     309         [ #  # ]:          0 :         if (r->src.plen) {
     310         [ #  # ]:          0 :                 if (flags & RT6_LOOKUP_F_HAS_SADDR) {
     311         [ #  # ]:          0 :                         if (!ipv6_prefix_equal(&fl6->saddr, &r->src.addr,
     312                 :            :                                                r->src.plen))
     313                 :            :                                 return 0;
     314         [ #  # ]:          0 :                 } else if (!(r->common.flags & FIB_RULE_FIND_SADDR))
     315                 :            :                         return 0;
     316                 :            :         }
     317                 :            : 
     318   [ #  #  #  # ]:          0 :         if (r->tclass && r->tclass != ip6_tclass(fl6->flowlabel))
     319                 :            :                 return 0;
     320                 :            : 
     321   [ #  #  #  # ]:          0 :         if (rule->ip_proto && (rule->ip_proto != fl6->flowi6_proto))
     322                 :            :                 return 0;
     323                 :            : 
     324   [ #  #  #  # ]:          0 :         if (fib_rule_port_range_set(&rule->sport_range) &&
     325                 :          0 :             !fib_rule_port_inrange(&rule->sport_range, fl6->fl6_sport))
     326                 :            :                 return 0;
     327                 :            : 
     328   [ #  #  #  # ]:          0 :         if (fib_rule_port_range_set(&rule->dport_range) &&
     329                 :          0 :             !fib_rule_port_inrange(&rule->dport_range, fl6->fl6_dport))
     330                 :            :                 return 0;
     331                 :            : 
     332                 :          0 :         return 1;
     333                 :            : }
     334                 :            : 
     335                 :            : static const struct nla_policy fib6_rule_policy[FRA_MAX+1] = {
     336                 :            :         FRA_GENERIC_POLICY,
     337                 :            : };
     338                 :            : 
     339                 :          0 : static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
     340                 :            :                                struct fib_rule_hdr *frh,
     341                 :            :                                struct nlattr **tb,
     342                 :            :                                struct netlink_ext_ack *extack)
     343                 :            : {
     344                 :            :         int err = -EINVAL;
     345                 :          0 :         struct net *net = sock_net(skb->sk);
     346                 :            :         struct fib6_rule *rule6 = (struct fib6_rule *) rule;
     347                 :            : 
     348         [ #  # ]:          0 :         if (rule->action == FR_ACT_TO_TBL && !rule->l3mdev) {
     349         [ #  # ]:          0 :                 if (rule->table == RT6_TABLE_UNSPEC) {
     350         [ #  # ]:          0 :                         NL_SET_ERR_MSG(extack, "Invalid table");
     351                 :            :                         goto errout;
     352                 :            :                 }
     353                 :            : 
     354         [ #  # ]:          0 :                 if (fib6_new_table(net, rule->table) == NULL) {
     355                 :            :                         err = -ENOBUFS;
     356                 :            :                         goto errout;
     357                 :            :                 }
     358                 :            :         }
     359                 :            : 
     360         [ #  # ]:          0 :         if (frh->src_len)
     361                 :          0 :                 rule6->src.addr = nla_get_in6_addr(tb[FRA_SRC]);
     362                 :            : 
     363         [ #  # ]:          0 :         if (frh->dst_len)
     364                 :          0 :                 rule6->dst.addr = nla_get_in6_addr(tb[FRA_DST]);
     365                 :            : 
     366                 :          0 :         rule6->src.plen = frh->src_len;
     367                 :          0 :         rule6->dst.plen = frh->dst_len;
     368                 :          0 :         rule6->tclass = frh->tos;
     369                 :            : 
     370         [ #  # ]:          0 :         if (fib_rule_requires_fldissect(rule))
     371                 :          0 :                 net->ipv6.fib6_rules_require_fldissect++;
     372                 :            : 
     373                 :          0 :         net->ipv6.fib6_has_custom_rules = true;
     374                 :            :         err = 0;
     375                 :            : errout:
     376                 :          0 :         return err;
     377                 :            : }
     378                 :            : 
     379                 :          4 : static int fib6_rule_delete(struct fib_rule *rule)
     380                 :            : {
     381                 :          4 :         struct net *net = rule->fr_net;
     382                 :            : 
     383   [ -  +  #  # ]:          4 :         if (net->ipv6.fib6_rules_require_fldissect &&
     384                 :          0 :             fib_rule_requires_fldissect(rule))
     385                 :          0 :                 net->ipv6.fib6_rules_require_fldissect--;
     386                 :            : 
     387                 :          4 :         return 0;
     388                 :            : }
     389                 :            : 
     390                 :          0 : static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
     391                 :            :                              struct nlattr **tb)
     392                 :            : {
     393                 :            :         struct fib6_rule *rule6 = (struct fib6_rule *) rule;
     394                 :            : 
     395   [ #  #  #  # ]:          0 :         if (frh->src_len && (rule6->src.plen != frh->src_len))
     396                 :            :                 return 0;
     397                 :            : 
     398   [ #  #  #  # ]:          0 :         if (frh->dst_len && (rule6->dst.plen != frh->dst_len))
     399                 :            :                 return 0;
     400                 :            : 
     401   [ #  #  #  # ]:          0 :         if (frh->tos && (rule6->tclass != frh->tos))
     402                 :            :                 return 0;
     403                 :            : 
     404   [ #  #  #  # ]:          0 :         if (frh->src_len &&
     405                 :          0 :             nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr)))
     406                 :            :                 return 0;
     407                 :            : 
     408   [ #  #  #  # ]:          0 :         if (frh->dst_len &&
     409                 :          0 :             nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr)))
     410                 :            :                 return 0;
     411                 :            : 
     412                 :            :         return 1;
     413                 :            : }
     414                 :            : 
     415                 :          0 : static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
     416                 :            :                           struct fib_rule_hdr *frh)
     417                 :            : {
     418                 :            :         struct fib6_rule *rule6 = (struct fib6_rule *) rule;
     419                 :            : 
     420                 :          0 :         frh->dst_len = rule6->dst.plen;
     421                 :          0 :         frh->src_len = rule6->src.plen;
     422                 :          0 :         frh->tos = rule6->tclass;
     423                 :            : 
     424   [ #  #  #  # ]:          0 :         if ((rule6->dst.plen &&
     425         [ #  # ]:          0 :              nla_put_in6_addr(skb, FRA_DST, &rule6->dst.addr)) ||
     426         [ #  # ]:          0 :             (rule6->src.plen &&
     427                 :          0 :              nla_put_in6_addr(skb, FRA_SRC, &rule6->src.addr)))
     428                 :            :                 goto nla_put_failure;
     429                 :            :         return 0;
     430                 :            : 
     431                 :            : nla_put_failure:
     432                 :            :         return -ENOBUFS;
     433                 :            : }
     434                 :            : 
     435                 :          0 : static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule)
     436                 :            : {
     437                 :          0 :         return nla_total_size(16) /* dst */
     438                 :            :                + nla_total_size(16); /* src */
     439                 :            : }
     440                 :            : 
     441                 :            : static const struct fib_rules_ops __net_initconst fib6_rules_ops_template = {
     442                 :            :         .family                 = AF_INET6,
     443                 :            :         .rule_size              = sizeof(struct fib6_rule),
     444                 :            :         .addr_size              = sizeof(struct in6_addr),
     445                 :            :         .action                 = fib6_rule_action,
     446                 :            :         .match                  = fib6_rule_match,
     447                 :            :         .suppress               = fib6_rule_suppress,
     448                 :            :         .configure              = fib6_rule_configure,
     449                 :            :         .delete                 = fib6_rule_delete,
     450                 :            :         .compare                = fib6_rule_compare,
     451                 :            :         .fill                   = fib6_rule_fill,
     452                 :            :         .nlmsg_payload          = fib6_rule_nlmsg_payload,
     453                 :            :         .nlgroup                = RTNLGRP_IPV6_RULE,
     454                 :            :         .policy                 = fib6_rule_policy,
     455                 :            :         .owner                  = THIS_MODULE,
     456                 :            :         .fro_net                = &init_net,
     457                 :            : };
     458                 :            : 
     459                 :        406 : static int __net_init fib6_rules_net_init(struct net *net)
     460                 :            : {
     461                 :            :         struct fib_rules_ops *ops;
     462                 :            :         int err = -ENOMEM;
     463                 :            : 
     464                 :        406 :         ops = fib_rules_register(&fib6_rules_ops_template, net);
     465         [ -  + ]:        406 :         if (IS_ERR(ops))
     466                 :          0 :                 return PTR_ERR(ops);
     467                 :            : 
     468                 :        406 :         err = fib_default_rule_add(ops, 0, RT6_TABLE_LOCAL, 0);
     469         [ +  - ]:        406 :         if (err)
     470                 :            :                 goto out_fib6_rules_ops;
     471                 :            : 
     472                 :        406 :         err = fib_default_rule_add(ops, 0x7FFE, RT6_TABLE_MAIN, 0);
     473         [ +  - ]:        406 :         if (err)
     474                 :            :                 goto out_fib6_rules_ops;
     475                 :            : 
     476                 :        406 :         net->ipv6.fib6_rules_ops = ops;
     477                 :        406 :         net->ipv6.fib6_rules_require_fldissect = 0;
     478                 :            : out:
     479                 :        406 :         return err;
     480                 :            : 
     481                 :            : out_fib6_rules_ops:
     482                 :          0 :         fib_rules_unregister(ops);
     483                 :          0 :         goto out;
     484                 :            : }
     485                 :            : 
     486                 :          2 : static void __net_exit fib6_rules_net_exit(struct net *net)
     487                 :            : {
     488                 :          2 :         rtnl_lock();
     489                 :          2 :         fib_rules_unregister(net->ipv6.fib6_rules_ops);
     490                 :          2 :         rtnl_unlock();
     491                 :          2 : }
     492                 :            : 
     493                 :            : static struct pernet_operations fib6_rules_net_ops = {
     494                 :            :         .init = fib6_rules_net_init,
     495                 :            :         .exit = fib6_rules_net_exit,
     496                 :            : };
     497                 :            : 
     498                 :        404 : int __init fib6_rules_init(void)
     499                 :            : {
     500                 :        404 :         return register_pernet_subsys(&fib6_rules_net_ops);
     501                 :            : }
     502                 :            : 
     503                 :            : 
     504                 :          0 : void fib6_rules_cleanup(void)
     505                 :            : {
     506                 :          0 :         unregister_pernet_subsys(&fib6_rules_net_ops);
     507                 :          0 : }

Generated by: LCOV version 1.14