flow_offload.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #include <linux/kernel.h>
  3. #include <linux/slab.h>
  4. #include <net/act_api.h>
  5. #include <net/flow_offload.h>
  6. #include <linux/rtnetlink.h>
  7. #include <linux/mutex.h>
  8. #include <linux/rhashtable.h>
  9. struct flow_rule *flow_rule_alloc(unsigned int num_actions)
  10. {
  11. struct flow_rule *rule;
  12. int i;
  13. rule = kzalloc_flex(*rule, action.entries, num_actions);
  14. if (!rule)
  15. return NULL;
  16. rule->action.num_entries = num_actions;
  17. /* Pre-fill each action hw_stats with DONT_CARE.
  18. * Caller can override this if it wants stats for a given action.
  19. */
  20. for (i = 0; i < num_actions; i++)
  21. rule->action.entries[i].hw_stats = FLOW_ACTION_HW_STATS_DONT_CARE;
  22. return rule;
  23. }
  24. EXPORT_SYMBOL(flow_rule_alloc);
  25. struct flow_offload_action *offload_action_alloc(unsigned int num_actions)
  26. {
  27. struct flow_offload_action *fl_action;
  28. int i;
  29. fl_action = kzalloc_flex(*fl_action, action.entries, num_actions);
  30. if (!fl_action)
  31. return NULL;
  32. fl_action->action.num_entries = num_actions;
  33. /* Pre-fill each action hw_stats with DONT_CARE.
  34. * Caller can override this if it wants stats for a given action.
  35. */
  36. for (i = 0; i < num_actions; i++)
  37. fl_action->action.entries[i].hw_stats = FLOW_ACTION_HW_STATS_DONT_CARE;
  38. return fl_action;
  39. }
  40. #define FLOW_DISSECTOR_MATCH(__rule, __type, __out) \
  41. const struct flow_match *__m = &(__rule)->match; \
  42. struct flow_dissector *__d = (__m)->dissector; \
  43. \
  44. (__out)->key = skb_flow_dissector_target(__d, __type, (__m)->key); \
  45. (__out)->mask = skb_flow_dissector_target(__d, __type, (__m)->mask); \
  46. void flow_rule_match_meta(const struct flow_rule *rule,
  47. struct flow_match_meta *out)
  48. {
  49. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_META, out);
  50. }
  51. EXPORT_SYMBOL(flow_rule_match_meta);
  52. void flow_rule_match_basic(const struct flow_rule *rule,
  53. struct flow_match_basic *out)
  54. {
  55. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_BASIC, out);
  56. }
  57. EXPORT_SYMBOL(flow_rule_match_basic);
  58. void flow_rule_match_control(const struct flow_rule *rule,
  59. struct flow_match_control *out)
  60. {
  61. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_CONTROL, out);
  62. }
  63. EXPORT_SYMBOL(flow_rule_match_control);
  64. void flow_rule_match_eth_addrs(const struct flow_rule *rule,
  65. struct flow_match_eth_addrs *out)
  66. {
  67. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS, out);
  68. }
  69. EXPORT_SYMBOL(flow_rule_match_eth_addrs);
  70. void flow_rule_match_vlan(const struct flow_rule *rule,
  71. struct flow_match_vlan *out)
  72. {
  73. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_VLAN, out);
  74. }
  75. EXPORT_SYMBOL(flow_rule_match_vlan);
  76. void flow_rule_match_cvlan(const struct flow_rule *rule,
  77. struct flow_match_vlan *out)
  78. {
  79. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_CVLAN, out);
  80. }
  81. EXPORT_SYMBOL(flow_rule_match_cvlan);
  82. void flow_rule_match_arp(const struct flow_rule *rule,
  83. struct flow_match_arp *out)
  84. {
  85. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ARP, out);
  86. }
  87. EXPORT_SYMBOL(flow_rule_match_arp);
  88. void flow_rule_match_ipv4_addrs(const struct flow_rule *rule,
  89. struct flow_match_ipv4_addrs *out)
  90. {
  91. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS, out);
  92. }
  93. EXPORT_SYMBOL(flow_rule_match_ipv4_addrs);
  94. void flow_rule_match_ipv6_addrs(const struct flow_rule *rule,
  95. struct flow_match_ipv6_addrs *out)
  96. {
  97. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS, out);
  98. }
  99. EXPORT_SYMBOL(flow_rule_match_ipv6_addrs);
  100. void flow_rule_match_ip(const struct flow_rule *rule,
  101. struct flow_match_ip *out)
  102. {
  103. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IP, out);
  104. }
  105. EXPORT_SYMBOL(flow_rule_match_ip);
  106. void flow_rule_match_ports(const struct flow_rule *rule,
  107. struct flow_match_ports *out)
  108. {
  109. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_PORTS, out);
  110. }
  111. EXPORT_SYMBOL(flow_rule_match_ports);
  112. void flow_rule_match_ports_range(const struct flow_rule *rule,
  113. struct flow_match_ports_range *out)
  114. {
  115. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_PORTS_RANGE, out);
  116. }
  117. EXPORT_SYMBOL(flow_rule_match_ports_range);
  118. void flow_rule_match_tcp(const struct flow_rule *rule,
  119. struct flow_match_tcp *out)
  120. {
  121. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_TCP, out);
  122. }
  123. EXPORT_SYMBOL(flow_rule_match_tcp);
  124. void flow_rule_match_ipsec(const struct flow_rule *rule,
  125. struct flow_match_ipsec *out)
  126. {
  127. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPSEC, out);
  128. }
  129. EXPORT_SYMBOL(flow_rule_match_ipsec);
  130. void flow_rule_match_icmp(const struct flow_rule *rule,
  131. struct flow_match_icmp *out)
  132. {
  133. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ICMP, out);
  134. }
  135. EXPORT_SYMBOL(flow_rule_match_icmp);
  136. void flow_rule_match_mpls(const struct flow_rule *rule,
  137. struct flow_match_mpls *out)
  138. {
  139. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_MPLS, out);
  140. }
  141. EXPORT_SYMBOL(flow_rule_match_mpls);
  142. void flow_rule_match_enc_control(const struct flow_rule *rule,
  143. struct flow_match_control *out)
  144. {
  145. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_CONTROL, out);
  146. }
  147. EXPORT_SYMBOL(flow_rule_match_enc_control);
  148. void flow_rule_match_enc_ipv4_addrs(const struct flow_rule *rule,
  149. struct flow_match_ipv4_addrs *out)
  150. {
  151. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, out);
  152. }
  153. EXPORT_SYMBOL(flow_rule_match_enc_ipv4_addrs);
  154. void flow_rule_match_enc_ipv6_addrs(const struct flow_rule *rule,
  155. struct flow_match_ipv6_addrs *out)
  156. {
  157. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, out);
  158. }
  159. EXPORT_SYMBOL(flow_rule_match_enc_ipv6_addrs);
  160. void flow_rule_match_enc_ip(const struct flow_rule *rule,
  161. struct flow_match_ip *out)
  162. {
  163. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IP, out);
  164. }
  165. EXPORT_SYMBOL(flow_rule_match_enc_ip);
  166. void flow_rule_match_enc_ports(const struct flow_rule *rule,
  167. struct flow_match_ports *out)
  168. {
  169. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_PORTS, out);
  170. }
  171. EXPORT_SYMBOL(flow_rule_match_enc_ports);
  172. void flow_rule_match_enc_keyid(const struct flow_rule *rule,
  173. struct flow_match_enc_keyid *out)
  174. {
  175. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_KEYID, out);
  176. }
  177. EXPORT_SYMBOL(flow_rule_match_enc_keyid);
  178. void flow_rule_match_enc_opts(const struct flow_rule *rule,
  179. struct flow_match_enc_opts *out)
  180. {
  181. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_OPTS, out);
  182. }
  183. EXPORT_SYMBOL(flow_rule_match_enc_opts);
  184. struct flow_action_cookie *flow_action_cookie_create(void *data,
  185. unsigned int len,
  186. gfp_t gfp)
  187. {
  188. struct flow_action_cookie *cookie;
  189. cookie = kmalloc(sizeof(*cookie) + len, gfp);
  190. if (!cookie)
  191. return NULL;
  192. cookie->cookie_len = len;
  193. memcpy(cookie->cookie, data, len);
  194. return cookie;
  195. }
  196. EXPORT_SYMBOL(flow_action_cookie_create);
  197. void flow_action_cookie_destroy(struct flow_action_cookie *cookie)
  198. {
  199. kfree(cookie);
  200. }
  201. EXPORT_SYMBOL(flow_action_cookie_destroy);
  202. void flow_rule_match_ct(const struct flow_rule *rule,
  203. struct flow_match_ct *out)
  204. {
  205. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_CT, out);
  206. }
  207. EXPORT_SYMBOL(flow_rule_match_ct);
  208. void flow_rule_match_pppoe(const struct flow_rule *rule,
  209. struct flow_match_pppoe *out)
  210. {
  211. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_PPPOE, out);
  212. }
  213. EXPORT_SYMBOL(flow_rule_match_pppoe);
  214. void flow_rule_match_l2tpv3(const struct flow_rule *rule,
  215. struct flow_match_l2tpv3 *out)
  216. {
  217. FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_L2TPV3, out);
  218. }
  219. EXPORT_SYMBOL(flow_rule_match_l2tpv3);
  220. struct flow_block_cb *flow_block_cb_alloc(flow_setup_cb_t *cb,
  221. void *cb_ident, void *cb_priv,
  222. void (*release)(void *cb_priv))
  223. {
  224. struct flow_block_cb *block_cb;
  225. block_cb = kzalloc_obj(*block_cb);
  226. if (!block_cb)
  227. return ERR_PTR(-ENOMEM);
  228. block_cb->cb = cb;
  229. block_cb->cb_ident = cb_ident;
  230. block_cb->cb_priv = cb_priv;
  231. block_cb->release = release;
  232. return block_cb;
  233. }
  234. EXPORT_SYMBOL(flow_block_cb_alloc);
  235. void flow_block_cb_free(struct flow_block_cb *block_cb)
  236. {
  237. if (block_cb->release)
  238. block_cb->release(block_cb->cb_priv);
  239. kfree(block_cb);
  240. }
  241. EXPORT_SYMBOL(flow_block_cb_free);
  242. struct flow_block_cb *flow_block_cb_lookup(struct flow_block *block,
  243. flow_setup_cb_t *cb, void *cb_ident)
  244. {
  245. struct flow_block_cb *block_cb;
  246. list_for_each_entry(block_cb, &block->cb_list, list) {
  247. if (block_cb->cb == cb &&
  248. block_cb->cb_ident == cb_ident)
  249. return block_cb;
  250. }
  251. return NULL;
  252. }
  253. EXPORT_SYMBOL(flow_block_cb_lookup);
  254. void *flow_block_cb_priv(struct flow_block_cb *block_cb)
  255. {
  256. return block_cb->cb_priv;
  257. }
  258. EXPORT_SYMBOL(flow_block_cb_priv);
  259. void flow_block_cb_incref(struct flow_block_cb *block_cb)
  260. {
  261. block_cb->refcnt++;
  262. }
  263. EXPORT_SYMBOL(flow_block_cb_incref);
  264. unsigned int flow_block_cb_decref(struct flow_block_cb *block_cb)
  265. {
  266. return --block_cb->refcnt;
  267. }
  268. EXPORT_SYMBOL(flow_block_cb_decref);
  269. bool flow_block_cb_is_busy(flow_setup_cb_t *cb, void *cb_ident,
  270. struct list_head *driver_block_list)
  271. {
  272. struct flow_block_cb *block_cb;
  273. list_for_each_entry(block_cb, driver_block_list, driver_list) {
  274. if (block_cb->cb == cb &&
  275. block_cb->cb_ident == cb_ident)
  276. return true;
  277. }
  278. return false;
  279. }
  280. EXPORT_SYMBOL(flow_block_cb_is_busy);
  281. int flow_block_cb_setup_simple(struct flow_block_offload *f,
  282. struct list_head *driver_block_list,
  283. flow_setup_cb_t *cb,
  284. void *cb_ident, void *cb_priv,
  285. bool ingress_only)
  286. {
  287. struct flow_block_cb *block_cb;
  288. if (ingress_only &&
  289. f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
  290. return -EOPNOTSUPP;
  291. f->driver_block_list = driver_block_list;
  292. switch (f->command) {
  293. case FLOW_BLOCK_BIND:
  294. if (flow_block_cb_is_busy(cb, cb_ident, driver_block_list))
  295. return -EBUSY;
  296. block_cb = flow_block_cb_alloc(cb, cb_ident, cb_priv, NULL);
  297. if (IS_ERR(block_cb))
  298. return PTR_ERR(block_cb);
  299. flow_block_cb_add(block_cb, f);
  300. list_add_tail(&block_cb->driver_list, driver_block_list);
  301. return 0;
  302. case FLOW_BLOCK_UNBIND:
  303. block_cb = flow_block_cb_lookup(f->block, cb, cb_ident);
  304. if (!block_cb)
  305. return -ENOENT;
  306. flow_block_cb_remove(block_cb, f);
  307. list_del(&block_cb->driver_list);
  308. return 0;
  309. default:
  310. return -EOPNOTSUPP;
  311. }
  312. }
  313. EXPORT_SYMBOL(flow_block_cb_setup_simple);
  314. static DEFINE_MUTEX(flow_indr_block_lock);
  315. static LIST_HEAD(flow_block_indr_list);
  316. static LIST_HEAD(flow_block_indr_dev_list);
  317. static LIST_HEAD(flow_indir_dev_list);
  318. struct flow_indr_dev {
  319. struct list_head list;
  320. flow_indr_block_bind_cb_t *cb;
  321. void *cb_priv;
  322. refcount_t refcnt;
  323. };
  324. static struct flow_indr_dev *flow_indr_dev_alloc(flow_indr_block_bind_cb_t *cb,
  325. void *cb_priv)
  326. {
  327. struct flow_indr_dev *indr_dev;
  328. indr_dev = kmalloc_obj(*indr_dev);
  329. if (!indr_dev)
  330. return NULL;
  331. indr_dev->cb = cb;
  332. indr_dev->cb_priv = cb_priv;
  333. refcount_set(&indr_dev->refcnt, 1);
  334. return indr_dev;
  335. }
  336. struct flow_indir_dev_info {
  337. void *data;
  338. struct net_device *dev;
  339. struct Qdisc *sch;
  340. enum tc_setup_type type;
  341. void (*cleanup)(struct flow_block_cb *block_cb);
  342. struct list_head list;
  343. enum flow_block_command command;
  344. enum flow_block_binder_type binder_type;
  345. struct list_head *cb_list;
  346. };
  347. static void existing_qdiscs_register(flow_indr_block_bind_cb_t *cb, void *cb_priv)
  348. {
  349. struct flow_block_offload bo;
  350. struct flow_indir_dev_info *cur;
  351. list_for_each_entry(cur, &flow_indir_dev_list, list) {
  352. memset(&bo, 0, sizeof(bo));
  353. bo.command = cur->command;
  354. bo.binder_type = cur->binder_type;
  355. INIT_LIST_HEAD(&bo.cb_list);
  356. cb(cur->dev, cur->sch, cb_priv, cur->type, &bo, cur->data, cur->cleanup);
  357. list_splice(&bo.cb_list, cur->cb_list);
  358. }
  359. }
  360. int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv)
  361. {
  362. struct flow_indr_dev *indr_dev;
  363. mutex_lock(&flow_indr_block_lock);
  364. list_for_each_entry(indr_dev, &flow_block_indr_dev_list, list) {
  365. if (indr_dev->cb == cb &&
  366. indr_dev->cb_priv == cb_priv) {
  367. refcount_inc(&indr_dev->refcnt);
  368. mutex_unlock(&flow_indr_block_lock);
  369. return 0;
  370. }
  371. }
  372. indr_dev = flow_indr_dev_alloc(cb, cb_priv);
  373. if (!indr_dev) {
  374. mutex_unlock(&flow_indr_block_lock);
  375. return -ENOMEM;
  376. }
  377. list_add(&indr_dev->list, &flow_block_indr_dev_list);
  378. existing_qdiscs_register(cb, cb_priv);
  379. mutex_unlock(&flow_indr_block_lock);
  380. tcf_action_reoffload_cb(cb, cb_priv, true);
  381. return 0;
  382. }
  383. EXPORT_SYMBOL(flow_indr_dev_register);
  384. static void __flow_block_indr_cleanup(void (*release)(void *cb_priv),
  385. void *cb_priv,
  386. struct list_head *cleanup_list)
  387. {
  388. struct flow_block_cb *this, *next;
  389. list_for_each_entry_safe(this, next, &flow_block_indr_list, indr.list) {
  390. if (this->release == release &&
  391. this->indr.cb_priv == cb_priv)
  392. list_move(&this->indr.list, cleanup_list);
  393. }
  394. }
  395. static void flow_block_indr_notify(struct list_head *cleanup_list)
  396. {
  397. struct flow_block_cb *this, *next;
  398. list_for_each_entry_safe(this, next, cleanup_list, indr.list) {
  399. list_del(&this->indr.list);
  400. this->indr.cleanup(this);
  401. }
  402. }
  403. void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
  404. void (*release)(void *cb_priv))
  405. {
  406. struct flow_indr_dev *this, *next, *indr_dev = NULL;
  407. LIST_HEAD(cleanup_list);
  408. mutex_lock(&flow_indr_block_lock);
  409. list_for_each_entry_safe(this, next, &flow_block_indr_dev_list, list) {
  410. if (this->cb == cb &&
  411. this->cb_priv == cb_priv &&
  412. refcount_dec_and_test(&this->refcnt)) {
  413. indr_dev = this;
  414. list_del(&indr_dev->list);
  415. break;
  416. }
  417. }
  418. if (!indr_dev) {
  419. mutex_unlock(&flow_indr_block_lock);
  420. return;
  421. }
  422. __flow_block_indr_cleanup(release, cb_priv, &cleanup_list);
  423. mutex_unlock(&flow_indr_block_lock);
  424. tcf_action_reoffload_cb(cb, cb_priv, false);
  425. flow_block_indr_notify(&cleanup_list);
  426. kfree(indr_dev);
  427. }
  428. EXPORT_SYMBOL(flow_indr_dev_unregister);
  429. static void flow_block_indr_init(struct flow_block_cb *flow_block,
  430. struct flow_block_offload *bo,
  431. struct net_device *dev, struct Qdisc *sch, void *data,
  432. void *cb_priv,
  433. void (*cleanup)(struct flow_block_cb *block_cb))
  434. {
  435. flow_block->indr.binder_type = bo->binder_type;
  436. flow_block->indr.data = data;
  437. flow_block->indr.cb_priv = cb_priv;
  438. flow_block->indr.dev = dev;
  439. flow_block->indr.sch = sch;
  440. flow_block->indr.cleanup = cleanup;
  441. }
  442. struct flow_block_cb *flow_indr_block_cb_alloc(flow_setup_cb_t *cb,
  443. void *cb_ident, void *cb_priv,
  444. void (*release)(void *cb_priv),
  445. struct flow_block_offload *bo,
  446. struct net_device *dev,
  447. struct Qdisc *sch, void *data,
  448. void *indr_cb_priv,
  449. void (*cleanup)(struct flow_block_cb *block_cb))
  450. {
  451. struct flow_block_cb *block_cb;
  452. block_cb = flow_block_cb_alloc(cb, cb_ident, cb_priv, release);
  453. if (IS_ERR(block_cb))
  454. goto out;
  455. flow_block_indr_init(block_cb, bo, dev, sch, data, indr_cb_priv, cleanup);
  456. list_add(&block_cb->indr.list, &flow_block_indr_list);
  457. out:
  458. return block_cb;
  459. }
  460. EXPORT_SYMBOL(flow_indr_block_cb_alloc);
  461. static struct flow_indir_dev_info *find_indir_dev(void *data)
  462. {
  463. struct flow_indir_dev_info *cur;
  464. list_for_each_entry(cur, &flow_indir_dev_list, list) {
  465. if (cur->data == data)
  466. return cur;
  467. }
  468. return NULL;
  469. }
  470. static int indir_dev_add(void *data, struct net_device *dev, struct Qdisc *sch,
  471. enum tc_setup_type type, void (*cleanup)(struct flow_block_cb *block_cb),
  472. struct flow_block_offload *bo)
  473. {
  474. struct flow_indir_dev_info *info;
  475. info = find_indir_dev(data);
  476. if (info)
  477. return -EEXIST;
  478. info = kzalloc_obj(*info);
  479. if (!info)
  480. return -ENOMEM;
  481. info->data = data;
  482. info->dev = dev;
  483. info->sch = sch;
  484. info->type = type;
  485. info->cleanup = cleanup;
  486. info->command = bo->command;
  487. info->binder_type = bo->binder_type;
  488. info->cb_list = bo->cb_list_head;
  489. list_add(&info->list, &flow_indir_dev_list);
  490. return 0;
  491. }
  492. static int indir_dev_remove(void *data)
  493. {
  494. struct flow_indir_dev_info *info;
  495. info = find_indir_dev(data);
  496. if (!info)
  497. return -ENOENT;
  498. list_del(&info->list);
  499. kfree(info);
  500. return 0;
  501. }
  502. int flow_indr_dev_setup_offload(struct net_device *dev, struct Qdisc *sch,
  503. enum tc_setup_type type, void *data,
  504. struct flow_block_offload *bo,
  505. void (*cleanup)(struct flow_block_cb *block_cb))
  506. {
  507. struct flow_indr_dev *this;
  508. u32 count = 0;
  509. int err;
  510. mutex_lock(&flow_indr_block_lock);
  511. if (bo) {
  512. if (bo->command == FLOW_BLOCK_BIND)
  513. indir_dev_add(data, dev, sch, type, cleanup, bo);
  514. else if (bo->command == FLOW_BLOCK_UNBIND)
  515. indir_dev_remove(data);
  516. }
  517. list_for_each_entry(this, &flow_block_indr_dev_list, list) {
  518. err = this->cb(dev, sch, this->cb_priv, type, bo, data, cleanup);
  519. if (!err)
  520. count++;
  521. }
  522. mutex_unlock(&flow_indr_block_lock);
  523. return (bo && list_empty(&bo->cb_list)) ? -EOPNOTSUPP : count;
  524. }
  525. EXPORT_SYMBOL(flow_indr_dev_setup_offload);
  526. bool flow_indr_dev_exists(void)
  527. {
  528. return !list_empty(&flow_block_indr_dev_list);
  529. }
  530. EXPORT_SYMBOL(flow_indr_dev_exists);