Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #include <linux/init.h>
0003 #include <linux/module.h>
0004 #include <linux/netfilter.h>
0005 #include <net/flow_offload.h>
0006 #include <net/netfilter/nf_tables.h>
0007 #include <net/netfilter/nf_tables_offload.h>
0008 #include <net/pkt_cls.h>
0009 
0010 static struct nft_flow_rule *nft_flow_rule_alloc(int num_actions)
0011 {
0012     struct nft_flow_rule *flow;
0013 
0014     flow = kzalloc(sizeof(struct nft_flow_rule), GFP_KERNEL);
0015     if (!flow)
0016         return NULL;
0017 
0018     flow->rule = flow_rule_alloc(num_actions);
0019     if (!flow->rule) {
0020         kfree(flow);
0021         return NULL;
0022     }
0023 
0024     flow->rule->match.dissector = &flow->match.dissector;
0025     flow->rule->match.mask      = &flow->match.mask;
0026     flow->rule->match.key       = &flow->match.key;
0027 
0028     return flow;
0029 }
0030 
0031 void nft_flow_rule_set_addr_type(struct nft_flow_rule *flow,
0032                  enum flow_dissector_key_id addr_type)
0033 {
0034     struct nft_flow_match *match = &flow->match;
0035     struct nft_flow_key *mask = &match->mask;
0036     struct nft_flow_key *key = &match->key;
0037 
0038     if (match->dissector.used_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL))
0039         return;
0040 
0041     key->control.addr_type = addr_type;
0042     mask->control.addr_type = 0xffff;
0043     match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL);
0044     match->dissector.offset[FLOW_DISSECTOR_KEY_CONTROL] =
0045         offsetof(struct nft_flow_key, control);
0046 }
0047 
0048 struct nft_offload_ethertype {
0049     __be16 value;
0050     __be16 mask;
0051 };
0052 
0053 static void nft_flow_rule_transfer_vlan(struct nft_offload_ctx *ctx,
0054                     struct nft_flow_rule *flow)
0055 {
0056     struct nft_flow_match *match = &flow->match;
0057     struct nft_offload_ethertype ethertype = {
0058         .value  = match->key.basic.n_proto,
0059         .mask   = match->mask.basic.n_proto,
0060     };
0061 
0062     if (match->dissector.used_keys & BIT(FLOW_DISSECTOR_KEY_VLAN) &&
0063         (match->key.vlan.vlan_tpid == htons(ETH_P_8021Q) ||
0064          match->key.vlan.vlan_tpid == htons(ETH_P_8021AD))) {
0065         match->key.basic.n_proto = match->key.cvlan.vlan_tpid;
0066         match->mask.basic.n_proto = match->mask.cvlan.vlan_tpid;
0067         match->key.cvlan.vlan_tpid = match->key.vlan.vlan_tpid;
0068         match->mask.cvlan.vlan_tpid = match->mask.vlan.vlan_tpid;
0069         match->key.vlan.vlan_tpid = ethertype.value;
0070         match->mask.vlan.vlan_tpid = ethertype.mask;
0071         match->dissector.offset[FLOW_DISSECTOR_KEY_CVLAN] =
0072             offsetof(struct nft_flow_key, cvlan);
0073         match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_CVLAN);
0074     } else if (match->dissector.used_keys & BIT(FLOW_DISSECTOR_KEY_BASIC) &&
0075            (match->key.basic.n_proto == htons(ETH_P_8021Q) ||
0076             match->key.basic.n_proto == htons(ETH_P_8021AD))) {
0077         match->key.basic.n_proto = match->key.vlan.vlan_tpid;
0078         match->mask.basic.n_proto = match->mask.vlan.vlan_tpid;
0079         match->key.vlan.vlan_tpid = ethertype.value;
0080         match->mask.vlan.vlan_tpid = ethertype.mask;
0081         match->dissector.offset[FLOW_DISSECTOR_KEY_VLAN] =
0082             offsetof(struct nft_flow_key, vlan);
0083         match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_VLAN);
0084     }
0085 }
0086 
0087 struct nft_flow_rule *nft_flow_rule_create(struct net *net,
0088                        const struct nft_rule *rule)
0089 {
0090     struct nft_offload_ctx *ctx;
0091     struct nft_flow_rule *flow;
0092     int num_actions = 0, err;
0093     struct nft_expr *expr;
0094 
0095     expr = nft_expr_first(rule);
0096     while (nft_expr_more(rule, expr)) {
0097         if (expr->ops->offload_action &&
0098             expr->ops->offload_action(expr))
0099             num_actions++;
0100 
0101         expr = nft_expr_next(expr);
0102     }
0103 
0104     if (num_actions == 0)
0105         return ERR_PTR(-EOPNOTSUPP);
0106 
0107     flow = nft_flow_rule_alloc(num_actions);
0108     if (!flow)
0109         return ERR_PTR(-ENOMEM);
0110 
0111     expr = nft_expr_first(rule);
0112 
0113     ctx = kzalloc(sizeof(struct nft_offload_ctx), GFP_KERNEL);
0114     if (!ctx) {
0115         err = -ENOMEM;
0116         goto err_out;
0117     }
0118     ctx->net = net;
0119     ctx->dep.type = NFT_OFFLOAD_DEP_UNSPEC;
0120 
0121     while (nft_expr_more(rule, expr)) {
0122         if (!expr->ops->offload) {
0123             err = -EOPNOTSUPP;
0124             goto err_out;
0125         }
0126         err = expr->ops->offload(ctx, flow, expr);
0127         if (err < 0)
0128             goto err_out;
0129 
0130         expr = nft_expr_next(expr);
0131     }
0132     nft_flow_rule_transfer_vlan(ctx, flow);
0133 
0134     flow->proto = ctx->dep.l3num;
0135     kfree(ctx);
0136 
0137     return flow;
0138 err_out:
0139     kfree(ctx);
0140     nft_flow_rule_destroy(flow);
0141 
0142     return ERR_PTR(err);
0143 }
0144 
0145 void nft_flow_rule_destroy(struct nft_flow_rule *flow)
0146 {
0147     struct flow_action_entry *entry;
0148     int i;
0149 
0150     flow_action_for_each(i, entry, &flow->rule->action) {
0151         switch (entry->id) {
0152         case FLOW_ACTION_REDIRECT:
0153         case FLOW_ACTION_MIRRED:
0154             dev_put(entry->dev);
0155             break;
0156         default:
0157             break;
0158         }
0159     }
0160     kfree(flow->rule);
0161     kfree(flow);
0162 }
0163 
0164 void nft_offload_set_dependency(struct nft_offload_ctx *ctx,
0165                 enum nft_offload_dep_type type)
0166 {
0167     ctx->dep.type = type;
0168 }
0169 
0170 void nft_offload_update_dependency(struct nft_offload_ctx *ctx,
0171                    const void *data, u32 len)
0172 {
0173     switch (ctx->dep.type) {
0174     case NFT_OFFLOAD_DEP_NETWORK:
0175         WARN_ON(len != sizeof(__u16));
0176         memcpy(&ctx->dep.l3num, data, sizeof(__u16));
0177         break;
0178     case NFT_OFFLOAD_DEP_TRANSPORT:
0179         WARN_ON(len != sizeof(__u8));
0180         memcpy(&ctx->dep.protonum, data, sizeof(__u8));
0181         break;
0182     default:
0183         break;
0184     }
0185     ctx->dep.type = NFT_OFFLOAD_DEP_UNSPEC;
0186 }
0187 
0188 static void nft_flow_offload_common_init(struct flow_cls_common_offload *common,
0189                      __be16 proto, int priority,
0190                      struct netlink_ext_ack *extack)
0191 {
0192     common->protocol = proto;
0193     common->prio = priority;
0194     common->extack = extack;
0195 }
0196 
0197 static int nft_setup_cb_call(enum tc_setup_type type, void *type_data,
0198                  struct list_head *cb_list)
0199 {
0200     struct flow_block_cb *block_cb;
0201     int err;
0202 
0203     list_for_each_entry(block_cb, cb_list, list) {
0204         err = block_cb->cb(type, type_data, block_cb->cb_priv);
0205         if (err < 0)
0206             return err;
0207     }
0208     return 0;
0209 }
0210 
0211 static int nft_chain_offload_priority(const struct nft_base_chain *basechain)
0212 {
0213     if (basechain->ops.priority <= 0 ||
0214         basechain->ops.priority > USHRT_MAX)
0215         return -1;
0216 
0217     return 0;
0218 }
0219 
0220 bool nft_chain_offload_support(const struct nft_base_chain *basechain)
0221 {
0222     struct net_device *dev;
0223     struct nft_hook *hook;
0224 
0225     if (nft_chain_offload_priority(basechain) < 0)
0226         return false;
0227 
0228     list_for_each_entry(hook, &basechain->hook_list, list) {
0229         if (hook->ops.pf != NFPROTO_NETDEV ||
0230             hook->ops.hooknum != NF_NETDEV_INGRESS)
0231             return false;
0232 
0233         dev = hook->ops.dev;
0234         if (!dev->netdev_ops->ndo_setup_tc && !flow_indr_dev_exists())
0235             return false;
0236     }
0237 
0238     return true;
0239 }
0240 
0241 static void nft_flow_cls_offload_setup(struct flow_cls_offload *cls_flow,
0242                        const struct nft_base_chain *basechain,
0243                        const struct nft_rule *rule,
0244                        const struct nft_flow_rule *flow,
0245                        struct netlink_ext_ack *extack,
0246                        enum flow_cls_command command)
0247 {
0248     __be16 proto = ETH_P_ALL;
0249 
0250     memset(cls_flow, 0, sizeof(*cls_flow));
0251 
0252     if (flow)
0253         proto = flow->proto;
0254 
0255     nft_flow_offload_common_init(&cls_flow->common, proto,
0256                      basechain->ops.priority, extack);
0257     cls_flow->command = command;
0258     cls_flow->cookie = (unsigned long) rule;
0259     if (flow)
0260         cls_flow->rule = flow->rule;
0261 }
0262 
0263 static int nft_flow_offload_cmd(const struct nft_chain *chain,
0264                 const struct nft_rule *rule,
0265                 struct nft_flow_rule *flow,
0266                 enum flow_cls_command command,
0267                 struct flow_cls_offload *cls_flow)
0268 {
0269     struct netlink_ext_ack extack = {};
0270     struct nft_base_chain *basechain;
0271 
0272     if (!nft_is_base_chain(chain))
0273         return -EOPNOTSUPP;
0274 
0275     basechain = nft_base_chain(chain);
0276     nft_flow_cls_offload_setup(cls_flow, basechain, rule, flow, &extack,
0277                    command);
0278 
0279     return nft_setup_cb_call(TC_SETUP_CLSFLOWER, cls_flow,
0280                  &basechain->flow_block.cb_list);
0281 }
0282 
0283 static int nft_flow_offload_rule(const struct nft_chain *chain,
0284                  struct nft_rule *rule,
0285                  struct nft_flow_rule *flow,
0286                  enum flow_cls_command command)
0287 {
0288     struct flow_cls_offload cls_flow;
0289 
0290     return nft_flow_offload_cmd(chain, rule, flow, command, &cls_flow);
0291 }
0292 
0293 int nft_flow_rule_stats(const struct nft_chain *chain,
0294             const struct nft_rule *rule)
0295 {
0296     struct flow_cls_offload cls_flow = {};
0297     struct nft_expr *expr, *next;
0298     int err;
0299 
0300     err = nft_flow_offload_cmd(chain, rule, NULL, FLOW_CLS_STATS,
0301                    &cls_flow);
0302     if (err < 0)
0303         return err;
0304 
0305     nft_rule_for_each_expr(expr, next, rule) {
0306         if (expr->ops->offload_stats)
0307             expr->ops->offload_stats(expr, &cls_flow.stats);
0308     }
0309 
0310     return 0;
0311 }
0312 
0313 static int nft_flow_offload_bind(struct flow_block_offload *bo,
0314                  struct nft_base_chain *basechain)
0315 {
0316     list_splice(&bo->cb_list, &basechain->flow_block.cb_list);
0317     return 0;
0318 }
0319 
0320 static int nft_flow_offload_unbind(struct flow_block_offload *bo,
0321                    struct nft_base_chain *basechain)
0322 {
0323     struct flow_block_cb *block_cb, *next;
0324     struct flow_cls_offload cls_flow;
0325     struct netlink_ext_ack extack;
0326     struct nft_chain *chain;
0327     struct nft_rule *rule;
0328 
0329     chain = &basechain->chain;
0330     list_for_each_entry(rule, &chain->rules, list) {
0331         memset(&extack, 0, sizeof(extack));
0332         nft_flow_cls_offload_setup(&cls_flow, basechain, rule, NULL,
0333                        &extack, FLOW_CLS_DESTROY);
0334         nft_setup_cb_call(TC_SETUP_CLSFLOWER, &cls_flow, &bo->cb_list);
0335     }
0336 
0337     list_for_each_entry_safe(block_cb, next, &bo->cb_list, list) {
0338         list_del(&block_cb->list);
0339         flow_block_cb_free(block_cb);
0340     }
0341 
0342     return 0;
0343 }
0344 
0345 static int nft_block_setup(struct nft_base_chain *basechain,
0346                struct flow_block_offload *bo,
0347                enum flow_block_command cmd)
0348 {
0349     int err;
0350 
0351     switch (cmd) {
0352     case FLOW_BLOCK_BIND:
0353         err = nft_flow_offload_bind(bo, basechain);
0354         break;
0355     case FLOW_BLOCK_UNBIND:
0356         err = nft_flow_offload_unbind(bo, basechain);
0357         break;
0358     default:
0359         WARN_ON_ONCE(1);
0360         err = -EOPNOTSUPP;
0361     }
0362 
0363     return err;
0364 }
0365 
0366 static void nft_flow_block_offload_init(struct flow_block_offload *bo,
0367                     struct net *net,
0368                     enum flow_block_command cmd,
0369                     struct nft_base_chain *basechain,
0370                     struct netlink_ext_ack *extack)
0371 {
0372     memset(bo, 0, sizeof(*bo));
0373     bo->net     = net;
0374     bo->block   = &basechain->flow_block;
0375     bo->command = cmd;
0376     bo->binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
0377     bo->extack  = extack;
0378     bo->cb_list_head = &basechain->flow_block.cb_list;
0379     INIT_LIST_HEAD(&bo->cb_list);
0380 }
0381 
0382 static int nft_block_offload_cmd(struct nft_base_chain *chain,
0383                  struct net_device *dev,
0384                  enum flow_block_command cmd)
0385 {
0386     struct netlink_ext_ack extack = {};
0387     struct flow_block_offload bo;
0388     int err;
0389 
0390     nft_flow_block_offload_init(&bo, dev_net(dev), cmd, chain, &extack);
0391 
0392     err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo);
0393     if (err < 0)
0394         return err;
0395 
0396     return nft_block_setup(chain, &bo, cmd);
0397 }
0398 
0399 static void nft_indr_block_cleanup(struct flow_block_cb *block_cb)
0400 {
0401     struct nft_base_chain *basechain = block_cb->indr.data;
0402     struct net_device *dev = block_cb->indr.dev;
0403     struct netlink_ext_ack extack = {};
0404     struct nftables_pernet *nft_net;
0405     struct net *net = dev_net(dev);
0406     struct flow_block_offload bo;
0407 
0408     nft_flow_block_offload_init(&bo, dev_net(dev), FLOW_BLOCK_UNBIND,
0409                     basechain, &extack);
0410     nft_net = nft_pernet(net);
0411     mutex_lock(&nft_net->commit_mutex);
0412     list_del(&block_cb->driver_list);
0413     list_move(&block_cb->list, &bo.cb_list);
0414     nft_flow_offload_unbind(&bo, basechain);
0415     mutex_unlock(&nft_net->commit_mutex);
0416 }
0417 
0418 static int nft_indr_block_offload_cmd(struct nft_base_chain *basechain,
0419                       struct net_device *dev,
0420                       enum flow_block_command cmd)
0421 {
0422     struct netlink_ext_ack extack = {};
0423     struct flow_block_offload bo;
0424     int err;
0425 
0426     nft_flow_block_offload_init(&bo, dev_net(dev), cmd, basechain, &extack);
0427 
0428     err = flow_indr_dev_setup_offload(dev, NULL, TC_SETUP_BLOCK, basechain, &bo,
0429                       nft_indr_block_cleanup);
0430     if (err < 0)
0431         return err;
0432 
0433     if (list_empty(&bo.cb_list))
0434         return -EOPNOTSUPP;
0435 
0436     return nft_block_setup(basechain, &bo, cmd);
0437 }
0438 
0439 static int nft_chain_offload_cmd(struct nft_base_chain *basechain,
0440                  struct net_device *dev,
0441                  enum flow_block_command cmd)
0442 {
0443     int err;
0444 
0445     if (dev->netdev_ops->ndo_setup_tc)
0446         err = nft_block_offload_cmd(basechain, dev, cmd);
0447     else
0448         err = nft_indr_block_offload_cmd(basechain, dev, cmd);
0449 
0450     return err;
0451 }
0452 
0453 static int nft_flow_block_chain(struct nft_base_chain *basechain,
0454                 const struct net_device *this_dev,
0455                 enum flow_block_command cmd)
0456 {
0457     struct net_device *dev;
0458     struct nft_hook *hook;
0459     int err, i = 0;
0460 
0461     list_for_each_entry(hook, &basechain->hook_list, list) {
0462         dev = hook->ops.dev;
0463         if (this_dev && this_dev != dev)
0464             continue;
0465 
0466         err = nft_chain_offload_cmd(basechain, dev, cmd);
0467         if (err < 0 && cmd == FLOW_BLOCK_BIND) {
0468             if (!this_dev)
0469                 goto err_flow_block;
0470 
0471             return err;
0472         }
0473         i++;
0474     }
0475 
0476     return 0;
0477 
0478 err_flow_block:
0479     list_for_each_entry(hook, &basechain->hook_list, list) {
0480         if (i-- <= 0)
0481             break;
0482 
0483         dev = hook->ops.dev;
0484         nft_chain_offload_cmd(basechain, dev, FLOW_BLOCK_UNBIND);
0485     }
0486     return err;
0487 }
0488 
0489 static int nft_flow_offload_chain(struct nft_chain *chain, u8 *ppolicy,
0490                   enum flow_block_command cmd)
0491 {
0492     struct nft_base_chain *basechain;
0493     u8 policy;
0494 
0495     if (!nft_is_base_chain(chain))
0496         return -EOPNOTSUPP;
0497 
0498     basechain = nft_base_chain(chain);
0499     policy = ppolicy ? *ppolicy : basechain->policy;
0500 
0501     /* Only default policy to accept is supported for now. */
0502     if (cmd == FLOW_BLOCK_BIND && policy == NF_DROP)
0503         return -EOPNOTSUPP;
0504 
0505     return nft_flow_block_chain(basechain, NULL, cmd);
0506 }
0507 
0508 static void nft_flow_rule_offload_abort(struct net *net,
0509                     struct nft_trans *trans)
0510 {
0511     struct nftables_pernet *nft_net = nft_pernet(net);
0512     int err = 0;
0513 
0514     list_for_each_entry_continue_reverse(trans, &nft_net->commit_list, list) {
0515         if (trans->ctx.family != NFPROTO_NETDEV)
0516             continue;
0517 
0518         switch (trans->msg_type) {
0519         case NFT_MSG_NEWCHAIN:
0520             if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD) ||
0521                 nft_trans_chain_update(trans))
0522                 continue;
0523 
0524             err = nft_flow_offload_chain(trans->ctx.chain, NULL,
0525                              FLOW_BLOCK_UNBIND);
0526             break;
0527         case NFT_MSG_DELCHAIN:
0528             if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
0529                 continue;
0530 
0531             err = nft_flow_offload_chain(trans->ctx.chain, NULL,
0532                              FLOW_BLOCK_BIND);
0533             break;
0534         case NFT_MSG_NEWRULE:
0535             if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
0536                 continue;
0537 
0538             err = nft_flow_offload_rule(trans->ctx.chain,
0539                             nft_trans_rule(trans),
0540                             NULL, FLOW_CLS_DESTROY);
0541             break;
0542         case NFT_MSG_DELRULE:
0543             if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
0544                 continue;
0545 
0546             err = nft_flow_offload_rule(trans->ctx.chain,
0547                             nft_trans_rule(trans),
0548                             nft_trans_flow_rule(trans),
0549                             FLOW_CLS_REPLACE);
0550             break;
0551         }
0552 
0553         if (WARN_ON_ONCE(err))
0554             break;
0555     }
0556 }
0557 
0558 int nft_flow_rule_offload_commit(struct net *net)
0559 {
0560     struct nftables_pernet *nft_net = nft_pernet(net);
0561     struct nft_trans *trans;
0562     int err = 0;
0563     u8 policy;
0564 
0565     list_for_each_entry(trans, &nft_net->commit_list, list) {
0566         if (trans->ctx.family != NFPROTO_NETDEV)
0567             continue;
0568 
0569         switch (trans->msg_type) {
0570         case NFT_MSG_NEWCHAIN:
0571             if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD) ||
0572                 nft_trans_chain_update(trans))
0573                 continue;
0574 
0575             policy = nft_trans_chain_policy(trans);
0576             err = nft_flow_offload_chain(trans->ctx.chain, &policy,
0577                              FLOW_BLOCK_BIND);
0578             break;
0579         case NFT_MSG_DELCHAIN:
0580             if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
0581                 continue;
0582 
0583             policy = nft_trans_chain_policy(trans);
0584             err = nft_flow_offload_chain(trans->ctx.chain, &policy,
0585                              FLOW_BLOCK_UNBIND);
0586             break;
0587         case NFT_MSG_NEWRULE:
0588             if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
0589                 continue;
0590 
0591             if (trans->ctx.flags & NLM_F_REPLACE ||
0592                 !(trans->ctx.flags & NLM_F_APPEND)) {
0593                 err = -EOPNOTSUPP;
0594                 break;
0595             }
0596             err = nft_flow_offload_rule(trans->ctx.chain,
0597                             nft_trans_rule(trans),
0598                             nft_trans_flow_rule(trans),
0599                             FLOW_CLS_REPLACE);
0600             break;
0601         case NFT_MSG_DELRULE:
0602             if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
0603                 continue;
0604 
0605             err = nft_flow_offload_rule(trans->ctx.chain,
0606                             nft_trans_rule(trans),
0607                             NULL, FLOW_CLS_DESTROY);
0608             break;
0609         }
0610 
0611         if (err) {
0612             nft_flow_rule_offload_abort(net, trans);
0613             break;
0614         }
0615     }
0616 
0617     return err;
0618 }
0619 
0620 static struct nft_chain *__nft_offload_get_chain(const struct nftables_pernet *nft_net,
0621                          struct net_device *dev)
0622 {
0623     struct nft_base_chain *basechain;
0624     struct nft_hook *hook, *found;
0625     const struct nft_table *table;
0626     struct nft_chain *chain;
0627 
0628     list_for_each_entry(table, &nft_net->tables, list) {
0629         if (table->family != NFPROTO_NETDEV)
0630             continue;
0631 
0632         list_for_each_entry(chain, &table->chains, list) {
0633             if (!nft_is_base_chain(chain) ||
0634                 !(chain->flags & NFT_CHAIN_HW_OFFLOAD))
0635                 continue;
0636 
0637             found = NULL;
0638             basechain = nft_base_chain(chain);
0639             list_for_each_entry(hook, &basechain->hook_list, list) {
0640                 if (hook->ops.dev != dev)
0641                     continue;
0642 
0643                 found = hook;
0644                 break;
0645             }
0646             if (!found)
0647                 continue;
0648 
0649             return chain;
0650         }
0651     }
0652 
0653     return NULL;
0654 }
0655 
0656 static int nft_offload_netdev_event(struct notifier_block *this,
0657                     unsigned long event, void *ptr)
0658 {
0659     struct net_device *dev = netdev_notifier_info_to_dev(ptr);
0660     struct nftables_pernet *nft_net;
0661     struct net *net = dev_net(dev);
0662     struct nft_chain *chain;
0663 
0664     if (event != NETDEV_UNREGISTER)
0665         return NOTIFY_DONE;
0666 
0667     nft_net = nft_pernet(net);
0668     mutex_lock(&nft_net->commit_mutex);
0669     chain = __nft_offload_get_chain(nft_net, dev);
0670     if (chain)
0671         nft_flow_block_chain(nft_base_chain(chain), dev,
0672                      FLOW_BLOCK_UNBIND);
0673 
0674     mutex_unlock(&nft_net->commit_mutex);
0675 
0676     return NOTIFY_DONE;
0677 }
0678 
0679 static struct notifier_block nft_offload_netdev_notifier = {
0680     .notifier_call  = nft_offload_netdev_event,
0681 };
0682 
0683 int nft_offload_init(void)
0684 {
0685     return register_netdevice_notifier(&nft_offload_netdev_notifier);
0686 }
0687 
0688 void nft_offload_exit(void)
0689 {
0690     unregister_netdevice_notifier(&nft_offload_netdev_notifier);
0691 }