act_skbedit.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2008, Intel Corporation.
  4. *
  5. * Author: Alexander Duyck <alexander.h.duyck@intel.com>
  6. */
  7. #include <linux/module.h>
  8. #include <linux/init.h>
  9. #include <linux/kernel.h>
  10. #include <linux/skbuff.h>
  11. #include <linux/rtnetlink.h>
  12. #include <net/netlink.h>
  13. #include <net/pkt_sched.h>
  14. #include <net/ip.h>
  15. #include <net/ipv6.h>
  16. #include <net/dsfield.h>
  17. #include <net/pkt_cls.h>
  18. #include <net/tc_wrapper.h>
  19. #include <linux/tc_act/tc_skbedit.h>
  20. #include <net/tc_act/tc_skbedit.h>
  21. static struct tc_action_ops act_skbedit_ops;
  22. static u16 tcf_skbedit_hash(struct tcf_skbedit_params *params,
  23. struct sk_buff *skb)
  24. {
  25. u16 queue_mapping = params->queue_mapping;
  26. if (params->flags & SKBEDIT_F_TXQ_SKBHASH) {
  27. u32 hash = skb_get_hash(skb);
  28. queue_mapping += hash % params->mapping_mod;
  29. }
  30. return netdev_cap_txqueue(skb->dev, queue_mapping);
  31. }
  32. TC_INDIRECT_SCOPE int tcf_skbedit_act(struct sk_buff *skb,
  33. const struct tc_action *a,
  34. struct tcf_result *res)
  35. {
  36. struct tcf_skbedit *d = to_skbedit(a);
  37. struct tcf_skbedit_params *params;
  38. tcf_lastuse_update(&d->tcf_tm);
  39. bstats_update(this_cpu_ptr(d->common.cpu_bstats), skb);
  40. params = rcu_dereference_bh(d->params);
  41. if (params->flags & SKBEDIT_F_PRIORITY)
  42. skb->priority = params->priority;
  43. if (params->flags & SKBEDIT_F_INHERITDSFIELD) {
  44. int wlen = skb_network_offset(skb);
  45. switch (skb_protocol(skb, true)) {
  46. case htons(ETH_P_IP):
  47. wlen += sizeof(struct iphdr);
  48. if (!pskb_may_pull(skb, wlen))
  49. goto err;
  50. skb->priority = ipv4_get_dsfield(ip_hdr(skb)) >> 2;
  51. break;
  52. case htons(ETH_P_IPV6):
  53. wlen += sizeof(struct ipv6hdr);
  54. if (!pskb_may_pull(skb, wlen))
  55. goto err;
  56. skb->priority = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2;
  57. break;
  58. }
  59. }
  60. if (params->flags & SKBEDIT_F_QUEUE_MAPPING &&
  61. skb->dev->real_num_tx_queues > params->queue_mapping) {
  62. #ifdef CONFIG_NET_EGRESS
  63. netdev_xmit_skip_txqueue(true);
  64. #endif
  65. skb_set_queue_mapping(skb, tcf_skbedit_hash(params, skb));
  66. }
  67. if (params->flags & SKBEDIT_F_MARK) {
  68. skb->mark &= ~params->mask;
  69. skb->mark |= params->mark & params->mask;
  70. }
  71. if (params->flags & SKBEDIT_F_PTYPE)
  72. skb->pkt_type = params->ptype;
  73. return params->action;
  74. err:
  75. qstats_drop_inc(this_cpu_ptr(d->common.cpu_qstats));
  76. return TC_ACT_SHOT;
  77. }
  78. static void tcf_skbedit_stats_update(struct tc_action *a, u64 bytes,
  79. u64 packets, u64 drops,
  80. u64 lastuse, bool hw)
  81. {
  82. struct tcf_skbedit *d = to_skbedit(a);
  83. struct tcf_t *tm = &d->tcf_tm;
  84. tcf_action_update_stats(a, bytes, packets, drops, hw);
  85. tm->lastuse = max_t(u64, tm->lastuse, lastuse);
  86. }
  87. static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
  88. [TCA_SKBEDIT_PARMS] = { .len = sizeof(struct tc_skbedit) },
  89. [TCA_SKBEDIT_PRIORITY] = { .len = sizeof(u32) },
  90. [TCA_SKBEDIT_QUEUE_MAPPING] = { .len = sizeof(u16) },
  91. [TCA_SKBEDIT_MARK] = { .len = sizeof(u32) },
  92. [TCA_SKBEDIT_PTYPE] = { .len = sizeof(u16) },
  93. [TCA_SKBEDIT_MASK] = { .len = sizeof(u32) },
  94. [TCA_SKBEDIT_FLAGS] = { .len = sizeof(u64) },
  95. [TCA_SKBEDIT_QUEUE_MAPPING_MAX] = { .len = sizeof(u16) },
  96. };
  97. static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
  98. struct nlattr *est, struct tc_action **a,
  99. struct tcf_proto *tp, u32 act_flags,
  100. struct netlink_ext_ack *extack)
  101. {
  102. struct tc_action_net *tn = net_generic(net, act_skbedit_ops.net_id);
  103. bool bind = act_flags & TCA_ACT_FLAGS_BIND;
  104. struct tcf_skbedit_params *params_new;
  105. struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
  106. struct tcf_chain *goto_ch = NULL;
  107. struct tc_skbedit *parm;
  108. struct tcf_skbedit *d;
  109. u32 flags = 0, *priority = NULL, *mark = NULL, *mask = NULL;
  110. u16 *queue_mapping = NULL, *ptype = NULL;
  111. u32 mapping_mod = 1;
  112. bool exists = false;
  113. int ret = 0, err;
  114. u32 index;
  115. if (nla == NULL)
  116. return -EINVAL;
  117. err = nla_parse_nested_deprecated(tb, TCA_SKBEDIT_MAX, nla,
  118. skbedit_policy, NULL);
  119. if (err < 0)
  120. return err;
  121. if (tb[TCA_SKBEDIT_PARMS] == NULL)
  122. return -EINVAL;
  123. if (tb[TCA_SKBEDIT_PRIORITY] != NULL) {
  124. flags |= SKBEDIT_F_PRIORITY;
  125. priority = nla_data(tb[TCA_SKBEDIT_PRIORITY]);
  126. }
  127. if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) {
  128. if (is_tcf_skbedit_ingress(act_flags) &&
  129. !(act_flags & TCA_ACT_FLAGS_SKIP_SW)) {
  130. NL_SET_ERR_MSG_MOD(extack, "\"queue_mapping\" option on receive side is hardware only, use skip_sw");
  131. return -EOPNOTSUPP;
  132. }
  133. flags |= SKBEDIT_F_QUEUE_MAPPING;
  134. queue_mapping = nla_data(tb[TCA_SKBEDIT_QUEUE_MAPPING]);
  135. }
  136. if (tb[TCA_SKBEDIT_PTYPE] != NULL) {
  137. ptype = nla_data(tb[TCA_SKBEDIT_PTYPE]);
  138. if (!skb_pkt_type_ok(*ptype))
  139. return -EINVAL;
  140. flags |= SKBEDIT_F_PTYPE;
  141. }
  142. if (tb[TCA_SKBEDIT_MARK] != NULL) {
  143. flags |= SKBEDIT_F_MARK;
  144. mark = nla_data(tb[TCA_SKBEDIT_MARK]);
  145. }
  146. if (tb[TCA_SKBEDIT_MASK] != NULL) {
  147. flags |= SKBEDIT_F_MASK;
  148. mask = nla_data(tb[TCA_SKBEDIT_MASK]);
  149. }
  150. if (tb[TCA_SKBEDIT_FLAGS] != NULL) {
  151. u64 *pure_flags = nla_data(tb[TCA_SKBEDIT_FLAGS]);
  152. if (*pure_flags & SKBEDIT_F_TXQ_SKBHASH) {
  153. u16 *queue_mapping_max;
  154. if (!tb[TCA_SKBEDIT_QUEUE_MAPPING] ||
  155. !tb[TCA_SKBEDIT_QUEUE_MAPPING_MAX]) {
  156. NL_SET_ERR_MSG_MOD(extack, "Missing required range of queue_mapping.");
  157. return -EINVAL;
  158. }
  159. queue_mapping_max =
  160. nla_data(tb[TCA_SKBEDIT_QUEUE_MAPPING_MAX]);
  161. if (*queue_mapping_max < *queue_mapping) {
  162. NL_SET_ERR_MSG_MOD(extack, "The range of queue_mapping is invalid, max < min.");
  163. return -EINVAL;
  164. }
  165. mapping_mod = *queue_mapping_max - *queue_mapping + 1;
  166. if (mapping_mod > U16_MAX) {
  167. NL_SET_ERR_MSG_MOD(extack, "The range of queue_mapping is invalid.");
  168. return -EINVAL;
  169. }
  170. flags |= SKBEDIT_F_TXQ_SKBHASH;
  171. }
  172. if (*pure_flags & SKBEDIT_F_INHERITDSFIELD)
  173. flags |= SKBEDIT_F_INHERITDSFIELD;
  174. }
  175. parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
  176. index = parm->index;
  177. err = tcf_idr_check_alloc(tn, &index, a, bind);
  178. if (err < 0)
  179. return err;
  180. exists = err;
  181. if (exists && bind)
  182. return ACT_P_BOUND;
  183. if (!flags) {
  184. if (exists)
  185. tcf_idr_release(*a, bind);
  186. else
  187. tcf_idr_cleanup(tn, index);
  188. return -EINVAL;
  189. }
  190. if (!exists) {
  191. ret = tcf_idr_create(tn, index, est, a,
  192. &act_skbedit_ops, bind, true, act_flags);
  193. if (ret) {
  194. tcf_idr_cleanup(tn, index);
  195. return ret;
  196. }
  197. d = to_skbedit(*a);
  198. ret = ACT_P_CREATED;
  199. } else {
  200. d = to_skbedit(*a);
  201. if (!(act_flags & TCA_ACT_FLAGS_REPLACE)) {
  202. tcf_idr_release(*a, bind);
  203. return -EEXIST;
  204. }
  205. }
  206. err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
  207. if (err < 0)
  208. goto release_idr;
  209. params_new = kzalloc_obj(*params_new);
  210. if (unlikely(!params_new)) {
  211. err = -ENOMEM;
  212. goto put_chain;
  213. }
  214. params_new->flags = flags;
  215. if (flags & SKBEDIT_F_PRIORITY)
  216. params_new->priority = *priority;
  217. if (flags & SKBEDIT_F_QUEUE_MAPPING) {
  218. params_new->queue_mapping = *queue_mapping;
  219. params_new->mapping_mod = mapping_mod;
  220. }
  221. if (flags & SKBEDIT_F_MARK)
  222. params_new->mark = *mark;
  223. if (flags & SKBEDIT_F_PTYPE)
  224. params_new->ptype = *ptype;
  225. /* default behaviour is to use all the bits */
  226. params_new->mask = 0xffffffff;
  227. if (flags & SKBEDIT_F_MASK)
  228. params_new->mask = *mask;
  229. params_new->action = parm->action;
  230. spin_lock_bh(&d->tcf_lock);
  231. goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
  232. params_new = rcu_replace_pointer(d->params, params_new,
  233. lockdep_is_held(&d->tcf_lock));
  234. spin_unlock_bh(&d->tcf_lock);
  235. if (params_new)
  236. kfree_rcu(params_new, rcu);
  237. if (goto_ch)
  238. tcf_chain_put_by_act(goto_ch);
  239. return ret;
  240. put_chain:
  241. if (goto_ch)
  242. tcf_chain_put_by_act(goto_ch);
  243. release_idr:
  244. tcf_idr_release(*a, bind);
  245. return err;
  246. }
  247. static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
  248. int bind, int ref)
  249. {
  250. const struct tcf_skbedit *d = to_skbedit(a);
  251. unsigned char *b = skb_tail_pointer(skb);
  252. const struct tcf_skbedit_params *params;
  253. struct tc_skbedit opt = {
  254. .index = d->tcf_index,
  255. .refcnt = refcount_read(&d->tcf_refcnt) - ref,
  256. .bindcnt = atomic_read(&d->tcf_bindcnt) - bind,
  257. };
  258. u64 pure_flags = 0;
  259. struct tcf_t t;
  260. rcu_read_lock();
  261. params = rcu_dereference(d->params);
  262. opt.action = params->action;
  263. if (nla_put(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt))
  264. goto nla_put_failure;
  265. if ((params->flags & SKBEDIT_F_PRIORITY) &&
  266. nla_put_u32(skb, TCA_SKBEDIT_PRIORITY, params->priority))
  267. goto nla_put_failure;
  268. if ((params->flags & SKBEDIT_F_QUEUE_MAPPING) &&
  269. nla_put_u16(skb, TCA_SKBEDIT_QUEUE_MAPPING, params->queue_mapping))
  270. goto nla_put_failure;
  271. if ((params->flags & SKBEDIT_F_MARK) &&
  272. nla_put_u32(skb, TCA_SKBEDIT_MARK, params->mark))
  273. goto nla_put_failure;
  274. if ((params->flags & SKBEDIT_F_PTYPE) &&
  275. nla_put_u16(skb, TCA_SKBEDIT_PTYPE, params->ptype))
  276. goto nla_put_failure;
  277. if ((params->flags & SKBEDIT_F_MASK) &&
  278. nla_put_u32(skb, TCA_SKBEDIT_MASK, params->mask))
  279. goto nla_put_failure;
  280. if (params->flags & SKBEDIT_F_INHERITDSFIELD)
  281. pure_flags |= SKBEDIT_F_INHERITDSFIELD;
  282. if (params->flags & SKBEDIT_F_TXQ_SKBHASH) {
  283. if (nla_put_u16(skb, TCA_SKBEDIT_QUEUE_MAPPING_MAX,
  284. params->queue_mapping + params->mapping_mod - 1))
  285. goto nla_put_failure;
  286. pure_flags |= SKBEDIT_F_TXQ_SKBHASH;
  287. }
  288. if (pure_flags != 0 &&
  289. nla_put(skb, TCA_SKBEDIT_FLAGS, sizeof(pure_flags), &pure_flags))
  290. goto nla_put_failure;
  291. tcf_tm_dump(&t, &d->tcf_tm);
  292. if (nla_put_64bit(skb, TCA_SKBEDIT_TM, sizeof(t), &t, TCA_SKBEDIT_PAD))
  293. goto nla_put_failure;
  294. rcu_read_unlock();
  295. return skb->len;
  296. nla_put_failure:
  297. rcu_read_unlock();
  298. nlmsg_trim(skb, b);
  299. return -1;
  300. }
  301. static void tcf_skbedit_cleanup(struct tc_action *a)
  302. {
  303. struct tcf_skbedit *d = to_skbedit(a);
  304. struct tcf_skbedit_params *params;
  305. params = rcu_dereference_protected(d->params, 1);
  306. if (params)
  307. kfree_rcu(params, rcu);
  308. }
  309. static size_t tcf_skbedit_get_fill_size(const struct tc_action *act)
  310. {
  311. return nla_total_size(sizeof(struct tc_skbedit))
  312. + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_PRIORITY */
  313. + nla_total_size(sizeof(u16)) /* TCA_SKBEDIT_QUEUE_MAPPING */
  314. + nla_total_size(sizeof(u16)) /* TCA_SKBEDIT_QUEUE_MAPPING_MAX */
  315. + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_MARK */
  316. + nla_total_size(sizeof(u16)) /* TCA_SKBEDIT_PTYPE */
  317. + nla_total_size(sizeof(u32)) /* TCA_SKBEDIT_MASK */
  318. + nla_total_size_64bit(sizeof(u64)); /* TCA_SKBEDIT_FLAGS */
  319. }
  320. static int tcf_skbedit_offload_act_setup(struct tc_action *act, void *entry_data,
  321. u32 *index_inc, bool bind,
  322. struct netlink_ext_ack *extack)
  323. {
  324. if (bind) {
  325. struct flow_action_entry *entry = entry_data;
  326. if (is_tcf_skbedit_mark(act)) {
  327. entry->id = FLOW_ACTION_MARK;
  328. entry->mark = tcf_skbedit_mark(act);
  329. } else if (is_tcf_skbedit_ptype(act)) {
  330. entry->id = FLOW_ACTION_PTYPE;
  331. entry->ptype = tcf_skbedit_ptype(act);
  332. } else if (is_tcf_skbedit_priority(act)) {
  333. entry->id = FLOW_ACTION_PRIORITY;
  334. entry->priority = tcf_skbedit_priority(act);
  335. } else if (is_tcf_skbedit_tx_queue_mapping(act)) {
  336. NL_SET_ERR_MSG_MOD(extack, "Offload not supported when \"queue_mapping\" option is used on transmit side");
  337. return -EOPNOTSUPP;
  338. } else if (is_tcf_skbedit_rx_queue_mapping(act)) {
  339. entry->id = FLOW_ACTION_RX_QUEUE_MAPPING;
  340. entry->rx_queue = tcf_skbedit_rx_queue_mapping(act);
  341. } else if (is_tcf_skbedit_inheritdsfield(act)) {
  342. NL_SET_ERR_MSG_MOD(extack, "Offload not supported when \"inheritdsfield\" option is used");
  343. return -EOPNOTSUPP;
  344. } else {
  345. NL_SET_ERR_MSG_MOD(extack, "Unsupported skbedit option offload");
  346. return -EOPNOTSUPP;
  347. }
  348. *index_inc = 1;
  349. } else {
  350. struct flow_offload_action *fl_action = entry_data;
  351. if (is_tcf_skbedit_mark(act))
  352. fl_action->id = FLOW_ACTION_MARK;
  353. else if (is_tcf_skbedit_ptype(act))
  354. fl_action->id = FLOW_ACTION_PTYPE;
  355. else if (is_tcf_skbedit_priority(act))
  356. fl_action->id = FLOW_ACTION_PRIORITY;
  357. else if (is_tcf_skbedit_rx_queue_mapping(act))
  358. fl_action->id = FLOW_ACTION_RX_QUEUE_MAPPING;
  359. else
  360. return -EOPNOTSUPP;
  361. }
  362. return 0;
  363. }
  364. static struct tc_action_ops act_skbedit_ops = {
  365. .kind = "skbedit",
  366. .id = TCA_ID_SKBEDIT,
  367. .owner = THIS_MODULE,
  368. .act = tcf_skbedit_act,
  369. .stats_update = tcf_skbedit_stats_update,
  370. .dump = tcf_skbedit_dump,
  371. .init = tcf_skbedit_init,
  372. .cleanup = tcf_skbedit_cleanup,
  373. .get_fill_size = tcf_skbedit_get_fill_size,
  374. .offload_act_setup = tcf_skbedit_offload_act_setup,
  375. .size = sizeof(struct tcf_skbedit),
  376. };
  377. MODULE_ALIAS_NET_ACT("skbedit");
  378. static __net_init int skbedit_init_net(struct net *net)
  379. {
  380. struct tc_action_net *tn = net_generic(net, act_skbedit_ops.net_id);
  381. return tc_action_net_init(net, tn, &act_skbedit_ops);
  382. }
  383. static void __net_exit skbedit_exit_net(struct list_head *net_list)
  384. {
  385. tc_action_net_exit(net_list, act_skbedit_ops.net_id);
  386. }
  387. static struct pernet_operations skbedit_net_ops = {
  388. .init = skbedit_init_net,
  389. .exit_batch = skbedit_exit_net,
  390. .id = &act_skbedit_ops.net_id,
  391. .size = sizeof(struct tc_action_net),
  392. };
  393. MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>");
  394. MODULE_DESCRIPTION("SKB Editing");
  395. MODULE_LICENSE("GPL");
  396. static int __init skbedit_init_module(void)
  397. {
  398. return tcf_register_action(&act_skbedit_ops, &skbedit_net_ops);
  399. }
  400. static void __exit skbedit_cleanup_module(void)
  401. {
  402. tcf_unregister_action(&act_skbedit_ops, &skbedit_net_ops);
  403. }
  404. module_init(skbedit_init_module);
  405. module_exit(skbedit_cleanup_module);