18f256622SPablo Neira Ayuso /* SPDX-License-Identifier: GPL-2.0 */
28f256622SPablo Neira Ayuso #include <linux/kernel.h>
38f256622SPablo Neira Ayuso #include <linux/slab.h>
413926d19SBaowen Zheng #include <net/act_api.h>
58f256622SPablo Neira Ayuso #include <net/flow_offload.h>
64e481908Swenxu #include <linux/rtnetlink.h>
71150ab0fSwenxu #include <linux/mutex.h>
8c2b69f24SHerbert Xu #include <linux/rhashtable.h>
98f256622SPablo Neira Ayuso
flow_rule_alloc(unsigned int num_actions)10e3ab786bSPablo Neira Ayuso struct flow_rule *flow_rule_alloc(unsigned int num_actions)
118f256622SPablo Neira Ayuso {
12e3ab786bSPablo Neira Ayuso struct flow_rule *rule;
13060b6381SEdward Cree int i;
14e3ab786bSPablo Neira Ayuso
156dca9360SGustavo A. R. Silva rule = kzalloc(struct_size(rule, action.entries, num_actions),
16e3ab786bSPablo Neira Ayuso GFP_KERNEL);
17e3ab786bSPablo Neira Ayuso if (!rule)
18e3ab786bSPablo Neira Ayuso return NULL;
19e3ab786bSPablo Neira Ayuso
20e3ab786bSPablo Neira Ayuso rule->action.num_entries = num_actions;
21060b6381SEdward Cree /* Pre-fill each action hw_stats with DONT_CARE.
22060b6381SEdward Cree * Caller can override this if it wants stats for a given action.
23060b6381SEdward Cree */
24060b6381SEdward Cree for (i = 0; i < num_actions; i++)
25060b6381SEdward Cree rule->action.entries[i].hw_stats = FLOW_ACTION_HW_STATS_DONT_CARE;
26e3ab786bSPablo Neira Ayuso
27e3ab786bSPablo Neira Ayuso return rule;
288f256622SPablo Neira Ayuso }
298f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_alloc);
308f256622SPablo Neira Ayuso
offload_action_alloc(unsigned int num_actions)318cbfe939SBaowen Zheng struct flow_offload_action *offload_action_alloc(unsigned int num_actions)
328cbfe939SBaowen Zheng {
338cbfe939SBaowen Zheng struct flow_offload_action *fl_action;
348cbfe939SBaowen Zheng int i;
358cbfe939SBaowen Zheng
368cbfe939SBaowen Zheng fl_action = kzalloc(struct_size(fl_action, action.entries, num_actions),
378cbfe939SBaowen Zheng GFP_KERNEL);
388cbfe939SBaowen Zheng if (!fl_action)
398cbfe939SBaowen Zheng return NULL;
408cbfe939SBaowen Zheng
418cbfe939SBaowen Zheng fl_action->action.num_entries = num_actions;
428cbfe939SBaowen Zheng /* Pre-fill each action hw_stats with DONT_CARE.
438cbfe939SBaowen Zheng * Caller can override this if it wants stats for a given action.
448cbfe939SBaowen Zheng */
458cbfe939SBaowen Zheng for (i = 0; i < num_actions; i++)
468cbfe939SBaowen Zheng fl_action->action.entries[i].hw_stats = FLOW_ACTION_HW_STATS_DONT_CARE;
478cbfe939SBaowen Zheng
488cbfe939SBaowen Zheng return fl_action;
498cbfe939SBaowen Zheng }
508cbfe939SBaowen Zheng
518f256622SPablo Neira Ayuso #define FLOW_DISSECTOR_MATCH(__rule, __type, __out) \
528f256622SPablo Neira Ayuso const struct flow_match *__m = &(__rule)->match; \
538f256622SPablo Neira Ayuso struct flow_dissector *__d = (__m)->dissector; \
548f256622SPablo Neira Ayuso \
558f256622SPablo Neira Ayuso (__out)->key = skb_flow_dissector_target(__d, __type, (__m)->key); \
568f256622SPablo Neira Ayuso (__out)->mask = skb_flow_dissector_target(__d, __type, (__m)->mask); \
578f256622SPablo Neira Ayuso
flow_rule_match_meta(const struct flow_rule * rule,struct flow_match_meta * out)589558a83aSJiri Pirko void flow_rule_match_meta(const struct flow_rule *rule,
599558a83aSJiri Pirko struct flow_match_meta *out)
609558a83aSJiri Pirko {
619558a83aSJiri Pirko FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_META, out);
629558a83aSJiri Pirko }
639558a83aSJiri Pirko EXPORT_SYMBOL(flow_rule_match_meta);
649558a83aSJiri Pirko
flow_rule_match_basic(const struct flow_rule * rule,struct flow_match_basic * out)658f256622SPablo Neira Ayuso void flow_rule_match_basic(const struct flow_rule *rule,
668f256622SPablo Neira Ayuso struct flow_match_basic *out)
678f256622SPablo Neira Ayuso {
688f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_BASIC, out);
698f256622SPablo Neira Ayuso }
708f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_basic);
718f256622SPablo Neira Ayuso
flow_rule_match_control(const struct flow_rule * rule,struct flow_match_control * out)728f256622SPablo Neira Ayuso void flow_rule_match_control(const struct flow_rule *rule,
738f256622SPablo Neira Ayuso struct flow_match_control *out)
748f256622SPablo Neira Ayuso {
758f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_CONTROL, out);
768f256622SPablo Neira Ayuso }
778f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_control);
788f256622SPablo Neira Ayuso
flow_rule_match_eth_addrs(const struct flow_rule * rule,struct flow_match_eth_addrs * out)798f256622SPablo Neira Ayuso void flow_rule_match_eth_addrs(const struct flow_rule *rule,
808f256622SPablo Neira Ayuso struct flow_match_eth_addrs *out)
818f256622SPablo Neira Ayuso {
828f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS, out);
838f256622SPablo Neira Ayuso }
848f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_eth_addrs);
858f256622SPablo Neira Ayuso
flow_rule_match_vlan(const struct flow_rule * rule,struct flow_match_vlan * out)868f256622SPablo Neira Ayuso void flow_rule_match_vlan(const struct flow_rule *rule,
878f256622SPablo Neira Ayuso struct flow_match_vlan *out)
888f256622SPablo Neira Ayuso {
898f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_VLAN, out);
908f256622SPablo Neira Ayuso }
918f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_vlan);
928f256622SPablo Neira Ayuso
flow_rule_match_cvlan(const struct flow_rule * rule,struct flow_match_vlan * out)93bae9ed69SEdward Cree void flow_rule_match_cvlan(const struct flow_rule *rule,
94bae9ed69SEdward Cree struct flow_match_vlan *out)
95bae9ed69SEdward Cree {
96bae9ed69SEdward Cree FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_CVLAN, out);
97bae9ed69SEdward Cree }
98bae9ed69SEdward Cree EXPORT_SYMBOL(flow_rule_match_cvlan);
99bae9ed69SEdward Cree
flow_rule_match_arp(const struct flow_rule * rule,struct flow_match_arp * out)10070ea86a0SSteen Hegelund void flow_rule_match_arp(const struct flow_rule *rule,
10170ea86a0SSteen Hegelund struct flow_match_arp *out)
10270ea86a0SSteen Hegelund {
10370ea86a0SSteen Hegelund FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ARP, out);
10470ea86a0SSteen Hegelund }
10570ea86a0SSteen Hegelund EXPORT_SYMBOL(flow_rule_match_arp);
10670ea86a0SSteen Hegelund
flow_rule_match_ipv4_addrs(const struct flow_rule * rule,struct flow_match_ipv4_addrs * out)1078f256622SPablo Neira Ayuso void flow_rule_match_ipv4_addrs(const struct flow_rule *rule,
1088f256622SPablo Neira Ayuso struct flow_match_ipv4_addrs *out)
1098f256622SPablo Neira Ayuso {
1108f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS, out);
1118f256622SPablo Neira Ayuso }
1128f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_ipv4_addrs);
1138f256622SPablo Neira Ayuso
flow_rule_match_ipv6_addrs(const struct flow_rule * rule,struct flow_match_ipv6_addrs * out)1148f256622SPablo Neira Ayuso void flow_rule_match_ipv6_addrs(const struct flow_rule *rule,
1158f256622SPablo Neira Ayuso struct flow_match_ipv6_addrs *out)
1168f256622SPablo Neira Ayuso {
1178f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS, out);
1188f256622SPablo Neira Ayuso }
1198f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_ipv6_addrs);
1208f256622SPablo Neira Ayuso
flow_rule_match_ip(const struct flow_rule * rule,struct flow_match_ip * out)1218f256622SPablo Neira Ayuso void flow_rule_match_ip(const struct flow_rule *rule,
1228f256622SPablo Neira Ayuso struct flow_match_ip *out)
1238f256622SPablo Neira Ayuso {
1248f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IP, out);
1258f256622SPablo Neira Ayuso }
1268f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_ip);
1278f256622SPablo Neira Ayuso
flow_rule_match_ports(const struct flow_rule * rule,struct flow_match_ports * out)1288f256622SPablo Neira Ayuso void flow_rule_match_ports(const struct flow_rule *rule,
1298f256622SPablo Neira Ayuso struct flow_match_ports *out)
1308f256622SPablo Neira Ayuso {
1318f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_PORTS, out);
1328f256622SPablo Neira Ayuso }
1338f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_ports);
1348f256622SPablo Neira Ayuso
flow_rule_match_ports_range(const struct flow_rule * rule,struct flow_match_ports_range * out)13583d85bb0SMaksym Glubokiy void flow_rule_match_ports_range(const struct flow_rule *rule,
13683d85bb0SMaksym Glubokiy struct flow_match_ports_range *out)
13783d85bb0SMaksym Glubokiy {
13883d85bb0SMaksym Glubokiy FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_PORTS_RANGE, out);
13983d85bb0SMaksym Glubokiy }
14083d85bb0SMaksym Glubokiy EXPORT_SYMBOL(flow_rule_match_ports_range);
14183d85bb0SMaksym Glubokiy
flow_rule_match_tcp(const struct flow_rule * rule,struct flow_match_tcp * out)1428f256622SPablo Neira Ayuso void flow_rule_match_tcp(const struct flow_rule *rule,
1438f256622SPablo Neira Ayuso struct flow_match_tcp *out)
1448f256622SPablo Neira Ayuso {
1458f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_TCP, out);
1468f256622SPablo Neira Ayuso }
1478f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_tcp);
1488f256622SPablo Neira Ayuso
flow_rule_match_ipsec(const struct flow_rule * rule,struct flow_match_ipsec * out)149*c8915d73SRatheesh Kannoth void flow_rule_match_ipsec(const struct flow_rule *rule,
150*c8915d73SRatheesh Kannoth struct flow_match_ipsec *out)
151*c8915d73SRatheesh Kannoth {
152*c8915d73SRatheesh Kannoth FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPSEC, out);
153*c8915d73SRatheesh Kannoth }
154*c8915d73SRatheesh Kannoth EXPORT_SYMBOL(flow_rule_match_ipsec);
155*c8915d73SRatheesh Kannoth
flow_rule_match_icmp(const struct flow_rule * rule,struct flow_match_icmp * out)1568f256622SPablo Neira Ayuso void flow_rule_match_icmp(const struct flow_rule *rule,
1578f256622SPablo Neira Ayuso struct flow_match_icmp *out)
1588f256622SPablo Neira Ayuso {
1598f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ICMP, out);
1608f256622SPablo Neira Ayuso }
1618f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_icmp);
1628f256622SPablo Neira Ayuso
flow_rule_match_mpls(const struct flow_rule * rule,struct flow_match_mpls * out)1638f256622SPablo Neira Ayuso void flow_rule_match_mpls(const struct flow_rule *rule,
1648f256622SPablo Neira Ayuso struct flow_match_mpls *out)
1658f256622SPablo Neira Ayuso {
1668f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_MPLS, out);
1678f256622SPablo Neira Ayuso }
1688f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_mpls);
1698f256622SPablo Neira Ayuso
flow_rule_match_enc_control(const struct flow_rule * rule,struct flow_match_control * out)1708f256622SPablo Neira Ayuso void flow_rule_match_enc_control(const struct flow_rule *rule,
1718f256622SPablo Neira Ayuso struct flow_match_control *out)
1728f256622SPablo Neira Ayuso {
1738f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_CONTROL, out);
1748f256622SPablo Neira Ayuso }
1758f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_enc_control);
1768f256622SPablo Neira Ayuso
flow_rule_match_enc_ipv4_addrs(const struct flow_rule * rule,struct flow_match_ipv4_addrs * out)1778f256622SPablo Neira Ayuso void flow_rule_match_enc_ipv4_addrs(const struct flow_rule *rule,
1788f256622SPablo Neira Ayuso struct flow_match_ipv4_addrs *out)
1798f256622SPablo Neira Ayuso {
1808f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, out);
1818f256622SPablo Neira Ayuso }
1828f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_enc_ipv4_addrs);
1838f256622SPablo Neira Ayuso
flow_rule_match_enc_ipv6_addrs(const struct flow_rule * rule,struct flow_match_ipv6_addrs * out)1848f256622SPablo Neira Ayuso void flow_rule_match_enc_ipv6_addrs(const struct flow_rule *rule,
1858f256622SPablo Neira Ayuso struct flow_match_ipv6_addrs *out)
1868f256622SPablo Neira Ayuso {
1878f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, out);
1888f256622SPablo Neira Ayuso }
1898f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_enc_ipv6_addrs);
1908f256622SPablo Neira Ayuso
flow_rule_match_enc_ip(const struct flow_rule * rule,struct flow_match_ip * out)1918f256622SPablo Neira Ayuso void flow_rule_match_enc_ip(const struct flow_rule *rule,
1928f256622SPablo Neira Ayuso struct flow_match_ip *out)
1938f256622SPablo Neira Ayuso {
1948f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IP, out);
1958f256622SPablo Neira Ayuso }
1968f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_enc_ip);
1978f256622SPablo Neira Ayuso
flow_rule_match_enc_ports(const struct flow_rule * rule,struct flow_match_ports * out)1988f256622SPablo Neira Ayuso void flow_rule_match_enc_ports(const struct flow_rule *rule,
1998f256622SPablo Neira Ayuso struct flow_match_ports *out)
2008f256622SPablo Neira Ayuso {
2018f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_PORTS, out);
2028f256622SPablo Neira Ayuso }
2038f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_enc_ports);
2048f256622SPablo Neira Ayuso
flow_rule_match_enc_keyid(const struct flow_rule * rule,struct flow_match_enc_keyid * out)2058f256622SPablo Neira Ayuso void flow_rule_match_enc_keyid(const struct flow_rule *rule,
2068f256622SPablo Neira Ayuso struct flow_match_enc_keyid *out)
2078f256622SPablo Neira Ayuso {
2088f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_KEYID, out);
2098f256622SPablo Neira Ayuso }
2108f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_enc_keyid);
2118f256622SPablo Neira Ayuso
flow_rule_match_enc_opts(const struct flow_rule * rule,struct flow_match_enc_opts * out)2128f256622SPablo Neira Ayuso void flow_rule_match_enc_opts(const struct flow_rule *rule,
2138f256622SPablo Neira Ayuso struct flow_match_enc_opts *out)
2148f256622SPablo Neira Ayuso {
2158f256622SPablo Neira Ayuso FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_OPTS, out);
2168f256622SPablo Neira Ayuso }
2178f256622SPablo Neira Ayuso EXPORT_SYMBOL(flow_rule_match_enc_opts);
2184e95bc26SPablo Neira Ayuso
flow_action_cookie_create(void * data,unsigned int len,gfp_t gfp)2192008495dSJiri Pirko struct flow_action_cookie *flow_action_cookie_create(void *data,
2202008495dSJiri Pirko unsigned int len,
2212008495dSJiri Pirko gfp_t gfp)
2222008495dSJiri Pirko {
2232008495dSJiri Pirko struct flow_action_cookie *cookie;
2242008495dSJiri Pirko
2252008495dSJiri Pirko cookie = kmalloc(sizeof(*cookie) + len, gfp);
2262008495dSJiri Pirko if (!cookie)
2272008495dSJiri Pirko return NULL;
2282008495dSJiri Pirko cookie->cookie_len = len;
2292008495dSJiri Pirko memcpy(cookie->cookie, data, len);
2302008495dSJiri Pirko return cookie;
2312008495dSJiri Pirko }
2322008495dSJiri Pirko EXPORT_SYMBOL(flow_action_cookie_create);
2332008495dSJiri Pirko
flow_action_cookie_destroy(struct flow_action_cookie * cookie)2342008495dSJiri Pirko void flow_action_cookie_destroy(struct flow_action_cookie *cookie)
2352008495dSJiri Pirko {
2362008495dSJiri Pirko kfree(cookie);
2372008495dSJiri Pirko }
2382008495dSJiri Pirko EXPORT_SYMBOL(flow_action_cookie_destroy);
2392008495dSJiri Pirko
flow_rule_match_ct(const struct flow_rule * rule,struct flow_match_ct * out)240ee1c45e8SPaul Blakey void flow_rule_match_ct(const struct flow_rule *rule,
241ee1c45e8SPaul Blakey struct flow_match_ct *out)
242ee1c45e8SPaul Blakey {
243ee1c45e8SPaul Blakey FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_CT, out);
244ee1c45e8SPaul Blakey }
245ee1c45e8SPaul Blakey EXPORT_SYMBOL(flow_rule_match_ct);
246ee1c45e8SPaul Blakey
flow_rule_match_pppoe(const struct flow_rule * rule,struct flow_match_pppoe * out)2476a21b085SWojciech Drewek void flow_rule_match_pppoe(const struct flow_rule *rule,
2486a21b085SWojciech Drewek struct flow_match_pppoe *out)
2496a21b085SWojciech Drewek {
2506a21b085SWojciech Drewek FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_PPPOE, out);
2516a21b085SWojciech Drewek }
2526a21b085SWojciech Drewek EXPORT_SYMBOL(flow_rule_match_pppoe);
2536a21b085SWojciech Drewek
flow_rule_match_l2tpv3(const struct flow_rule * rule,struct flow_match_l2tpv3 * out)2542c1befacSWojciech Drewek void flow_rule_match_l2tpv3(const struct flow_rule *rule,
2552c1befacSWojciech Drewek struct flow_match_l2tpv3 *out)
2562c1befacSWojciech Drewek {
2572c1befacSWojciech Drewek FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_L2TPV3, out);
2582c1befacSWojciech Drewek }
2592c1befacSWojciech Drewek EXPORT_SYMBOL(flow_rule_match_l2tpv3);
2602c1befacSWojciech Drewek
flow_block_cb_alloc(flow_setup_cb_t * cb,void * cb_ident,void * cb_priv,void (* release)(void * cb_priv))261a7323311SPablo Neira Ayuso struct flow_block_cb *flow_block_cb_alloc(flow_setup_cb_t *cb,
262d63db30cSPablo Neira Ayuso void *cb_ident, void *cb_priv,
263d63db30cSPablo Neira Ayuso void (*release)(void *cb_priv))
264d63db30cSPablo Neira Ayuso {
265d63db30cSPablo Neira Ayuso struct flow_block_cb *block_cb;
266d63db30cSPablo Neira Ayuso
267d63db30cSPablo Neira Ayuso block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL);
268d63db30cSPablo Neira Ayuso if (!block_cb)
269d63db30cSPablo Neira Ayuso return ERR_PTR(-ENOMEM);
270d63db30cSPablo Neira Ayuso
271d63db30cSPablo Neira Ayuso block_cb->cb = cb;
272d63db30cSPablo Neira Ayuso block_cb->cb_ident = cb_ident;
273d63db30cSPablo Neira Ayuso block_cb->cb_priv = cb_priv;
274d63db30cSPablo Neira Ayuso block_cb->release = release;
275d63db30cSPablo Neira Ayuso
276d63db30cSPablo Neira Ayuso return block_cb;
277d63db30cSPablo Neira Ayuso }
278d63db30cSPablo Neira Ayuso EXPORT_SYMBOL(flow_block_cb_alloc);
279d63db30cSPablo Neira Ayuso
flow_block_cb_free(struct flow_block_cb * block_cb)280d63db30cSPablo Neira Ayuso void flow_block_cb_free(struct flow_block_cb *block_cb)
281d63db30cSPablo Neira Ayuso {
282d63db30cSPablo Neira Ayuso if (block_cb->release)
283d63db30cSPablo Neira Ayuso block_cb->release(block_cb->cb_priv);
284d63db30cSPablo Neira Ayuso
285d63db30cSPablo Neira Ayuso kfree(block_cb);
286d63db30cSPablo Neira Ayuso }
287d63db30cSPablo Neira Ayuso EXPORT_SYMBOL(flow_block_cb_free);
288d63db30cSPablo Neira Ayuso
flow_block_cb_lookup(struct flow_block * block,flow_setup_cb_t * cb,void * cb_ident)28914bfb13fSPablo Neira Ayuso struct flow_block_cb *flow_block_cb_lookup(struct flow_block *block,
290a7323311SPablo Neira Ayuso flow_setup_cb_t *cb, void *cb_ident)
291da3eeb90SPablo Neira Ayuso {
292da3eeb90SPablo Neira Ayuso struct flow_block_cb *block_cb;
293da3eeb90SPablo Neira Ayuso
29414bfb13fSPablo Neira Ayuso list_for_each_entry(block_cb, &block->cb_list, list) {
2950c7294ddSPablo Neira Ayuso if (block_cb->cb == cb &&
296da3eeb90SPablo Neira Ayuso block_cb->cb_ident == cb_ident)
297da3eeb90SPablo Neira Ayuso return block_cb;
298da3eeb90SPablo Neira Ayuso }
299da3eeb90SPablo Neira Ayuso
300da3eeb90SPablo Neira Ayuso return NULL;
301da3eeb90SPablo Neira Ayuso }
302da3eeb90SPablo Neira Ayuso EXPORT_SYMBOL(flow_block_cb_lookup);
303da3eeb90SPablo Neira Ayuso
flow_block_cb_priv(struct flow_block_cb * block_cb)30467bd0d5eSPablo Neira Ayuso void *flow_block_cb_priv(struct flow_block_cb *block_cb)
30567bd0d5eSPablo Neira Ayuso {
30667bd0d5eSPablo Neira Ayuso return block_cb->cb_priv;
30767bd0d5eSPablo Neira Ayuso }
30867bd0d5eSPablo Neira Ayuso EXPORT_SYMBOL(flow_block_cb_priv);
30967bd0d5eSPablo Neira Ayuso
flow_block_cb_incref(struct flow_block_cb * block_cb)31067bd0d5eSPablo Neira Ayuso void flow_block_cb_incref(struct flow_block_cb *block_cb)
31167bd0d5eSPablo Neira Ayuso {
31267bd0d5eSPablo Neira Ayuso block_cb->refcnt++;
31367bd0d5eSPablo Neira Ayuso }
31467bd0d5eSPablo Neira Ayuso EXPORT_SYMBOL(flow_block_cb_incref);
31567bd0d5eSPablo Neira Ayuso
flow_block_cb_decref(struct flow_block_cb * block_cb)31667bd0d5eSPablo Neira Ayuso unsigned int flow_block_cb_decref(struct flow_block_cb *block_cb)
31767bd0d5eSPablo Neira Ayuso {
31867bd0d5eSPablo Neira Ayuso return --block_cb->refcnt;
31967bd0d5eSPablo Neira Ayuso }
32067bd0d5eSPablo Neira Ayuso EXPORT_SYMBOL(flow_block_cb_decref);
32167bd0d5eSPablo Neira Ayuso
flow_block_cb_is_busy(flow_setup_cb_t * cb,void * cb_ident,struct list_head * driver_block_list)322a7323311SPablo Neira Ayuso bool flow_block_cb_is_busy(flow_setup_cb_t *cb, void *cb_ident,
3230d4fd02eSPablo Neira Ayuso struct list_head *driver_block_list)
3240d4fd02eSPablo Neira Ayuso {
3250d4fd02eSPablo Neira Ayuso struct flow_block_cb *block_cb;
3260d4fd02eSPablo Neira Ayuso
3270d4fd02eSPablo Neira Ayuso list_for_each_entry(block_cb, driver_block_list, driver_list) {
3280d4fd02eSPablo Neira Ayuso if (block_cb->cb == cb &&
3290d4fd02eSPablo Neira Ayuso block_cb->cb_ident == cb_ident)
3300d4fd02eSPablo Neira Ayuso return true;
3310d4fd02eSPablo Neira Ayuso }
3320d4fd02eSPablo Neira Ayuso
3330d4fd02eSPablo Neira Ayuso return false;
3340d4fd02eSPablo Neira Ayuso }
3350d4fd02eSPablo Neira Ayuso EXPORT_SYMBOL(flow_block_cb_is_busy);
3360d4fd02eSPablo Neira Ayuso
flow_block_cb_setup_simple(struct flow_block_offload * f,struct list_head * driver_block_list,flow_setup_cb_t * cb,void * cb_ident,void * cb_priv,bool ingress_only)3374e95bc26SPablo Neira Ayuso int flow_block_cb_setup_simple(struct flow_block_offload *f,
3384e95bc26SPablo Neira Ayuso struct list_head *driver_block_list,
339a7323311SPablo Neira Ayuso flow_setup_cb_t *cb,
340a7323311SPablo Neira Ayuso void *cb_ident, void *cb_priv,
3414e95bc26SPablo Neira Ayuso bool ingress_only)
3424e95bc26SPablo Neira Ayuso {
343955bcb6eSPablo Neira Ayuso struct flow_block_cb *block_cb;
344955bcb6eSPablo Neira Ayuso
3454e95bc26SPablo Neira Ayuso if (ingress_only &&
34632f8c409SPablo Neira Ayuso f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
3474e95bc26SPablo Neira Ayuso return -EOPNOTSUPP;
3484e95bc26SPablo Neira Ayuso
3494e95bc26SPablo Neira Ayuso f->driver_block_list = driver_block_list;
3504e95bc26SPablo Neira Ayuso
3514e95bc26SPablo Neira Ayuso switch (f->command) {
3529c0e189eSPablo Neira Ayuso case FLOW_BLOCK_BIND:
3530d4fd02eSPablo Neira Ayuso if (flow_block_cb_is_busy(cb, cb_ident, driver_block_list))
3540d4fd02eSPablo Neira Ayuso return -EBUSY;
3550d4fd02eSPablo Neira Ayuso
3560c7294ddSPablo Neira Ayuso block_cb = flow_block_cb_alloc(cb, cb_ident, cb_priv, NULL);
357955bcb6eSPablo Neira Ayuso if (IS_ERR(block_cb))
358955bcb6eSPablo Neira Ayuso return PTR_ERR(block_cb);
359955bcb6eSPablo Neira Ayuso
360955bcb6eSPablo Neira Ayuso flow_block_cb_add(block_cb, f);
361955bcb6eSPablo Neira Ayuso list_add_tail(&block_cb->driver_list, driver_block_list);
362955bcb6eSPablo Neira Ayuso return 0;
3639c0e189eSPablo Neira Ayuso case FLOW_BLOCK_UNBIND:
36414bfb13fSPablo Neira Ayuso block_cb = flow_block_cb_lookup(f->block, cb, cb_ident);
365955bcb6eSPablo Neira Ayuso if (!block_cb)
366955bcb6eSPablo Neira Ayuso return -ENOENT;
367955bcb6eSPablo Neira Ayuso
368955bcb6eSPablo Neira Ayuso flow_block_cb_remove(block_cb, f);
369955bcb6eSPablo Neira Ayuso list_del(&block_cb->driver_list);
3704e95bc26SPablo Neira Ayuso return 0;
3714e95bc26SPablo Neira Ayuso default:
3724e95bc26SPablo Neira Ayuso return -EOPNOTSUPP;
3734e95bc26SPablo Neira Ayuso }
3744e95bc26SPablo Neira Ayuso }
3754e95bc26SPablo Neira Ayuso EXPORT_SYMBOL(flow_block_cb_setup_simple);
3764e481908Swenxu
3771fac52daSPablo Neira Ayuso static DEFINE_MUTEX(flow_indr_block_lock);
3781fac52daSPablo Neira Ayuso static LIST_HEAD(flow_block_indr_list);
3791fac52daSPablo Neira Ayuso static LIST_HEAD(flow_block_indr_dev_list);
38074fc4f82SEli Cohen static LIST_HEAD(flow_indir_dev_list);
3811fac52daSPablo Neira Ayuso
3821fac52daSPablo Neira Ayuso struct flow_indr_dev {
3831fac52daSPablo Neira Ayuso struct list_head list;
3841fac52daSPablo Neira Ayuso flow_indr_block_bind_cb_t *cb;
3851fac52daSPablo Neira Ayuso void *cb_priv;
3861fac52daSPablo Neira Ayuso refcount_t refcnt;
3871fac52daSPablo Neira Ayuso };
3881fac52daSPablo Neira Ayuso
flow_indr_dev_alloc(flow_indr_block_bind_cb_t * cb,void * cb_priv)3891fac52daSPablo Neira Ayuso static struct flow_indr_dev *flow_indr_dev_alloc(flow_indr_block_bind_cb_t *cb,
3901fac52daSPablo Neira Ayuso void *cb_priv)
3911fac52daSPablo Neira Ayuso {
3921fac52daSPablo Neira Ayuso struct flow_indr_dev *indr_dev;
3931fac52daSPablo Neira Ayuso
3941fac52daSPablo Neira Ayuso indr_dev = kmalloc(sizeof(*indr_dev), GFP_KERNEL);
3951fac52daSPablo Neira Ayuso if (!indr_dev)
3961fac52daSPablo Neira Ayuso return NULL;
3971fac52daSPablo Neira Ayuso
3981fac52daSPablo Neira Ayuso indr_dev->cb = cb;
3991fac52daSPablo Neira Ayuso indr_dev->cb_priv = cb_priv;
4001fac52daSPablo Neira Ayuso refcount_set(&indr_dev->refcnt, 1);
4011fac52daSPablo Neira Ayuso
4021fac52daSPablo Neira Ayuso return indr_dev;
4031fac52daSPablo Neira Ayuso }
4041fac52daSPablo Neira Ayuso
40574fc4f82SEli Cohen struct flow_indir_dev_info {
40674fc4f82SEli Cohen void *data;
40774fc4f82SEli Cohen struct net_device *dev;
40874fc4f82SEli Cohen struct Qdisc *sch;
40974fc4f82SEli Cohen enum tc_setup_type type;
41074fc4f82SEli Cohen void (*cleanup)(struct flow_block_cb *block_cb);
41174fc4f82SEli Cohen struct list_head list;
41274fc4f82SEli Cohen enum flow_block_command command;
41374fc4f82SEli Cohen enum flow_block_binder_type binder_type;
41474fc4f82SEli Cohen struct list_head *cb_list;
41574fc4f82SEli Cohen };
41674fc4f82SEli Cohen
existing_qdiscs_register(flow_indr_block_bind_cb_t * cb,void * cb_priv)41774fc4f82SEli Cohen static void existing_qdiscs_register(flow_indr_block_bind_cb_t *cb, void *cb_priv)
41874fc4f82SEli Cohen {
41974fc4f82SEli Cohen struct flow_block_offload bo;
42074fc4f82SEli Cohen struct flow_indir_dev_info *cur;
42174fc4f82SEli Cohen
42274fc4f82SEli Cohen list_for_each_entry(cur, &flow_indir_dev_list, list) {
42374fc4f82SEli Cohen memset(&bo, 0, sizeof(bo));
42474fc4f82SEli Cohen bo.command = cur->command;
42574fc4f82SEli Cohen bo.binder_type = cur->binder_type;
42674fc4f82SEli Cohen INIT_LIST_HEAD(&bo.cb_list);
42774fc4f82SEli Cohen cb(cur->dev, cur->sch, cb_priv, cur->type, &bo, cur->data, cur->cleanup);
42874fc4f82SEli Cohen list_splice(&bo.cb_list, cur->cb_list);
42974fc4f82SEli Cohen }
43074fc4f82SEli Cohen }
43174fc4f82SEli Cohen
flow_indr_dev_register(flow_indr_block_bind_cb_t * cb,void * cb_priv)4321fac52daSPablo Neira Ayuso int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv)
4331fac52daSPablo Neira Ayuso {
4341fac52daSPablo Neira Ayuso struct flow_indr_dev *indr_dev;
4351fac52daSPablo Neira Ayuso
4361fac52daSPablo Neira Ayuso mutex_lock(&flow_indr_block_lock);
4371fac52daSPablo Neira Ayuso list_for_each_entry(indr_dev, &flow_block_indr_dev_list, list) {
4381fac52daSPablo Neira Ayuso if (indr_dev->cb == cb &&
4391fac52daSPablo Neira Ayuso indr_dev->cb_priv == cb_priv) {
4401fac52daSPablo Neira Ayuso refcount_inc(&indr_dev->refcnt);
4411fac52daSPablo Neira Ayuso mutex_unlock(&flow_indr_block_lock);
4421fac52daSPablo Neira Ayuso return 0;
4431fac52daSPablo Neira Ayuso }
4441fac52daSPablo Neira Ayuso }
4451fac52daSPablo Neira Ayuso
4461fac52daSPablo Neira Ayuso indr_dev = flow_indr_dev_alloc(cb, cb_priv);
4471fac52daSPablo Neira Ayuso if (!indr_dev) {
4481fac52daSPablo Neira Ayuso mutex_unlock(&flow_indr_block_lock);
4491fac52daSPablo Neira Ayuso return -ENOMEM;
4501fac52daSPablo Neira Ayuso }
4511fac52daSPablo Neira Ayuso
4521fac52daSPablo Neira Ayuso list_add(&indr_dev->list, &flow_block_indr_dev_list);
45374fc4f82SEli Cohen existing_qdiscs_register(cb, cb_priv);
4541fac52daSPablo Neira Ayuso mutex_unlock(&flow_indr_block_lock);
4551fac52daSPablo Neira Ayuso
45613926d19SBaowen Zheng tcf_action_reoffload_cb(cb, cb_priv, true);
45713926d19SBaowen Zheng
4581fac52daSPablo Neira Ayuso return 0;
4591fac52daSPablo Neira Ayuso }
4601fac52daSPablo Neira Ayuso EXPORT_SYMBOL(flow_indr_dev_register);
4611fac52daSPablo Neira Ayuso
__flow_block_indr_cleanup(void (* release)(void * cb_priv),void * cb_priv,struct list_head * cleanup_list)462a1db2178Swenxu static void __flow_block_indr_cleanup(void (*release)(void *cb_priv),
463a1db2178Swenxu void *cb_priv,
4641fac52daSPablo Neira Ayuso struct list_head *cleanup_list)
4651fac52daSPablo Neira Ayuso {
4661fac52daSPablo Neira Ayuso struct flow_block_cb *this, *next;
4671fac52daSPablo Neira Ayuso
4681fac52daSPablo Neira Ayuso list_for_each_entry_safe(this, next, &flow_block_indr_list, indr.list) {
469a1db2178Swenxu if (this->release == release &&
4705137d303SChris Mi this->indr.cb_priv == cb_priv)
4711fac52daSPablo Neira Ayuso list_move(&this->indr.list, cleanup_list);
4721fac52daSPablo Neira Ayuso }
4731fac52daSPablo Neira Ayuso }
4741fac52daSPablo Neira Ayuso
flow_block_indr_notify(struct list_head * cleanup_list)4751fac52daSPablo Neira Ayuso static void flow_block_indr_notify(struct list_head *cleanup_list)
4761fac52daSPablo Neira Ayuso {
4771fac52daSPablo Neira Ayuso struct flow_block_cb *this, *next;
4781fac52daSPablo Neira Ayuso
4791fac52daSPablo Neira Ayuso list_for_each_entry_safe(this, next, cleanup_list, indr.list) {
4801fac52daSPablo Neira Ayuso list_del(&this->indr.list);
4811fac52daSPablo Neira Ayuso this->indr.cleanup(this);
4821fac52daSPablo Neira Ayuso }
4831fac52daSPablo Neira Ayuso }
4841fac52daSPablo Neira Ayuso
flow_indr_dev_unregister(flow_indr_block_bind_cb_t * cb,void * cb_priv,void (* release)(void * cb_priv))4851fac52daSPablo Neira Ayuso void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
486a1db2178Swenxu void (*release)(void *cb_priv))
4871fac52daSPablo Neira Ayuso {
4881fac52daSPablo Neira Ayuso struct flow_indr_dev *this, *next, *indr_dev = NULL;
4891fac52daSPablo Neira Ayuso LIST_HEAD(cleanup_list);
4901fac52daSPablo Neira Ayuso
4911fac52daSPablo Neira Ayuso mutex_lock(&flow_indr_block_lock);
4921fac52daSPablo Neira Ayuso list_for_each_entry_safe(this, next, &flow_block_indr_dev_list, list) {
4931fac52daSPablo Neira Ayuso if (this->cb == cb &&
4941fac52daSPablo Neira Ayuso this->cb_priv == cb_priv &&
4951fac52daSPablo Neira Ayuso refcount_dec_and_test(&this->refcnt)) {
4961fac52daSPablo Neira Ayuso indr_dev = this;
4971fac52daSPablo Neira Ayuso list_del(&indr_dev->list);
4981fac52daSPablo Neira Ayuso break;
4991fac52daSPablo Neira Ayuso }
5001fac52daSPablo Neira Ayuso }
5011fac52daSPablo Neira Ayuso
5021fac52daSPablo Neira Ayuso if (!indr_dev) {
5031fac52daSPablo Neira Ayuso mutex_unlock(&flow_indr_block_lock);
5041fac52daSPablo Neira Ayuso return;
5051fac52daSPablo Neira Ayuso }
5061fac52daSPablo Neira Ayuso
507a1db2178Swenxu __flow_block_indr_cleanup(release, cb_priv, &cleanup_list);
5081fac52daSPablo Neira Ayuso mutex_unlock(&flow_indr_block_lock);
5091fac52daSPablo Neira Ayuso
51013926d19SBaowen Zheng tcf_action_reoffload_cb(cb, cb_priv, false);
5111fac52daSPablo Neira Ayuso flow_block_indr_notify(&cleanup_list);
5121fac52daSPablo Neira Ayuso kfree(indr_dev);
5131fac52daSPablo Neira Ayuso }
5141fac52daSPablo Neira Ayuso EXPORT_SYMBOL(flow_indr_dev_unregister);
5151fac52daSPablo Neira Ayuso
flow_block_indr_init(struct flow_block_cb * flow_block,struct flow_block_offload * bo,struct net_device * dev,struct Qdisc * sch,void * data,void * cb_priv,void (* cleanup)(struct flow_block_cb * block_cb))5161fac52daSPablo Neira Ayuso static void flow_block_indr_init(struct flow_block_cb *flow_block,
5171fac52daSPablo Neira Ayuso struct flow_block_offload *bo,
518c40f4e50SPetr Machata struct net_device *dev, struct Qdisc *sch, void *data,
519a1db2178Swenxu void *cb_priv,
5201fac52daSPablo Neira Ayuso void (*cleanup)(struct flow_block_cb *block_cb))
5211fac52daSPablo Neira Ayuso {
5221fac52daSPablo Neira Ayuso flow_block->indr.binder_type = bo->binder_type;
5231fac52daSPablo Neira Ayuso flow_block->indr.data = data;
524a1db2178Swenxu flow_block->indr.cb_priv = cb_priv;
5251fac52daSPablo Neira Ayuso flow_block->indr.dev = dev;
526c40f4e50SPetr Machata flow_block->indr.sch = sch;
5271fac52daSPablo Neira Ayuso flow_block->indr.cleanup = cleanup;
5281fac52daSPablo Neira Ayuso }
5291fac52daSPablo Neira Ayuso
flow_indr_block_cb_alloc(flow_setup_cb_t * cb,void * cb_ident,void * cb_priv,void (* release)(void * cb_priv),struct flow_block_offload * bo,struct net_device * dev,struct Qdisc * sch,void * data,void * indr_cb_priv,void (* cleanup)(struct flow_block_cb * block_cb))53026f2eb27Swenxu struct flow_block_cb *flow_indr_block_cb_alloc(flow_setup_cb_t *cb,
53126f2eb27Swenxu void *cb_ident, void *cb_priv,
53226f2eb27Swenxu void (*release)(void *cb_priv),
53326f2eb27Swenxu struct flow_block_offload *bo,
534c40f4e50SPetr Machata struct net_device *dev,
535c40f4e50SPetr Machata struct Qdisc *sch, void *data,
536a1db2178Swenxu void *indr_cb_priv,
53726f2eb27Swenxu void (*cleanup)(struct flow_block_cb *block_cb))
53826f2eb27Swenxu {
53926f2eb27Swenxu struct flow_block_cb *block_cb;
54026f2eb27Swenxu
54126f2eb27Swenxu block_cb = flow_block_cb_alloc(cb, cb_ident, cb_priv, release);
54226f2eb27Swenxu if (IS_ERR(block_cb))
54326f2eb27Swenxu goto out;
54426f2eb27Swenxu
545c40f4e50SPetr Machata flow_block_indr_init(block_cb, bo, dev, sch, data, indr_cb_priv, cleanup);
54626f2eb27Swenxu list_add(&block_cb->indr.list, &flow_block_indr_list);
54726f2eb27Swenxu
54826f2eb27Swenxu out:
54926f2eb27Swenxu return block_cb;
55026f2eb27Swenxu }
55126f2eb27Swenxu EXPORT_SYMBOL(flow_indr_block_cb_alloc);
55226f2eb27Swenxu
find_indir_dev(void * data)55374fc4f82SEli Cohen static struct flow_indir_dev_info *find_indir_dev(void *data)
55474fc4f82SEli Cohen {
55574fc4f82SEli Cohen struct flow_indir_dev_info *cur;
55674fc4f82SEli Cohen
55774fc4f82SEli Cohen list_for_each_entry(cur, &flow_indir_dev_list, list) {
55874fc4f82SEli Cohen if (cur->data == data)
55974fc4f82SEli Cohen return cur;
56074fc4f82SEli Cohen }
56174fc4f82SEli Cohen return NULL;
56274fc4f82SEli Cohen }
56374fc4f82SEli Cohen
indir_dev_add(void * data,struct net_device * dev,struct Qdisc * sch,enum tc_setup_type type,void (* cleanup)(struct flow_block_cb * block_cb),struct flow_block_offload * bo)56474fc4f82SEli Cohen static int indir_dev_add(void *data, struct net_device *dev, struct Qdisc *sch,
56574fc4f82SEli Cohen enum tc_setup_type type, void (*cleanup)(struct flow_block_cb *block_cb),
56674fc4f82SEli Cohen struct flow_block_offload *bo)
56774fc4f82SEli Cohen {
56874fc4f82SEli Cohen struct flow_indir_dev_info *info;
56974fc4f82SEli Cohen
57074fc4f82SEli Cohen info = find_indir_dev(data);
57174fc4f82SEli Cohen if (info)
57274fc4f82SEli Cohen return -EEXIST;
57374fc4f82SEli Cohen
57474fc4f82SEli Cohen info = kzalloc(sizeof(*info), GFP_KERNEL);
57574fc4f82SEli Cohen if (!info)
57674fc4f82SEli Cohen return -ENOMEM;
57774fc4f82SEli Cohen
57874fc4f82SEli Cohen info->data = data;
57974fc4f82SEli Cohen info->dev = dev;
58074fc4f82SEli Cohen info->sch = sch;
58174fc4f82SEli Cohen info->type = type;
58274fc4f82SEli Cohen info->cleanup = cleanup;
58374fc4f82SEli Cohen info->command = bo->command;
58474fc4f82SEli Cohen info->binder_type = bo->binder_type;
58574fc4f82SEli Cohen info->cb_list = bo->cb_list_head;
58674fc4f82SEli Cohen
58774fc4f82SEli Cohen list_add(&info->list, &flow_indir_dev_list);
58874fc4f82SEli Cohen return 0;
58974fc4f82SEli Cohen }
59074fc4f82SEli Cohen
indir_dev_remove(void * data)59174fc4f82SEli Cohen static int indir_dev_remove(void *data)
59274fc4f82SEli Cohen {
59374fc4f82SEli Cohen struct flow_indir_dev_info *info;
59474fc4f82SEli Cohen
59574fc4f82SEli Cohen info = find_indir_dev(data);
59674fc4f82SEli Cohen if (!info)
59774fc4f82SEli Cohen return -ENOENT;
59874fc4f82SEli Cohen
59974fc4f82SEli Cohen list_del(&info->list);
60074fc4f82SEli Cohen
60174fc4f82SEli Cohen kfree(info);
60274fc4f82SEli Cohen return 0;
60374fc4f82SEli Cohen }
60474fc4f82SEli Cohen
flow_indr_dev_setup_offload(struct net_device * dev,struct Qdisc * sch,enum tc_setup_type type,void * data,struct flow_block_offload * bo,void (* cleanup)(struct flow_block_cb * block_cb))605c40f4e50SPetr Machata int flow_indr_dev_setup_offload(struct net_device *dev, struct Qdisc *sch,
6061fac52daSPablo Neira Ayuso enum tc_setup_type type, void *data,
6071fac52daSPablo Neira Ayuso struct flow_block_offload *bo,
6081fac52daSPablo Neira Ayuso void (*cleanup)(struct flow_block_cb *block_cb))
6091fac52daSPablo Neira Ayuso {
6101fac52daSPablo Neira Ayuso struct flow_indr_dev *this;
6118cbfe939SBaowen Zheng u32 count = 0;
6128cbfe939SBaowen Zheng int err;
6131fac52daSPablo Neira Ayuso
6141fac52daSPablo Neira Ayuso mutex_lock(&flow_indr_block_lock);
6158cbfe939SBaowen Zheng if (bo) {
61674fc4f82SEli Cohen if (bo->command == FLOW_BLOCK_BIND)
61774fc4f82SEli Cohen indir_dev_add(data, dev, sch, type, cleanup, bo);
61874fc4f82SEli Cohen else if (bo->command == FLOW_BLOCK_UNBIND)
61974fc4f82SEli Cohen indir_dev_remove(data);
6208cbfe939SBaowen Zheng }
62174fc4f82SEli Cohen
6228cbfe939SBaowen Zheng list_for_each_entry(this, &flow_block_indr_dev_list, list) {
6238cbfe939SBaowen Zheng err = this->cb(dev, sch, this->cb_priv, type, bo, data, cleanup);
6248cbfe939SBaowen Zheng if (!err)
6258cbfe939SBaowen Zheng count++;
6268cbfe939SBaowen Zheng }
6271fac52daSPablo Neira Ayuso
6281fac52daSPablo Neira Ayuso mutex_unlock(&flow_indr_block_lock);
6291fac52daSPablo Neira Ayuso
6308cbfe939SBaowen Zheng return (bo && list_empty(&bo->cb_list)) ? -EOPNOTSUPP : count;
6311fac52daSPablo Neira Ayuso }
6321fac52daSPablo Neira Ayuso EXPORT_SYMBOL(flow_indr_dev_setup_offload);
6333a41c64dSPablo Neira Ayuso
flow_indr_dev_exists(void)6343a41c64dSPablo Neira Ayuso bool flow_indr_dev_exists(void)
6353a41c64dSPablo Neira Ayuso {
6363a41c64dSPablo Neira Ayuso return !list_empty(&flow_block_indr_dev_list);
6373a41c64dSPablo Neira Ayuso }
6383a41c64dSPablo Neira Ayuso EXPORT_SYMBOL(flow_indr_dev_exists);
639