diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index beedd0d2b50973d7394a7c929530701b98e374e3..7801d8c552c9072432b7f216821a4e21eaaa4f56 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -1397,6 +1397,19 @@ void tcf_block_put(struct tcf_block *block) EXPORT_SYMBOL(tcf_block_put); +void (* const tmplt_reoffload)(struct tcf_chain *chain, bool add, + flow_setup_cb_t *cb, void *cb_priv); +EXPORT_SYMBOL(tmplt_reoffload); + +static void cls_tmplt_reoffload(struct tcf_chain *chain, bool add, + flow_setup_cb_t *cb, void *cb_priv) +{ + if (!tmplt_reoffload) + return; + + tmplt_reoffload(chain, add, cb, cb_priv); +} + static int tcf_block_playback_offloads(struct tcf_block *block, flow_setup_cb_t *cb, void *cb_priv, bool add, bool offload_in_use, @@ -1413,6 +1426,10 @@ tcf_block_playback_offloads(struct tcf_block *block, flow_setup_cb_t *cb, chain_prev = chain, chain = __tcf_get_next_chain(block, chain), tcf_chain_put(chain_prev)) { + if (chain->tmplt_ops && add) + if (!strcmp(chain->tmplt_ops->kind, "flower")) + cls_tmplt_reoffload(chain, true, cb, cb_priv); + for (tp = __tcf_get_next_proto(chain, NULL); tp; tp_prev = tp, tp = __tcf_get_next_proto(chain, tp), @@ -1428,6 +1445,9 @@ tcf_block_playback_offloads(struct tcf_block *block, flow_setup_cb_t *cb, goto err_playback_remove; } } + if (chain->tmplt_ops && !add) + if (!strcmp(chain->tmplt_ops->kind, "flower")) + cls_tmplt_reoffload(chain, false, cb, cb_priv); } return 0; diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index dc21e7fb1038b93fcc07ec95dfecb7cf3c486e06..3a1c139c426e6e73414a177747421f69fbcbdc29 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -336,6 +336,12 @@ static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, return -1; } +extern void (*tmplt_reoffload)(struct tcf_chain *chain, bool add, + flow_setup_cb_t *cb, void *cb_priv); + +static void fl_tmplt_reoffload(struct tcf_chain *chain, bool add, + flow_setup_cb_t *cb, void *cb_priv); + static int fl_init(struct tcf_proto *tp) { struct cls_fl_head *head; @@ -350,6 +356,8 @@ static int fl_init(struct tcf_proto *tp) rcu_assign_pointer(tp->root, head); idr_init(&head->handle_idr); + tmplt_reoffload = &fl_tmplt_reoffload; + return rhashtable_init(&head->ht, &mask_ht_params); } @@ -588,6 +596,8 @@ static void fl_destroy(struct tcf_proto *tp, bool rtnl_held, __module_get(THIS_MODULE); tcf_queue_work(&head->rwork, fl_destroy_sleepable); + + tmplt_reoffload = NULL; } static void fl_put(struct tcf_proto *tp, void *arg) @@ -2406,6 +2416,28 @@ static void fl_tmplt_destroy(void *tmplt_priv) kfree(tmplt); } +static void fl_tmplt_reoffload(struct tcf_chain *chain, bool add, + flow_setup_cb_t *cb, void *cb_priv) +{ + struct fl_flow_tmplt *tmplt = chain->tmplt_priv; + struct flow_cls_offload cls_flower = {}; + + cls_flower.rule = flow_rule_alloc(0); + if (!cls_flower.rule) + return; + + cls_flower.common.chain_index = chain->index; + cls_flower.command = add ? FLOW_CLS_TMPLT_CREATE : + FLOW_CLS_TMPLT_DESTROY; + cls_flower.cookie = (unsigned long) tmplt; + cls_flower.rule->match.dissector = &tmplt->dissector; + cls_flower.rule->match.mask = &tmplt->mask; + cls_flower.rule->match.key = &tmplt->dummy_key; + + cb(TC_SETUP_CLSFLOWER, &cls_flower, cb_priv); + kfree(cls_flower.rule); +} + static int fl_dump_key_val(struct sk_buff *skb, void *val, int val_type, void *mask, int mask_type, int len)