ioam6.c 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * IPv6 IOAM implementation
  4. *
  5. * Author:
  6. * Justin Iurman <justin.iurman@uliege.be>
  7. */
  8. #include <linux/errno.h>
  9. #include <linux/types.h>
  10. #include <linux/kernel.h>
  11. #include <linux/net.h>
  12. #include <linux/ioam6.h>
  13. #include <linux/ioam6_genl.h>
  14. #include <linux/rhashtable.h>
  15. #include <linux/netdevice.h>
  16. #include <net/addrconf.h>
  17. #include <net/genetlink.h>
  18. #include <net/ioam6.h>
  19. #include <net/sch_generic.h>
  20. static void ioam6_ns_release(struct ioam6_namespace *ns)
  21. {
  22. kfree_rcu(ns, rcu);
  23. }
  24. static void ioam6_sc_release(struct ioam6_schema *sc)
  25. {
  26. kfree_rcu(sc, rcu);
  27. }
  28. static void ioam6_free_ns(void *ptr, void *arg)
  29. {
  30. struct ioam6_namespace *ns = (struct ioam6_namespace *)ptr;
  31. if (ns)
  32. ioam6_ns_release(ns);
  33. }
  34. static void ioam6_free_sc(void *ptr, void *arg)
  35. {
  36. struct ioam6_schema *sc = (struct ioam6_schema *)ptr;
  37. if (sc)
  38. ioam6_sc_release(sc);
  39. }
  40. static int ioam6_ns_cmpfn(struct rhashtable_compare_arg *arg, const void *obj)
  41. {
  42. const struct ioam6_namespace *ns = obj;
  43. return (ns->id != *(__be16 *)arg->key);
  44. }
  45. static int ioam6_sc_cmpfn(struct rhashtable_compare_arg *arg, const void *obj)
  46. {
  47. const struct ioam6_schema *sc = obj;
  48. return (sc->id != *(u32 *)arg->key);
  49. }
  50. static const struct rhashtable_params rht_ns_params = {
  51. .key_len = sizeof(__be16),
  52. .key_offset = offsetof(struct ioam6_namespace, id),
  53. .head_offset = offsetof(struct ioam6_namespace, head),
  54. .automatic_shrinking = true,
  55. .obj_cmpfn = ioam6_ns_cmpfn,
  56. };
  57. static const struct rhashtable_params rht_sc_params = {
  58. .key_len = sizeof(u32),
  59. .key_offset = offsetof(struct ioam6_schema, id),
  60. .head_offset = offsetof(struct ioam6_schema, head),
  61. .automatic_shrinking = true,
  62. .obj_cmpfn = ioam6_sc_cmpfn,
  63. };
  64. static struct genl_family ioam6_genl_family;
  65. static const struct nla_policy ioam6_genl_policy_addns[] = {
  66. [IOAM6_ATTR_NS_ID] = { .type = NLA_U16 },
  67. [IOAM6_ATTR_NS_DATA] = { .type = NLA_U32 },
  68. [IOAM6_ATTR_NS_DATA_WIDE] = { .type = NLA_U64 },
  69. };
  70. static const struct nla_policy ioam6_genl_policy_delns[] = {
  71. [IOAM6_ATTR_NS_ID] = { .type = NLA_U16 },
  72. };
  73. static const struct nla_policy ioam6_genl_policy_addsc[] = {
  74. [IOAM6_ATTR_SC_ID] = { .type = NLA_U32 },
  75. [IOAM6_ATTR_SC_DATA] = { .type = NLA_BINARY,
  76. .len = IOAM6_MAX_SCHEMA_DATA_LEN },
  77. };
  78. static const struct nla_policy ioam6_genl_policy_delsc[] = {
  79. [IOAM6_ATTR_SC_ID] = { .type = NLA_U32 },
  80. };
  81. static const struct nla_policy ioam6_genl_policy_ns_sc[] = {
  82. [IOAM6_ATTR_NS_ID] = { .type = NLA_U16 },
  83. [IOAM6_ATTR_SC_ID] = { .type = NLA_U32 },
  84. [IOAM6_ATTR_SC_NONE] = { .type = NLA_FLAG },
  85. };
  86. static int ioam6_genl_addns(struct sk_buff *skb, struct genl_info *info)
  87. {
  88. struct ioam6_pernet_data *nsdata;
  89. struct ioam6_namespace *ns;
  90. u64 data64;
  91. u32 data32;
  92. __be16 id;
  93. int err;
  94. if (!info->attrs[IOAM6_ATTR_NS_ID])
  95. return -EINVAL;
  96. id = cpu_to_be16(nla_get_u16(info->attrs[IOAM6_ATTR_NS_ID]));
  97. nsdata = ioam6_pernet(genl_info_net(info));
  98. mutex_lock(&nsdata->lock);
  99. ns = rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params);
  100. if (ns) {
  101. err = -EEXIST;
  102. goto out_unlock;
  103. }
  104. ns = kzalloc_obj(*ns);
  105. if (!ns) {
  106. err = -ENOMEM;
  107. goto out_unlock;
  108. }
  109. ns->id = id;
  110. data32 = nla_get_u32_default(info->attrs[IOAM6_ATTR_NS_DATA],
  111. IOAM6_U32_UNAVAILABLE);
  112. data64 = nla_get_u64_default(info->attrs[IOAM6_ATTR_NS_DATA_WIDE],
  113. IOAM6_U64_UNAVAILABLE);
  114. ns->data = cpu_to_be32(data32);
  115. ns->data_wide = cpu_to_be64(data64);
  116. err = rhashtable_lookup_insert_fast(&nsdata->namespaces, &ns->head,
  117. rht_ns_params);
  118. if (err)
  119. kfree(ns);
  120. out_unlock:
  121. mutex_unlock(&nsdata->lock);
  122. return err;
  123. }
  124. static int ioam6_genl_delns(struct sk_buff *skb, struct genl_info *info)
  125. {
  126. struct ioam6_pernet_data *nsdata;
  127. struct ioam6_namespace *ns;
  128. struct ioam6_schema *sc;
  129. __be16 id;
  130. int err;
  131. if (!info->attrs[IOAM6_ATTR_NS_ID])
  132. return -EINVAL;
  133. id = cpu_to_be16(nla_get_u16(info->attrs[IOAM6_ATTR_NS_ID]));
  134. nsdata = ioam6_pernet(genl_info_net(info));
  135. mutex_lock(&nsdata->lock);
  136. ns = rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params);
  137. if (!ns) {
  138. err = -ENOENT;
  139. goto out_unlock;
  140. }
  141. sc = rcu_dereference_protected(ns->schema,
  142. lockdep_is_held(&nsdata->lock));
  143. err = rhashtable_remove_fast(&nsdata->namespaces, &ns->head,
  144. rht_ns_params);
  145. if (err)
  146. goto out_unlock;
  147. if (sc)
  148. rcu_assign_pointer(sc->ns, NULL);
  149. ioam6_ns_release(ns);
  150. out_unlock:
  151. mutex_unlock(&nsdata->lock);
  152. return err;
  153. }
  154. static int __ioam6_genl_dumpns_element(struct ioam6_namespace *ns,
  155. u32 portid,
  156. u32 seq,
  157. u32 flags,
  158. struct sk_buff *skb,
  159. u8 cmd)
  160. {
  161. struct ioam6_schema *sc;
  162. u64 data64;
  163. u32 data32;
  164. void *hdr;
  165. hdr = genlmsg_put(skb, portid, seq, &ioam6_genl_family, flags, cmd);
  166. if (!hdr)
  167. return -ENOMEM;
  168. data32 = be32_to_cpu(ns->data);
  169. data64 = be64_to_cpu(ns->data_wide);
  170. if (nla_put_u16(skb, IOAM6_ATTR_NS_ID, be16_to_cpu(ns->id)) ||
  171. (data32 != IOAM6_U32_UNAVAILABLE &&
  172. nla_put_u32(skb, IOAM6_ATTR_NS_DATA, data32)) ||
  173. (data64 != IOAM6_U64_UNAVAILABLE &&
  174. nla_put_u64_64bit(skb, IOAM6_ATTR_NS_DATA_WIDE,
  175. data64, IOAM6_ATTR_PAD)))
  176. goto nla_put_failure;
  177. rcu_read_lock();
  178. sc = rcu_dereference(ns->schema);
  179. if (sc && nla_put_u32(skb, IOAM6_ATTR_SC_ID, sc->id)) {
  180. rcu_read_unlock();
  181. goto nla_put_failure;
  182. }
  183. rcu_read_unlock();
  184. genlmsg_end(skb, hdr);
  185. return 0;
  186. nla_put_failure:
  187. genlmsg_cancel(skb, hdr);
  188. return -EMSGSIZE;
  189. }
  190. static int ioam6_genl_dumpns_start(struct netlink_callback *cb)
  191. {
  192. struct ioam6_pernet_data *nsdata = ioam6_pernet(sock_net(cb->skb->sk));
  193. struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
  194. if (!iter) {
  195. iter = kmalloc_obj(*iter);
  196. if (!iter)
  197. return -ENOMEM;
  198. cb->args[0] = (long)iter;
  199. }
  200. rhashtable_walk_enter(&nsdata->namespaces, iter);
  201. return 0;
  202. }
  203. static int ioam6_genl_dumpns_done(struct netlink_callback *cb)
  204. {
  205. struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
  206. rhashtable_walk_exit(iter);
  207. kfree(iter);
  208. return 0;
  209. }
  210. static int ioam6_genl_dumpns(struct sk_buff *skb, struct netlink_callback *cb)
  211. {
  212. struct rhashtable_iter *iter;
  213. struct ioam6_namespace *ns;
  214. int err;
  215. iter = (struct rhashtable_iter *)cb->args[0];
  216. rhashtable_walk_start(iter);
  217. for (;;) {
  218. ns = rhashtable_walk_next(iter);
  219. if (IS_ERR(ns)) {
  220. if (PTR_ERR(ns) == -EAGAIN)
  221. continue;
  222. err = PTR_ERR(ns);
  223. goto done;
  224. } else if (!ns) {
  225. break;
  226. }
  227. err = __ioam6_genl_dumpns_element(ns,
  228. NETLINK_CB(cb->skb).portid,
  229. cb->nlh->nlmsg_seq,
  230. NLM_F_MULTI,
  231. skb,
  232. IOAM6_CMD_DUMP_NAMESPACES);
  233. if (err)
  234. goto done;
  235. }
  236. err = skb->len;
  237. done:
  238. rhashtable_walk_stop(iter);
  239. return err;
  240. }
  241. static int ioam6_genl_addsc(struct sk_buff *skb, struct genl_info *info)
  242. {
  243. struct ioam6_pernet_data *nsdata;
  244. int len, len_aligned, err;
  245. struct ioam6_schema *sc;
  246. u32 id;
  247. if (!info->attrs[IOAM6_ATTR_SC_ID] || !info->attrs[IOAM6_ATTR_SC_DATA])
  248. return -EINVAL;
  249. id = nla_get_u32(info->attrs[IOAM6_ATTR_SC_ID]);
  250. nsdata = ioam6_pernet(genl_info_net(info));
  251. mutex_lock(&nsdata->lock);
  252. sc = rhashtable_lookup_fast(&nsdata->schemas, &id, rht_sc_params);
  253. if (sc) {
  254. err = -EEXIST;
  255. goto out_unlock;
  256. }
  257. len = nla_len(info->attrs[IOAM6_ATTR_SC_DATA]);
  258. len_aligned = ALIGN(len, 4);
  259. sc = kzalloc(sizeof(*sc) + len_aligned, GFP_KERNEL);
  260. if (!sc) {
  261. err = -ENOMEM;
  262. goto out_unlock;
  263. }
  264. sc->id = id;
  265. sc->len = len_aligned;
  266. sc->hdr = cpu_to_be32(sc->id | ((u8)(sc->len / 4) << 24));
  267. nla_memcpy(sc->data, info->attrs[IOAM6_ATTR_SC_DATA], len);
  268. err = rhashtable_lookup_insert_fast(&nsdata->schemas, &sc->head,
  269. rht_sc_params);
  270. if (err)
  271. goto free_sc;
  272. out_unlock:
  273. mutex_unlock(&nsdata->lock);
  274. return err;
  275. free_sc:
  276. kfree(sc);
  277. goto out_unlock;
  278. }
  279. static int ioam6_genl_delsc(struct sk_buff *skb, struct genl_info *info)
  280. {
  281. struct ioam6_pernet_data *nsdata;
  282. struct ioam6_namespace *ns;
  283. struct ioam6_schema *sc;
  284. int err;
  285. u32 id;
  286. if (!info->attrs[IOAM6_ATTR_SC_ID])
  287. return -EINVAL;
  288. id = nla_get_u32(info->attrs[IOAM6_ATTR_SC_ID]);
  289. nsdata = ioam6_pernet(genl_info_net(info));
  290. mutex_lock(&nsdata->lock);
  291. sc = rhashtable_lookup_fast(&nsdata->schemas, &id, rht_sc_params);
  292. if (!sc) {
  293. err = -ENOENT;
  294. goto out_unlock;
  295. }
  296. ns = rcu_dereference_protected(sc->ns, lockdep_is_held(&nsdata->lock));
  297. err = rhashtable_remove_fast(&nsdata->schemas, &sc->head,
  298. rht_sc_params);
  299. if (err)
  300. goto out_unlock;
  301. if (ns)
  302. rcu_assign_pointer(ns->schema, NULL);
  303. ioam6_sc_release(sc);
  304. out_unlock:
  305. mutex_unlock(&nsdata->lock);
  306. return err;
  307. }
  308. static int __ioam6_genl_dumpsc_element(struct ioam6_schema *sc,
  309. u32 portid, u32 seq, u32 flags,
  310. struct sk_buff *skb, u8 cmd)
  311. {
  312. struct ioam6_namespace *ns;
  313. void *hdr;
  314. hdr = genlmsg_put(skb, portid, seq, &ioam6_genl_family, flags, cmd);
  315. if (!hdr)
  316. return -ENOMEM;
  317. if (nla_put_u32(skb, IOAM6_ATTR_SC_ID, sc->id) ||
  318. nla_put(skb, IOAM6_ATTR_SC_DATA, sc->len, sc->data))
  319. goto nla_put_failure;
  320. rcu_read_lock();
  321. ns = rcu_dereference(sc->ns);
  322. if (ns && nla_put_u16(skb, IOAM6_ATTR_NS_ID, be16_to_cpu(ns->id))) {
  323. rcu_read_unlock();
  324. goto nla_put_failure;
  325. }
  326. rcu_read_unlock();
  327. genlmsg_end(skb, hdr);
  328. return 0;
  329. nla_put_failure:
  330. genlmsg_cancel(skb, hdr);
  331. return -EMSGSIZE;
  332. }
  333. static int ioam6_genl_dumpsc_start(struct netlink_callback *cb)
  334. {
  335. struct ioam6_pernet_data *nsdata = ioam6_pernet(sock_net(cb->skb->sk));
  336. struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
  337. if (!iter) {
  338. iter = kmalloc_obj(*iter);
  339. if (!iter)
  340. return -ENOMEM;
  341. cb->args[0] = (long)iter;
  342. }
  343. rhashtable_walk_enter(&nsdata->schemas, iter);
  344. return 0;
  345. }
  346. static int ioam6_genl_dumpsc_done(struct netlink_callback *cb)
  347. {
  348. struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
  349. rhashtable_walk_exit(iter);
  350. kfree(iter);
  351. return 0;
  352. }
  353. static int ioam6_genl_dumpsc(struct sk_buff *skb, struct netlink_callback *cb)
  354. {
  355. struct rhashtable_iter *iter;
  356. struct ioam6_schema *sc;
  357. int err;
  358. iter = (struct rhashtable_iter *)cb->args[0];
  359. rhashtable_walk_start(iter);
  360. for (;;) {
  361. sc = rhashtable_walk_next(iter);
  362. if (IS_ERR(sc)) {
  363. if (PTR_ERR(sc) == -EAGAIN)
  364. continue;
  365. err = PTR_ERR(sc);
  366. goto done;
  367. } else if (!sc) {
  368. break;
  369. }
  370. err = __ioam6_genl_dumpsc_element(sc,
  371. NETLINK_CB(cb->skb).portid,
  372. cb->nlh->nlmsg_seq,
  373. NLM_F_MULTI,
  374. skb,
  375. IOAM6_CMD_DUMP_SCHEMAS);
  376. if (err)
  377. goto done;
  378. }
  379. err = skb->len;
  380. done:
  381. rhashtable_walk_stop(iter);
  382. return err;
  383. }
  384. static int ioam6_genl_ns_set_schema(struct sk_buff *skb, struct genl_info *info)
  385. {
  386. struct ioam6_namespace *ns, *ns_ref;
  387. struct ioam6_schema *sc, *sc_ref;
  388. struct ioam6_pernet_data *nsdata;
  389. __be16 ns_id;
  390. u32 sc_id;
  391. int err;
  392. if (!info->attrs[IOAM6_ATTR_NS_ID] ||
  393. (!info->attrs[IOAM6_ATTR_SC_ID] &&
  394. !info->attrs[IOAM6_ATTR_SC_NONE]))
  395. return -EINVAL;
  396. ns_id = cpu_to_be16(nla_get_u16(info->attrs[IOAM6_ATTR_NS_ID]));
  397. nsdata = ioam6_pernet(genl_info_net(info));
  398. mutex_lock(&nsdata->lock);
  399. ns = rhashtable_lookup_fast(&nsdata->namespaces, &ns_id, rht_ns_params);
  400. if (!ns) {
  401. err = -ENOENT;
  402. goto out_unlock;
  403. }
  404. if (info->attrs[IOAM6_ATTR_SC_NONE]) {
  405. sc = NULL;
  406. } else {
  407. sc_id = nla_get_u32(info->attrs[IOAM6_ATTR_SC_ID]);
  408. sc = rhashtable_lookup_fast(&nsdata->schemas, &sc_id,
  409. rht_sc_params);
  410. if (!sc) {
  411. err = -ENOENT;
  412. goto out_unlock;
  413. }
  414. }
  415. sc_ref = rcu_dereference_protected(ns->schema,
  416. lockdep_is_held(&nsdata->lock));
  417. if (sc_ref)
  418. rcu_assign_pointer(sc_ref->ns, NULL);
  419. rcu_assign_pointer(ns->schema, sc);
  420. if (sc) {
  421. ns_ref = rcu_dereference_protected(sc->ns,
  422. lockdep_is_held(&nsdata->lock));
  423. if (ns_ref)
  424. rcu_assign_pointer(ns_ref->schema, NULL);
  425. rcu_assign_pointer(sc->ns, ns);
  426. }
  427. err = 0;
  428. out_unlock:
  429. mutex_unlock(&nsdata->lock);
  430. return err;
  431. }
  432. static const struct genl_ops ioam6_genl_ops[] = {
  433. {
  434. .cmd = IOAM6_CMD_ADD_NAMESPACE,
  435. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  436. .doit = ioam6_genl_addns,
  437. .flags = GENL_ADMIN_PERM,
  438. .policy = ioam6_genl_policy_addns,
  439. .maxattr = ARRAY_SIZE(ioam6_genl_policy_addns) - 1,
  440. },
  441. {
  442. .cmd = IOAM6_CMD_DEL_NAMESPACE,
  443. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  444. .doit = ioam6_genl_delns,
  445. .flags = GENL_ADMIN_PERM,
  446. .policy = ioam6_genl_policy_delns,
  447. .maxattr = ARRAY_SIZE(ioam6_genl_policy_delns) - 1,
  448. },
  449. {
  450. .cmd = IOAM6_CMD_DUMP_NAMESPACES,
  451. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  452. .start = ioam6_genl_dumpns_start,
  453. .dumpit = ioam6_genl_dumpns,
  454. .done = ioam6_genl_dumpns_done,
  455. .flags = GENL_ADMIN_PERM,
  456. },
  457. {
  458. .cmd = IOAM6_CMD_ADD_SCHEMA,
  459. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  460. .doit = ioam6_genl_addsc,
  461. .flags = GENL_ADMIN_PERM,
  462. .policy = ioam6_genl_policy_addsc,
  463. .maxattr = ARRAY_SIZE(ioam6_genl_policy_addsc) - 1,
  464. },
  465. {
  466. .cmd = IOAM6_CMD_DEL_SCHEMA,
  467. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  468. .doit = ioam6_genl_delsc,
  469. .flags = GENL_ADMIN_PERM,
  470. .policy = ioam6_genl_policy_delsc,
  471. .maxattr = ARRAY_SIZE(ioam6_genl_policy_delsc) - 1,
  472. },
  473. {
  474. .cmd = IOAM6_CMD_DUMP_SCHEMAS,
  475. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  476. .start = ioam6_genl_dumpsc_start,
  477. .dumpit = ioam6_genl_dumpsc,
  478. .done = ioam6_genl_dumpsc_done,
  479. .flags = GENL_ADMIN_PERM,
  480. },
  481. {
  482. .cmd = IOAM6_CMD_NS_SET_SCHEMA,
  483. .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
  484. .doit = ioam6_genl_ns_set_schema,
  485. .flags = GENL_ADMIN_PERM,
  486. .policy = ioam6_genl_policy_ns_sc,
  487. .maxattr = ARRAY_SIZE(ioam6_genl_policy_ns_sc) - 1,
  488. },
  489. };
  490. #define IOAM6_GENL_EV_GRP_OFFSET 0
  491. static const struct genl_multicast_group ioam6_mcgrps[] = {
  492. [IOAM6_GENL_EV_GRP_OFFSET] = { .name = IOAM6_GENL_EV_GRP_NAME,
  493. .flags = GENL_MCAST_CAP_NET_ADMIN },
  494. };
  495. static int ioam6_event_put_trace(struct sk_buff *skb,
  496. struct ioam6_trace_hdr *trace,
  497. unsigned int len)
  498. {
  499. if (nla_put_u16(skb, IOAM6_EVENT_ATTR_TRACE_NAMESPACE,
  500. be16_to_cpu(trace->namespace_id)) ||
  501. nla_put_u8(skb, IOAM6_EVENT_ATTR_TRACE_NODELEN, trace->nodelen) ||
  502. nla_put_u32(skb, IOAM6_EVENT_ATTR_TRACE_TYPE,
  503. be32_to_cpu(trace->type_be32)) ||
  504. nla_put(skb, IOAM6_EVENT_ATTR_TRACE_DATA,
  505. len - sizeof(struct ioam6_trace_hdr) - trace->remlen * 4,
  506. trace->data + trace->remlen * 4))
  507. return 1;
  508. return 0;
  509. }
  510. void ioam6_event(enum ioam6_event_type type, struct net *net, gfp_t gfp,
  511. void *opt, unsigned int opt_len)
  512. {
  513. struct nlmsghdr *nlh;
  514. struct sk_buff *skb;
  515. if (!genl_has_listeners(&ioam6_genl_family, net,
  516. IOAM6_GENL_EV_GRP_OFFSET))
  517. return;
  518. skb = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
  519. if (!skb)
  520. return;
  521. nlh = genlmsg_put(skb, 0, 0, &ioam6_genl_family, 0, type);
  522. if (!nlh)
  523. goto nla_put_failure;
  524. switch (type) {
  525. case IOAM6_EVENT_UNSPEC:
  526. WARN_ON_ONCE(1);
  527. break;
  528. case IOAM6_EVENT_TRACE:
  529. if (ioam6_event_put_trace(skb, (struct ioam6_trace_hdr *)opt,
  530. opt_len))
  531. goto nla_put_failure;
  532. break;
  533. }
  534. genlmsg_end(skb, nlh);
  535. genlmsg_multicast_netns(&ioam6_genl_family, net, skb, 0,
  536. IOAM6_GENL_EV_GRP_OFFSET, gfp);
  537. return;
  538. nla_put_failure:
  539. nlmsg_free(skb);
  540. }
  541. static struct genl_family ioam6_genl_family __ro_after_init = {
  542. .name = IOAM6_GENL_NAME,
  543. .version = IOAM6_GENL_VERSION,
  544. .netnsok = true,
  545. .parallel_ops = true,
  546. .ops = ioam6_genl_ops,
  547. .n_ops = ARRAY_SIZE(ioam6_genl_ops),
  548. .resv_start_op = IOAM6_CMD_NS_SET_SCHEMA + 1,
  549. .mcgrps = ioam6_mcgrps,
  550. .n_mcgrps = ARRAY_SIZE(ioam6_mcgrps),
  551. .module = THIS_MODULE,
  552. };
  553. struct ioam6_namespace *ioam6_namespace(struct net *net, __be16 id)
  554. {
  555. struct ioam6_pernet_data *nsdata = ioam6_pernet(net);
  556. return rhashtable_lookup_fast(&nsdata->namespaces, &id, rht_ns_params);
  557. }
  558. #define IOAM6_MASK_SHORT_FIELDS 0xff1ffc00
  559. #define IOAM6_MASK_WIDE_FIELDS 0x00e00000
  560. u8 ioam6_trace_compute_nodelen(u32 trace_type)
  561. {
  562. u8 nodelen = hweight32(trace_type & IOAM6_MASK_SHORT_FIELDS)
  563. * (sizeof(__be32) / 4);
  564. nodelen += hweight32(trace_type & IOAM6_MASK_WIDE_FIELDS)
  565. * (sizeof(__be64) / 4);
  566. return nodelen;
  567. }
  568. static void __ioam6_fill_trace_data(struct sk_buff *skb,
  569. struct ioam6_namespace *ns,
  570. struct ioam6_trace_hdr *trace,
  571. struct ioam6_schema *sc,
  572. unsigned int sclen, bool is_input)
  573. {
  574. /* Note: skb_dst_dev_rcu() can't be NULL at this point. */
  575. struct net_device *dev = skb_dst_dev_rcu(skb);
  576. struct inet6_dev *i_skb_dev, *idev;
  577. struct timespec64 ts;
  578. ktime_t tstamp;
  579. u64 raw64;
  580. u32 raw32;
  581. u16 raw16;
  582. u8 *data;
  583. u8 byte;
  584. data = trace->data + trace->remlen * 4 - trace->nodelen * 4 - sclen * 4;
  585. i_skb_dev = skb->dev ? __in6_dev_get(skb->dev) : NULL;
  586. idev = __in6_dev_get(dev);
  587. /* hop_lim and node_id */
  588. if (trace->type.bit0) {
  589. byte = ipv6_hdr(skb)->hop_limit;
  590. if (is_input)
  591. byte--;
  592. raw32 = READ_ONCE(dev_net(dev)->ipv6.sysctl.ioam6_id);
  593. *(__be32 *)data = cpu_to_be32((byte << 24) | raw32);
  594. data += sizeof(__be32);
  595. }
  596. /* ingress_if_id and egress_if_id */
  597. if (trace->type.bit1) {
  598. if (!i_skb_dev)
  599. raw16 = IOAM6_U16_UNAVAILABLE;
  600. else
  601. raw16 = (__force u16)READ_ONCE(i_skb_dev->cnf.ioam6_id);
  602. *(__be16 *)data = cpu_to_be16(raw16);
  603. data += sizeof(__be16);
  604. if ((dev->flags & IFF_LOOPBACK) || !idev)
  605. raw16 = IOAM6_U16_UNAVAILABLE;
  606. else
  607. raw16 = (__force u16)READ_ONCE(idev->cnf.ioam6_id);
  608. *(__be16 *)data = cpu_to_be16(raw16);
  609. data += sizeof(__be16);
  610. }
  611. /* timestamp seconds */
  612. if (trace->type.bit2) {
  613. if (!skb->dev) {
  614. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  615. } else {
  616. tstamp = skb_tstamp_cond(skb, true);
  617. ts = ktime_to_timespec64(tstamp);
  618. *(__be32 *)data = cpu_to_be32((u32)ts.tv_sec);
  619. }
  620. data += sizeof(__be32);
  621. }
  622. /* timestamp subseconds */
  623. if (trace->type.bit3) {
  624. if (!skb->dev) {
  625. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  626. } else {
  627. if (!trace->type.bit2) {
  628. tstamp = skb_tstamp_cond(skb, true);
  629. ts = ktime_to_timespec64(tstamp);
  630. }
  631. *(__be32 *)data = cpu_to_be32((u32)(ts.tv_nsec / NSEC_PER_USEC));
  632. }
  633. data += sizeof(__be32);
  634. }
  635. /* transit delay */
  636. if (trace->type.bit4) {
  637. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  638. data += sizeof(__be32);
  639. }
  640. /* namespace data */
  641. if (trace->type.bit5) {
  642. *(__be32 *)data = ns->data;
  643. data += sizeof(__be32);
  644. }
  645. /* queue depth */
  646. if (trace->type.bit6) {
  647. struct netdev_queue *queue;
  648. struct Qdisc *qdisc;
  649. __u32 qlen, backlog;
  650. if (dev->flags & IFF_LOOPBACK ||
  651. skb_get_queue_mapping(skb) >= dev->num_tx_queues) {
  652. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  653. } else {
  654. queue = skb_get_tx_queue(dev, skb);
  655. qdisc = rcu_dereference(queue->qdisc);
  656. spin_lock_bh(qdisc_lock(qdisc));
  657. qdisc_qstats_qlen_backlog(qdisc, &qlen, &backlog);
  658. spin_unlock_bh(qdisc_lock(qdisc));
  659. *(__be32 *)data = cpu_to_be32(backlog);
  660. }
  661. data += sizeof(__be32);
  662. }
  663. /* checksum complement */
  664. if (trace->type.bit7) {
  665. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  666. data += sizeof(__be32);
  667. }
  668. /* hop_lim and node_id (wide) */
  669. if (trace->type.bit8) {
  670. byte = ipv6_hdr(skb)->hop_limit;
  671. if (is_input)
  672. byte--;
  673. raw64 = READ_ONCE(dev_net(dev)->ipv6.sysctl.ioam6_id_wide);
  674. *(__be64 *)data = cpu_to_be64(((u64)byte << 56) | raw64);
  675. data += sizeof(__be64);
  676. }
  677. /* ingress_if_id and egress_if_id (wide) */
  678. if (trace->type.bit9) {
  679. if (!i_skb_dev)
  680. raw32 = IOAM6_U32_UNAVAILABLE;
  681. else
  682. raw32 = READ_ONCE(i_skb_dev->cnf.ioam6_id_wide);
  683. *(__be32 *)data = cpu_to_be32(raw32);
  684. data += sizeof(__be32);
  685. if ((dev->flags & IFF_LOOPBACK) || !idev)
  686. raw32 = IOAM6_U32_UNAVAILABLE;
  687. else
  688. raw32 = READ_ONCE(idev->cnf.ioam6_id_wide);
  689. *(__be32 *)data = cpu_to_be32(raw32);
  690. data += sizeof(__be32);
  691. }
  692. /* namespace data (wide) */
  693. if (trace->type.bit10) {
  694. *(__be64 *)data = ns->data_wide;
  695. data += sizeof(__be64);
  696. }
  697. /* buffer occupancy */
  698. if (trace->type.bit11) {
  699. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  700. data += sizeof(__be32);
  701. }
  702. /* bit12 undefined: filled with empty value */
  703. if (trace->type.bit12) {
  704. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  705. data += sizeof(__be32);
  706. }
  707. /* bit13 undefined: filled with empty value */
  708. if (trace->type.bit13) {
  709. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  710. data += sizeof(__be32);
  711. }
  712. /* bit14 undefined: filled with empty value */
  713. if (trace->type.bit14) {
  714. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  715. data += sizeof(__be32);
  716. }
  717. /* bit15 undefined: filled with empty value */
  718. if (trace->type.bit15) {
  719. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  720. data += sizeof(__be32);
  721. }
  722. /* bit16 undefined: filled with empty value */
  723. if (trace->type.bit16) {
  724. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  725. data += sizeof(__be32);
  726. }
  727. /* bit17 undefined: filled with empty value */
  728. if (trace->type.bit17) {
  729. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  730. data += sizeof(__be32);
  731. }
  732. /* bit18 undefined: filled with empty value */
  733. if (trace->type.bit18) {
  734. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  735. data += sizeof(__be32);
  736. }
  737. /* bit19 undefined: filled with empty value */
  738. if (trace->type.bit19) {
  739. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  740. data += sizeof(__be32);
  741. }
  742. /* bit20 undefined: filled with empty value */
  743. if (trace->type.bit20) {
  744. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  745. data += sizeof(__be32);
  746. }
  747. /* bit21 undefined: filled with empty value */
  748. if (trace->type.bit21) {
  749. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
  750. data += sizeof(__be32);
  751. }
  752. /* opaque state snapshot */
  753. if (trace->type.bit22) {
  754. if (!sc) {
  755. *(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE >> 8);
  756. } else {
  757. *(__be32 *)data = sc->hdr;
  758. data += sizeof(__be32);
  759. memcpy(data, sc->data, sc->len);
  760. }
  761. }
  762. }
  763. /* called with rcu_read_lock() */
  764. void ioam6_fill_trace_data(struct sk_buff *skb,
  765. struct ioam6_namespace *ns,
  766. struct ioam6_trace_hdr *trace,
  767. bool is_input)
  768. {
  769. struct ioam6_schema *sc;
  770. unsigned int sclen = 0;
  771. /* Skip if Overflow flag is set
  772. */
  773. if (trace->overflow)
  774. return;
  775. /* NodeLen does not include Opaque State Snapshot length. We need to
  776. * take it into account if the corresponding bit is set (bit 22) and
  777. * if the current IOAM namespace has an active schema attached to it
  778. */
  779. sc = rcu_dereference(ns->schema);
  780. if (trace->type.bit22) {
  781. sclen = sizeof_field(struct ioam6_schema, hdr) / 4;
  782. if (sc)
  783. sclen += sc->len / 4;
  784. }
  785. /* If there is no space remaining, we set the Overflow flag and we
  786. * skip without filling the trace
  787. */
  788. if (!trace->remlen || trace->remlen < trace->nodelen + sclen) {
  789. trace->overflow = 1;
  790. return;
  791. }
  792. __ioam6_fill_trace_data(skb, ns, trace, sc, sclen, is_input);
  793. trace->remlen -= trace->nodelen + sclen;
  794. }
  795. static int __net_init ioam6_net_init(struct net *net)
  796. {
  797. struct ioam6_pernet_data *nsdata;
  798. int err = -ENOMEM;
  799. nsdata = kzalloc_obj(*nsdata);
  800. if (!nsdata)
  801. goto out;
  802. mutex_init(&nsdata->lock);
  803. net->ipv6.ioam6_data = nsdata;
  804. err = rhashtable_init(&nsdata->namespaces, &rht_ns_params);
  805. if (err)
  806. goto free_nsdata;
  807. err = rhashtable_init(&nsdata->schemas, &rht_sc_params);
  808. if (err)
  809. goto free_rht_ns;
  810. out:
  811. return err;
  812. free_rht_ns:
  813. rhashtable_destroy(&nsdata->namespaces);
  814. free_nsdata:
  815. kfree(nsdata);
  816. net->ipv6.ioam6_data = NULL;
  817. goto out;
  818. }
  819. static void __net_exit ioam6_net_exit(struct net *net)
  820. {
  821. struct ioam6_pernet_data *nsdata = ioam6_pernet(net);
  822. rhashtable_free_and_destroy(&nsdata->namespaces, ioam6_free_ns, NULL);
  823. rhashtable_free_and_destroy(&nsdata->schemas, ioam6_free_sc, NULL);
  824. kfree(nsdata);
  825. }
  826. static struct pernet_operations ioam6_net_ops = {
  827. .init = ioam6_net_init,
  828. .exit = ioam6_net_exit,
  829. };
  830. int __init ioam6_init(void)
  831. {
  832. int err = register_pernet_subsys(&ioam6_net_ops);
  833. if (err)
  834. goto out;
  835. err = genl_register_family(&ioam6_genl_family);
  836. if (err)
  837. goto out_unregister_pernet_subsys;
  838. #ifdef CONFIG_IPV6_IOAM6_LWTUNNEL
  839. err = ioam6_iptunnel_init();
  840. if (err)
  841. goto out_unregister_genl;
  842. #endif
  843. pr_info("In-situ OAM (IOAM) with IPv6\n");
  844. out:
  845. return err;
  846. #ifdef CONFIG_IPV6_IOAM6_LWTUNNEL
  847. out_unregister_genl:
  848. genl_unregister_family(&ioam6_genl_family);
  849. #endif
  850. out_unregister_pernet_subsys:
  851. unregister_pernet_subsys(&ioam6_net_ops);
  852. goto out;
  853. }
  854. void ioam6_exit(void)
  855. {
  856. #ifdef CONFIG_IPV6_IOAM6_LWTUNNEL
  857. ioam6_iptunnel_exit();
  858. #endif
  859. genl_unregister_family(&ioam6_genl_family);
  860. unregister_pernet_subsys(&ioam6_net_ops);
  861. }