map.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495
  1. // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2. /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
  3. #include <assert.h>
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <linux/err.h>
  7. #include <linux/kernel.h>
  8. #include <net/if.h>
  9. #include <stdbool.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <unistd.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <bpf/bpf.h>
  17. #include <bpf/btf.h>
  18. #include <bpf/hashmap.h>
  19. #include "json_writer.h"
  20. #include "main.h"
  21. static struct hashmap *map_table;
  22. static bool map_is_per_cpu(__u32 type)
  23. {
  24. return type == BPF_MAP_TYPE_PERCPU_HASH ||
  25. type == BPF_MAP_TYPE_PERCPU_ARRAY ||
  26. type == BPF_MAP_TYPE_LRU_PERCPU_HASH ||
  27. type == BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE;
  28. }
  29. static bool map_is_map_of_maps(__u32 type)
  30. {
  31. return type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
  32. type == BPF_MAP_TYPE_HASH_OF_MAPS;
  33. }
  34. static bool map_is_map_of_progs(__u32 type)
  35. {
  36. return type == BPF_MAP_TYPE_PROG_ARRAY;
  37. }
  38. static int map_type_from_str(const char *type)
  39. {
  40. const char *map_type_str;
  41. unsigned int i;
  42. for (i = 0; ; i++) {
  43. map_type_str = libbpf_bpf_map_type_str(i);
  44. if (!map_type_str)
  45. break;
  46. /* Don't allow prefixing in case of possible future shadowing */
  47. if (!strcmp(map_type_str, type))
  48. return i;
  49. }
  50. return -1;
  51. }
  52. static void *alloc_value(struct bpf_map_info *info)
  53. {
  54. if (map_is_per_cpu(info->type))
  55. return malloc(round_up(info->value_size, 8) *
  56. get_possible_cpus());
  57. else
  58. return malloc(info->value_size);
  59. }
  60. static int do_dump_btf(const struct btf_dumper *d,
  61. struct bpf_map_info *map_info, void *key,
  62. void *value)
  63. {
  64. __u32 value_id;
  65. int ret = 0;
  66. /* start of key-value pair */
  67. jsonw_start_object(d->jw);
  68. if (map_info->btf_key_type_id) {
  69. jsonw_name(d->jw, "key");
  70. ret = btf_dumper_type(d, map_info->btf_key_type_id, key);
  71. if (ret)
  72. goto err_end_obj;
  73. }
  74. value_id = map_info->btf_vmlinux_value_type_id ?
  75. : map_info->btf_value_type_id;
  76. if (!map_is_per_cpu(map_info->type)) {
  77. jsonw_name(d->jw, "value");
  78. ret = btf_dumper_type(d, value_id, value);
  79. } else {
  80. unsigned int i, n, step;
  81. jsonw_name(d->jw, "values");
  82. jsonw_start_array(d->jw);
  83. n = get_possible_cpus();
  84. step = round_up(map_info->value_size, 8);
  85. for (i = 0; i < n; i++) {
  86. jsonw_start_object(d->jw);
  87. jsonw_int_field(d->jw, "cpu", i);
  88. jsonw_name(d->jw, "value");
  89. ret = btf_dumper_type(d, value_id, value + i * step);
  90. jsonw_end_object(d->jw);
  91. if (ret)
  92. break;
  93. }
  94. jsonw_end_array(d->jw);
  95. }
  96. err_end_obj:
  97. /* end of key-value pair */
  98. jsonw_end_object(d->jw);
  99. return ret;
  100. }
  101. static json_writer_t *get_btf_writer(void)
  102. {
  103. json_writer_t *jw = jsonw_new(stdout);
  104. if (!jw)
  105. return NULL;
  106. jsonw_pretty(jw, true);
  107. return jw;
  108. }
  109. static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
  110. unsigned char *value, struct btf *btf)
  111. {
  112. jsonw_start_object(json_wtr);
  113. if (!map_is_per_cpu(info->type)) {
  114. jsonw_name(json_wtr, "key");
  115. print_hex_data_json(key, info->key_size);
  116. jsonw_name(json_wtr, "value");
  117. print_hex_data_json(value, info->value_size);
  118. if (btf) {
  119. struct btf_dumper d = {
  120. .btf = btf,
  121. .jw = json_wtr,
  122. .is_plain_text = false,
  123. };
  124. jsonw_name(json_wtr, "formatted");
  125. do_dump_btf(&d, info, key, value);
  126. }
  127. } else {
  128. unsigned int i, n, step;
  129. n = get_possible_cpus();
  130. step = round_up(info->value_size, 8);
  131. jsonw_name(json_wtr, "key");
  132. print_hex_data_json(key, info->key_size);
  133. jsonw_name(json_wtr, "values");
  134. jsonw_start_array(json_wtr);
  135. for (i = 0; i < n; i++) {
  136. jsonw_start_object(json_wtr);
  137. jsonw_int_field(json_wtr, "cpu", i);
  138. jsonw_name(json_wtr, "value");
  139. print_hex_data_json(value + i * step,
  140. info->value_size);
  141. jsonw_end_object(json_wtr);
  142. }
  143. jsonw_end_array(json_wtr);
  144. if (btf) {
  145. struct btf_dumper d = {
  146. .btf = btf,
  147. .jw = json_wtr,
  148. .is_plain_text = false,
  149. };
  150. jsonw_name(json_wtr, "formatted");
  151. do_dump_btf(&d, info, key, value);
  152. }
  153. }
  154. jsonw_end_object(json_wtr);
  155. }
  156. static void
  157. print_entry_error_msg(struct bpf_map_info *info, unsigned char *key,
  158. const char *error_msg)
  159. {
  160. int msg_size = strlen(error_msg);
  161. bool single_line, break_names;
  162. break_names = info->key_size > 16 || msg_size > 16;
  163. single_line = info->key_size + msg_size <= 24 && !break_names;
  164. printf("key:%c", break_names ? '\n' : ' ');
  165. fprint_hex(stdout, key, info->key_size, " ");
  166. printf(single_line ? " " : "\n");
  167. printf("value:%c%s", break_names ? '\n' : ' ', error_msg);
  168. printf("\n");
  169. }
  170. static void
  171. print_entry_error(struct bpf_map_info *map_info, void *key, int lookup_errno)
  172. {
  173. /* For prog_array maps or arrays of maps, failure to lookup the value
  174. * means there is no entry for that key. Do not print an error message
  175. * in that case.
  176. */
  177. if ((map_is_map_of_maps(map_info->type) ||
  178. map_is_map_of_progs(map_info->type)) && lookup_errno == ENOENT)
  179. return;
  180. if (json_output) {
  181. jsonw_start_object(json_wtr); /* entry */
  182. jsonw_name(json_wtr, "key");
  183. print_hex_data_json(key, map_info->key_size);
  184. jsonw_name(json_wtr, "value");
  185. jsonw_start_object(json_wtr); /* error */
  186. jsonw_string_field(json_wtr, "error", strerror(lookup_errno));
  187. jsonw_end_object(json_wtr); /* error */
  188. jsonw_end_object(json_wtr); /* entry */
  189. } else {
  190. const char *msg = NULL;
  191. if (lookup_errno == ENOENT)
  192. msg = "<no entry>";
  193. else if (lookup_errno == ENOSPC &&
  194. map_info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY)
  195. msg = "<cannot read>";
  196. print_entry_error_msg(map_info, key,
  197. msg ? : strerror(lookup_errno));
  198. }
  199. }
  200. static void print_entry_plain(struct bpf_map_info *info, unsigned char *key,
  201. unsigned char *value)
  202. {
  203. if (!map_is_per_cpu(info->type)) {
  204. bool single_line, break_names;
  205. break_names = info->key_size > 16 || info->value_size > 16;
  206. single_line = info->key_size + info->value_size <= 24 &&
  207. !break_names;
  208. if (info->key_size) {
  209. printf("key:%c", break_names ? '\n' : ' ');
  210. fprint_hex(stdout, key, info->key_size, " ");
  211. printf(single_line ? " " : "\n");
  212. }
  213. if (info->value_size) {
  214. printf("value:%c", break_names ? '\n' : ' ');
  215. fprint_hex(stdout, value, info->value_size, " ");
  216. }
  217. printf("\n");
  218. } else {
  219. unsigned int i, n, step;
  220. n = get_possible_cpus();
  221. step = round_up(info->value_size, 8);
  222. if (info->key_size) {
  223. printf("key:\n");
  224. fprint_hex(stdout, key, info->key_size, " ");
  225. printf("\n");
  226. }
  227. if (info->value_size) {
  228. for (i = 0; i < n; i++) {
  229. printf("value (CPU %02d):%c",
  230. i, info->value_size > 16 ? '\n' : ' ');
  231. fprint_hex(stdout, value + i * step,
  232. info->value_size, " ");
  233. printf("\n");
  234. }
  235. }
  236. }
  237. }
  238. static char **parse_bytes(char **argv, const char *name, unsigned char *val,
  239. unsigned int n)
  240. {
  241. unsigned int i = 0, base = 0;
  242. char *endptr;
  243. if (is_prefix(*argv, "hex")) {
  244. base = 16;
  245. argv++;
  246. }
  247. while (i < n && argv[i]) {
  248. val[i] = strtoul(argv[i], &endptr, base);
  249. if (*endptr) {
  250. p_err("error parsing byte: %s", argv[i]);
  251. return NULL;
  252. }
  253. i++;
  254. }
  255. if (i != n) {
  256. p_err("%s expected %d bytes got %d", name, n, i);
  257. return NULL;
  258. }
  259. return argv + i;
  260. }
  261. /* on per cpu maps we must copy the provided value on all value instances */
  262. static void fill_per_cpu_value(struct bpf_map_info *info, void *value)
  263. {
  264. unsigned int i, n, step;
  265. if (!map_is_per_cpu(info->type))
  266. return;
  267. n = get_possible_cpus();
  268. step = round_up(info->value_size, 8);
  269. for (i = 1; i < n; i++)
  270. memcpy(value + i * step, value, info->value_size);
  271. }
  272. static int parse_elem(char **argv, struct bpf_map_info *info,
  273. void *key, void *value, __u32 key_size, __u32 value_size,
  274. __u32 *flags, __u32 **value_fd)
  275. {
  276. if (!*argv) {
  277. if (!key && !value)
  278. return 0;
  279. p_err("did not find %s", key ? "key" : "value");
  280. return -1;
  281. }
  282. if (is_prefix(*argv, "key")) {
  283. if (!key) {
  284. if (key_size)
  285. p_err("duplicate key");
  286. else
  287. p_err("unnecessary key");
  288. return -1;
  289. }
  290. argv = parse_bytes(argv + 1, "key", key, key_size);
  291. if (!argv)
  292. return -1;
  293. return parse_elem(argv, info, NULL, value, key_size, value_size,
  294. flags, value_fd);
  295. } else if (is_prefix(*argv, "value")) {
  296. int fd;
  297. if (!value) {
  298. if (value_size)
  299. p_err("duplicate value");
  300. else
  301. p_err("unnecessary value");
  302. return -1;
  303. }
  304. argv++;
  305. if (map_is_map_of_maps(info->type)) {
  306. int argc = 2;
  307. if (value_size != 4) {
  308. p_err("value smaller than 4B for map in map?");
  309. return -1;
  310. }
  311. if (!argv[0] || !argv[1]) {
  312. p_err("not enough value arguments for map in map");
  313. return -1;
  314. }
  315. fd = map_parse_fd(&argc, &argv);
  316. if (fd < 0)
  317. return -1;
  318. *value_fd = value;
  319. **value_fd = fd;
  320. } else if (map_is_map_of_progs(info->type)) {
  321. int argc = 2;
  322. if (value_size != 4) {
  323. p_err("value smaller than 4B for map of progs?");
  324. return -1;
  325. }
  326. if (!argv[0] || !argv[1]) {
  327. p_err("not enough value arguments for map of progs");
  328. return -1;
  329. }
  330. if (is_prefix(*argv, "id"))
  331. p_info("Warning: updating program array via MAP_ID, make sure this map is kept open\n"
  332. " by some process or pinned otherwise update will be lost");
  333. fd = prog_parse_fd(&argc, &argv);
  334. if (fd < 0)
  335. return -1;
  336. *value_fd = value;
  337. **value_fd = fd;
  338. } else {
  339. argv = parse_bytes(argv, "value", value, value_size);
  340. if (!argv)
  341. return -1;
  342. fill_per_cpu_value(info, value);
  343. }
  344. return parse_elem(argv, info, key, NULL, key_size, value_size,
  345. flags, NULL);
  346. } else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") ||
  347. is_prefix(*argv, "exist")) {
  348. if (!flags) {
  349. p_err("flags specified multiple times: %s", *argv);
  350. return -1;
  351. }
  352. if (is_prefix(*argv, "any"))
  353. *flags = BPF_ANY;
  354. else if (is_prefix(*argv, "noexist"))
  355. *flags = BPF_NOEXIST;
  356. else if (is_prefix(*argv, "exist"))
  357. *flags = BPF_EXIST;
  358. return parse_elem(argv + 1, info, key, value, key_size,
  359. value_size, NULL, value_fd);
  360. }
  361. p_err("expected key or value, got: %s", *argv);
  362. return -1;
  363. }
  364. static void show_map_header_json(struct bpf_map_info *info, json_writer_t *wtr)
  365. {
  366. const char *map_type_str;
  367. jsonw_uint_field(wtr, "id", info->id);
  368. map_type_str = libbpf_bpf_map_type_str(info->type);
  369. if (map_type_str)
  370. jsonw_string_field(wtr, "type", map_type_str);
  371. else
  372. jsonw_uint_field(wtr, "type", info->type);
  373. if (*info->name)
  374. jsonw_string_field(wtr, "name", info->name);
  375. jsonw_name(wtr, "flags");
  376. jsonw_printf(wtr, "%d", info->map_flags);
  377. }
  378. static int show_map_close_json(int fd, struct bpf_map_info *info)
  379. {
  380. char *memlock, *frozen_str;
  381. int frozen = 0;
  382. memlock = get_fdinfo(fd, "memlock");
  383. frozen_str = get_fdinfo(fd, "frozen");
  384. jsonw_start_object(json_wtr);
  385. show_map_header_json(info, json_wtr);
  386. print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
  387. jsonw_uint_field(json_wtr, "bytes_key", info->key_size);
  388. jsonw_uint_field(json_wtr, "bytes_value", info->value_size);
  389. jsonw_uint_field(json_wtr, "max_entries", info->max_entries);
  390. if (memlock)
  391. jsonw_int_field(json_wtr, "bytes_memlock", atoll(memlock));
  392. free(memlock);
  393. if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
  394. char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
  395. char *owner_jited = get_fdinfo(fd, "owner_jited");
  396. if (owner_prog_type) {
  397. unsigned int prog_type = atoi(owner_prog_type);
  398. const char *prog_type_str;
  399. prog_type_str = libbpf_bpf_prog_type_str(prog_type);
  400. if (prog_type_str)
  401. jsonw_string_field(json_wtr, "owner_prog_type",
  402. prog_type_str);
  403. else
  404. jsonw_uint_field(json_wtr, "owner_prog_type",
  405. prog_type);
  406. }
  407. if (owner_jited)
  408. jsonw_bool_field(json_wtr, "owner_jited",
  409. !!atoi(owner_jited));
  410. free(owner_prog_type);
  411. free(owner_jited);
  412. }
  413. close(fd);
  414. if (frozen_str) {
  415. frozen = atoi(frozen_str);
  416. free(frozen_str);
  417. }
  418. jsonw_int_field(json_wtr, "frozen", frozen);
  419. if (info->btf_id)
  420. jsonw_int_field(json_wtr, "btf_id", info->btf_id);
  421. if (!hashmap__empty(map_table)) {
  422. struct hashmap_entry *entry;
  423. jsonw_name(json_wtr, "pinned");
  424. jsonw_start_array(json_wtr);
  425. hashmap__for_each_key_entry(map_table, entry,
  426. u32_as_hash_field(info->id))
  427. jsonw_string(json_wtr, entry->value);
  428. jsonw_end_array(json_wtr);
  429. }
  430. emit_obj_refs_json(refs_table, info->id, json_wtr);
  431. jsonw_end_object(json_wtr);
  432. return 0;
  433. }
  434. static void show_map_header_plain(struct bpf_map_info *info)
  435. {
  436. const char *map_type_str;
  437. printf("%u: ", info->id);
  438. map_type_str = libbpf_bpf_map_type_str(info->type);
  439. if (map_type_str)
  440. printf("%s ", map_type_str);
  441. else
  442. printf("type %u ", info->type);
  443. if (*info->name)
  444. printf("name %s ", info->name);
  445. printf("flags 0x%x", info->map_flags);
  446. print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
  447. printf("\n");
  448. }
  449. static int show_map_close_plain(int fd, struct bpf_map_info *info)
  450. {
  451. char *memlock, *frozen_str;
  452. int frozen = 0;
  453. memlock = get_fdinfo(fd, "memlock");
  454. frozen_str = get_fdinfo(fd, "frozen");
  455. show_map_header_plain(info);
  456. printf("\tkey %uB value %uB max_entries %u",
  457. info->key_size, info->value_size, info->max_entries);
  458. if (memlock)
  459. printf(" memlock %sB", memlock);
  460. free(memlock);
  461. if (info->type == BPF_MAP_TYPE_PROG_ARRAY) {
  462. char *owner_prog_type = get_fdinfo(fd, "owner_prog_type");
  463. char *owner_jited = get_fdinfo(fd, "owner_jited");
  464. if (owner_prog_type || owner_jited)
  465. printf("\n\t");
  466. if (owner_prog_type) {
  467. unsigned int prog_type = atoi(owner_prog_type);
  468. const char *prog_type_str;
  469. prog_type_str = libbpf_bpf_prog_type_str(prog_type);
  470. if (prog_type_str)
  471. printf("owner_prog_type %s ", prog_type_str);
  472. else
  473. printf("owner_prog_type %d ", prog_type);
  474. }
  475. if (owner_jited)
  476. printf("owner%s jited",
  477. atoi(owner_jited) ? "" : " not");
  478. free(owner_prog_type);
  479. free(owner_jited);
  480. }
  481. close(fd);
  482. if (!hashmap__empty(map_table)) {
  483. struct hashmap_entry *entry;
  484. hashmap__for_each_key_entry(map_table, entry,
  485. u32_as_hash_field(info->id))
  486. printf("\n\tpinned %s", (char *)entry->value);
  487. }
  488. if (frozen_str) {
  489. frozen = atoi(frozen_str);
  490. free(frozen_str);
  491. }
  492. if (info->btf_id || frozen)
  493. printf("\n\t");
  494. if (info->btf_id)
  495. printf("btf_id %d", info->btf_id);
  496. if (frozen)
  497. printf("%sfrozen", info->btf_id ? " " : "");
  498. emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
  499. printf("\n");
  500. return 0;
  501. }
  502. static int do_show_subset(int argc, char **argv)
  503. {
  504. struct bpf_map_info info = {};
  505. __u32 len = sizeof(info);
  506. int *fds = NULL;
  507. int nb_fds, i;
  508. int err = -1;
  509. fds = malloc(sizeof(int));
  510. if (!fds) {
  511. p_err("mem alloc failed");
  512. return -1;
  513. }
  514. nb_fds = map_parse_fds(&argc, &argv, &fds);
  515. if (nb_fds < 1)
  516. goto exit_free;
  517. if (json_output && nb_fds > 1)
  518. jsonw_start_array(json_wtr); /* root array */
  519. for (i = 0; i < nb_fds; i++) {
  520. err = bpf_obj_get_info_by_fd(fds[i], &info, &len);
  521. if (err) {
  522. p_err("can't get map info: %s",
  523. strerror(errno));
  524. for (; i < nb_fds; i++)
  525. close(fds[i]);
  526. break;
  527. }
  528. if (json_output)
  529. show_map_close_json(fds[i], &info);
  530. else
  531. show_map_close_plain(fds[i], &info);
  532. close(fds[i]);
  533. }
  534. if (json_output && nb_fds > 1)
  535. jsonw_end_array(json_wtr); /* root array */
  536. exit_free:
  537. free(fds);
  538. return err;
  539. }
  540. static int do_show(int argc, char **argv)
  541. {
  542. struct bpf_map_info info = {};
  543. __u32 len = sizeof(info);
  544. __u32 id = 0;
  545. int err;
  546. int fd;
  547. if (show_pinned) {
  548. map_table = hashmap__new(hash_fn_for_key_as_id,
  549. equal_fn_for_key_as_id, NULL);
  550. if (IS_ERR(map_table)) {
  551. p_err("failed to create hashmap for pinned paths");
  552. return -1;
  553. }
  554. build_pinned_obj_table(map_table, BPF_OBJ_MAP);
  555. }
  556. build_obj_refs_table(&refs_table, BPF_OBJ_MAP);
  557. if (argc == 2)
  558. return do_show_subset(argc, argv);
  559. if (argc)
  560. return BAD_ARG();
  561. if (json_output)
  562. jsonw_start_array(json_wtr);
  563. while (true) {
  564. err = bpf_map_get_next_id(id, &id);
  565. if (err) {
  566. if (errno == ENOENT)
  567. break;
  568. p_err("can't get next map: %s%s", strerror(errno),
  569. errno == EINVAL ? " -- kernel too old?" : "");
  570. break;
  571. }
  572. fd = bpf_map_get_fd_by_id(id);
  573. if (fd < 0) {
  574. if (errno == ENOENT)
  575. continue;
  576. p_err("can't get map by id (%u): %s",
  577. id, strerror(errno));
  578. break;
  579. }
  580. err = bpf_obj_get_info_by_fd(fd, &info, &len);
  581. if (err) {
  582. p_err("can't get map info: %s", strerror(errno));
  583. close(fd);
  584. break;
  585. }
  586. if (json_output)
  587. show_map_close_json(fd, &info);
  588. else
  589. show_map_close_plain(fd, &info);
  590. }
  591. if (json_output)
  592. jsonw_end_array(json_wtr);
  593. delete_obj_refs_table(refs_table);
  594. if (show_pinned)
  595. delete_pinned_obj_table(map_table);
  596. return errno == ENOENT ? 0 : -1;
  597. }
  598. static int dump_map_elem(int fd, void *key, void *value,
  599. struct bpf_map_info *map_info, struct btf *btf,
  600. json_writer_t *btf_wtr)
  601. {
  602. if (bpf_map_lookup_elem(fd, key, value)) {
  603. print_entry_error(map_info, key, errno);
  604. return -1;
  605. }
  606. if (json_output) {
  607. print_entry_json(map_info, key, value, btf);
  608. } else if (btf) {
  609. struct btf_dumper d = {
  610. .btf = btf,
  611. .jw = btf_wtr,
  612. .is_plain_text = true,
  613. };
  614. do_dump_btf(&d, map_info, key, value);
  615. } else {
  616. print_entry_plain(map_info, key, value);
  617. }
  618. return 0;
  619. }
  620. static int maps_have_btf(int *fds, int nb_fds)
  621. {
  622. struct bpf_map_info info = {};
  623. __u32 len = sizeof(info);
  624. int err, i;
  625. for (i = 0; i < nb_fds; i++) {
  626. err = bpf_obj_get_info_by_fd(fds[i], &info, &len);
  627. if (err) {
  628. p_err("can't get map info: %s", strerror(errno));
  629. return -1;
  630. }
  631. if (!info.btf_id)
  632. return 0;
  633. }
  634. return 1;
  635. }
  636. static struct btf *btf_vmlinux;
  637. static int get_map_kv_btf(const struct bpf_map_info *info, struct btf **btf)
  638. {
  639. int err = 0;
  640. if (info->btf_vmlinux_value_type_id) {
  641. if (!btf_vmlinux) {
  642. btf_vmlinux = libbpf_find_kernel_btf();
  643. err = libbpf_get_error(btf_vmlinux);
  644. if (err) {
  645. p_err("failed to get kernel btf");
  646. return err;
  647. }
  648. }
  649. *btf = btf_vmlinux;
  650. } else if (info->btf_value_type_id) {
  651. *btf = btf__load_from_kernel_by_id(info->btf_id);
  652. err = libbpf_get_error(*btf);
  653. if (err)
  654. p_err("failed to get btf");
  655. } else {
  656. *btf = NULL;
  657. }
  658. return err;
  659. }
  660. static void free_map_kv_btf(struct btf *btf)
  661. {
  662. if (!libbpf_get_error(btf) && btf != btf_vmlinux)
  663. btf__free(btf);
  664. }
  665. static void free_btf_vmlinux(void)
  666. {
  667. if (!libbpf_get_error(btf_vmlinux))
  668. btf__free(btf_vmlinux);
  669. }
  670. static int
  671. map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
  672. bool show_header)
  673. {
  674. void *key, *value, *prev_key;
  675. unsigned int num_elems = 0;
  676. struct btf *btf = NULL;
  677. int err;
  678. key = malloc(info->key_size);
  679. value = alloc_value(info);
  680. if (!key || !value) {
  681. p_err("mem alloc failed");
  682. err = -1;
  683. goto exit_free;
  684. }
  685. prev_key = NULL;
  686. if (wtr) {
  687. err = get_map_kv_btf(info, &btf);
  688. if (err) {
  689. goto exit_free;
  690. }
  691. if (show_header) {
  692. jsonw_start_object(wtr); /* map object */
  693. show_map_header_json(info, wtr);
  694. jsonw_name(wtr, "elements");
  695. }
  696. jsonw_start_array(wtr); /* elements */
  697. } else if (show_header) {
  698. show_map_header_plain(info);
  699. }
  700. if (info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY &&
  701. info->value_size != 8) {
  702. const char *map_type_str;
  703. map_type_str = libbpf_bpf_map_type_str(info->type);
  704. p_info("Warning: cannot read values from %s map with value_size != 8",
  705. map_type_str);
  706. }
  707. while (true) {
  708. err = bpf_map_get_next_key(fd, prev_key, key);
  709. if (err) {
  710. if (errno == ENOENT)
  711. err = 0;
  712. break;
  713. }
  714. if (!dump_map_elem(fd, key, value, info, btf, wtr))
  715. num_elems++;
  716. prev_key = key;
  717. }
  718. if (wtr) {
  719. jsonw_end_array(wtr); /* elements */
  720. if (show_header)
  721. jsonw_end_object(wtr); /* map object */
  722. } else {
  723. printf("Found %u element%s\n", num_elems,
  724. num_elems != 1 ? "s" : "");
  725. }
  726. exit_free:
  727. free(key);
  728. free(value);
  729. close(fd);
  730. free_map_kv_btf(btf);
  731. return err;
  732. }
  733. static int do_dump(int argc, char **argv)
  734. {
  735. json_writer_t *wtr = NULL, *btf_wtr = NULL;
  736. struct bpf_map_info info = {};
  737. int nb_fds, i = 0;
  738. __u32 len = sizeof(info);
  739. int *fds = NULL;
  740. int err = -1;
  741. if (argc != 2)
  742. usage();
  743. fds = malloc(sizeof(int));
  744. if (!fds) {
  745. p_err("mem alloc failed");
  746. return -1;
  747. }
  748. nb_fds = map_parse_fds(&argc, &argv, &fds);
  749. if (nb_fds < 1)
  750. goto exit_free;
  751. if (json_output) {
  752. wtr = json_wtr;
  753. } else {
  754. int do_plain_btf;
  755. do_plain_btf = maps_have_btf(fds, nb_fds);
  756. if (do_plain_btf < 0)
  757. goto exit_close;
  758. if (do_plain_btf) {
  759. btf_wtr = get_btf_writer();
  760. wtr = btf_wtr;
  761. if (!btf_wtr)
  762. p_info("failed to create json writer for btf. falling back to plain output");
  763. }
  764. }
  765. if (wtr && nb_fds > 1)
  766. jsonw_start_array(wtr); /* root array */
  767. for (i = 0; i < nb_fds; i++) {
  768. if (bpf_obj_get_info_by_fd(fds[i], &info, &len)) {
  769. p_err("can't get map info: %s", strerror(errno));
  770. break;
  771. }
  772. err = map_dump(fds[i], &info, wtr, nb_fds > 1);
  773. if (!wtr && i != nb_fds - 1)
  774. printf("\n");
  775. if (err)
  776. break;
  777. close(fds[i]);
  778. }
  779. if (wtr && nb_fds > 1)
  780. jsonw_end_array(wtr); /* root array */
  781. if (btf_wtr)
  782. jsonw_destroy(&btf_wtr);
  783. exit_close:
  784. for (; i < nb_fds; i++)
  785. close(fds[i]);
  786. exit_free:
  787. free(fds);
  788. free_btf_vmlinux();
  789. return err;
  790. }
  791. static int alloc_key_value(struct bpf_map_info *info, void **key, void **value)
  792. {
  793. *key = NULL;
  794. *value = NULL;
  795. if (info->key_size) {
  796. *key = malloc(info->key_size);
  797. if (!*key) {
  798. p_err("key mem alloc failed");
  799. return -1;
  800. }
  801. }
  802. if (info->value_size) {
  803. *value = alloc_value(info);
  804. if (!*value) {
  805. p_err("value mem alloc failed");
  806. free(*key);
  807. *key = NULL;
  808. return -1;
  809. }
  810. }
  811. return 0;
  812. }
  813. static int do_update(int argc, char **argv)
  814. {
  815. struct bpf_map_info info = {};
  816. __u32 len = sizeof(info);
  817. __u32 *value_fd = NULL;
  818. __u32 flags = BPF_ANY;
  819. void *key, *value;
  820. int fd, err;
  821. if (argc < 2)
  822. usage();
  823. fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
  824. if (fd < 0)
  825. return -1;
  826. err = alloc_key_value(&info, &key, &value);
  827. if (err)
  828. goto exit_free;
  829. err = parse_elem(argv, &info, key, value, info.key_size,
  830. info.value_size, &flags, &value_fd);
  831. if (err)
  832. goto exit_free;
  833. err = bpf_map_update_elem(fd, key, value, flags);
  834. if (err) {
  835. p_err("update failed: %s", strerror(errno));
  836. goto exit_free;
  837. }
  838. exit_free:
  839. if (value_fd)
  840. close(*value_fd);
  841. free(key);
  842. free(value);
  843. close(fd);
  844. if (!err && json_output)
  845. jsonw_null(json_wtr);
  846. return err;
  847. }
  848. static void print_key_value(struct bpf_map_info *info, void *key,
  849. void *value)
  850. {
  851. json_writer_t *btf_wtr;
  852. struct btf *btf;
  853. if (get_map_kv_btf(info, &btf))
  854. return;
  855. if (json_output) {
  856. print_entry_json(info, key, value, btf);
  857. } else if (btf) {
  858. /* if here json_wtr wouldn't have been initialised,
  859. * so let's create separate writer for btf
  860. */
  861. btf_wtr = get_btf_writer();
  862. if (!btf_wtr) {
  863. p_info("failed to create json writer for btf. falling back to plain output");
  864. btf__free(btf);
  865. btf = NULL;
  866. print_entry_plain(info, key, value);
  867. } else {
  868. struct btf_dumper d = {
  869. .btf = btf,
  870. .jw = btf_wtr,
  871. .is_plain_text = true,
  872. };
  873. do_dump_btf(&d, info, key, value);
  874. jsonw_destroy(&btf_wtr);
  875. }
  876. } else {
  877. print_entry_plain(info, key, value);
  878. }
  879. btf__free(btf);
  880. }
  881. static int do_lookup(int argc, char **argv)
  882. {
  883. struct bpf_map_info info = {};
  884. __u32 len = sizeof(info);
  885. void *key, *value;
  886. int err;
  887. int fd;
  888. if (argc < 2)
  889. usage();
  890. fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
  891. if (fd < 0)
  892. return -1;
  893. err = alloc_key_value(&info, &key, &value);
  894. if (err)
  895. goto exit_free;
  896. err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
  897. if (err)
  898. goto exit_free;
  899. err = bpf_map_lookup_elem(fd, key, value);
  900. if (err) {
  901. if (errno == ENOENT) {
  902. if (json_output) {
  903. jsonw_null(json_wtr);
  904. } else {
  905. printf("key:\n");
  906. fprint_hex(stdout, key, info.key_size, " ");
  907. printf("\n\nNot found\n");
  908. }
  909. } else {
  910. p_err("lookup failed: %s", strerror(errno));
  911. }
  912. goto exit_free;
  913. }
  914. /* here means bpf_map_lookup_elem() succeeded */
  915. print_key_value(&info, key, value);
  916. exit_free:
  917. free(key);
  918. free(value);
  919. close(fd);
  920. return err;
  921. }
  922. static int do_getnext(int argc, char **argv)
  923. {
  924. struct bpf_map_info info = {};
  925. __u32 len = sizeof(info);
  926. void *key, *nextkey;
  927. int err;
  928. int fd;
  929. if (argc < 2)
  930. usage();
  931. fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
  932. if (fd < 0)
  933. return -1;
  934. key = malloc(info.key_size);
  935. nextkey = malloc(info.key_size);
  936. if (!key || !nextkey) {
  937. p_err("mem alloc failed");
  938. err = -1;
  939. goto exit_free;
  940. }
  941. if (argc) {
  942. err = parse_elem(argv, &info, key, NULL, info.key_size, 0,
  943. NULL, NULL);
  944. if (err)
  945. goto exit_free;
  946. } else {
  947. free(key);
  948. key = NULL;
  949. }
  950. err = bpf_map_get_next_key(fd, key, nextkey);
  951. if (err) {
  952. p_err("can't get next key: %s", strerror(errno));
  953. goto exit_free;
  954. }
  955. if (json_output) {
  956. jsonw_start_object(json_wtr);
  957. if (key) {
  958. jsonw_name(json_wtr, "key");
  959. print_hex_data_json(key, info.key_size);
  960. } else {
  961. jsonw_null_field(json_wtr, "key");
  962. }
  963. jsonw_name(json_wtr, "next_key");
  964. print_hex_data_json(nextkey, info.key_size);
  965. jsonw_end_object(json_wtr);
  966. } else {
  967. if (key) {
  968. printf("key:\n");
  969. fprint_hex(stdout, key, info.key_size, " ");
  970. printf("\n");
  971. } else {
  972. printf("key: None\n");
  973. }
  974. printf("next key:\n");
  975. fprint_hex(stdout, nextkey, info.key_size, " ");
  976. printf("\n");
  977. }
  978. exit_free:
  979. free(nextkey);
  980. free(key);
  981. close(fd);
  982. return err;
  983. }
  984. static int do_delete(int argc, char **argv)
  985. {
  986. struct bpf_map_info info = {};
  987. __u32 len = sizeof(info);
  988. void *key;
  989. int err;
  990. int fd;
  991. if (argc < 2)
  992. usage();
  993. fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
  994. if (fd < 0)
  995. return -1;
  996. key = malloc(info.key_size);
  997. if (!key) {
  998. p_err("mem alloc failed");
  999. err = -1;
  1000. goto exit_free;
  1001. }
  1002. err = parse_elem(argv, &info, key, NULL, info.key_size, 0, NULL, NULL);
  1003. if (err)
  1004. goto exit_free;
  1005. err = bpf_map_delete_elem(fd, key);
  1006. if (err)
  1007. p_err("delete failed: %s", strerror(errno));
  1008. exit_free:
  1009. free(key);
  1010. close(fd);
  1011. if (!err && json_output)
  1012. jsonw_null(json_wtr);
  1013. return err;
  1014. }
  1015. static int do_pin(int argc, char **argv)
  1016. {
  1017. int err;
  1018. err = do_pin_any(argc, argv, map_parse_fd);
  1019. if (!err && json_output)
  1020. jsonw_null(json_wtr);
  1021. return err;
  1022. }
  1023. static int do_create(int argc, char **argv)
  1024. {
  1025. LIBBPF_OPTS(bpf_map_create_opts, attr);
  1026. enum bpf_map_type map_type = BPF_MAP_TYPE_UNSPEC;
  1027. __u32 key_size = 0, value_size = 0, max_entries = 0;
  1028. const char *map_name = NULL;
  1029. const char *pinfile;
  1030. int err = -1, fd;
  1031. if (!REQ_ARGS(7))
  1032. return -1;
  1033. pinfile = GET_ARG();
  1034. while (argc) {
  1035. if (!REQ_ARGS(2))
  1036. return -1;
  1037. if (is_prefix(*argv, "type")) {
  1038. NEXT_ARG();
  1039. if (map_type) {
  1040. p_err("map type already specified");
  1041. goto exit;
  1042. }
  1043. map_type = map_type_from_str(*argv);
  1044. if ((int)map_type < 0) {
  1045. p_err("unrecognized map type: %s", *argv);
  1046. goto exit;
  1047. }
  1048. NEXT_ARG();
  1049. } else if (is_prefix(*argv, "name")) {
  1050. NEXT_ARG();
  1051. map_name = GET_ARG();
  1052. } else if (is_prefix(*argv, "key")) {
  1053. if (parse_u32_arg(&argc, &argv, &key_size,
  1054. "key size"))
  1055. goto exit;
  1056. } else if (is_prefix(*argv, "value")) {
  1057. if (parse_u32_arg(&argc, &argv, &value_size,
  1058. "value size"))
  1059. goto exit;
  1060. } else if (is_prefix(*argv, "entries")) {
  1061. if (parse_u32_arg(&argc, &argv, &max_entries,
  1062. "max entries"))
  1063. goto exit;
  1064. } else if (is_prefix(*argv, "flags")) {
  1065. if (parse_u32_arg(&argc, &argv, &attr.map_flags,
  1066. "flags"))
  1067. goto exit;
  1068. } else if (is_prefix(*argv, "dev")) {
  1069. NEXT_ARG();
  1070. if (attr.map_ifindex) {
  1071. p_err("offload device already specified");
  1072. goto exit;
  1073. }
  1074. attr.map_ifindex = if_nametoindex(*argv);
  1075. if (!attr.map_ifindex) {
  1076. p_err("unrecognized netdevice '%s': %s",
  1077. *argv, strerror(errno));
  1078. goto exit;
  1079. }
  1080. NEXT_ARG();
  1081. } else if (is_prefix(*argv, "inner_map")) {
  1082. struct bpf_map_info info = {};
  1083. __u32 len = sizeof(info);
  1084. int inner_map_fd;
  1085. NEXT_ARG();
  1086. if (!REQ_ARGS(2))
  1087. usage();
  1088. inner_map_fd = map_parse_fd_and_info(&argc, &argv,
  1089. &info, &len);
  1090. if (inner_map_fd < 0)
  1091. return -1;
  1092. attr.inner_map_fd = inner_map_fd;
  1093. } else {
  1094. p_err("unknown arg %s", *argv);
  1095. goto exit;
  1096. }
  1097. }
  1098. if (!map_name) {
  1099. p_err("map name not specified");
  1100. goto exit;
  1101. }
  1102. set_max_rlimit();
  1103. fd = bpf_map_create(map_type, map_name, key_size, value_size, max_entries, &attr);
  1104. if (fd < 0) {
  1105. p_err("map create failed: %s", strerror(errno));
  1106. goto exit;
  1107. }
  1108. err = do_pin_fd(fd, pinfile);
  1109. close(fd);
  1110. if (err)
  1111. goto exit;
  1112. if (json_output)
  1113. jsonw_null(json_wtr);
  1114. exit:
  1115. if (attr.inner_map_fd > 0)
  1116. close(attr.inner_map_fd);
  1117. return err;
  1118. }
  1119. static int do_pop_dequeue(int argc, char **argv)
  1120. {
  1121. struct bpf_map_info info = {};
  1122. __u32 len = sizeof(info);
  1123. void *key, *value;
  1124. int err;
  1125. int fd;
  1126. if (argc < 2)
  1127. usage();
  1128. fd = map_parse_fd_and_info(&argc, &argv, &info, &len);
  1129. if (fd < 0)
  1130. return -1;
  1131. err = alloc_key_value(&info, &key, &value);
  1132. if (err)
  1133. goto exit_free;
  1134. err = bpf_map_lookup_and_delete_elem(fd, key, value);
  1135. if (err) {
  1136. if (errno == ENOENT) {
  1137. if (json_output)
  1138. jsonw_null(json_wtr);
  1139. else
  1140. printf("Error: empty map\n");
  1141. } else {
  1142. p_err("pop failed: %s", strerror(errno));
  1143. }
  1144. goto exit_free;
  1145. }
  1146. print_key_value(&info, key, value);
  1147. exit_free:
  1148. free(key);
  1149. free(value);
  1150. close(fd);
  1151. return err;
  1152. }
  1153. static int do_freeze(int argc, char **argv)
  1154. {
  1155. int err, fd;
  1156. if (!REQ_ARGS(2))
  1157. return -1;
  1158. fd = map_parse_fd(&argc, &argv);
  1159. if (fd < 0)
  1160. return -1;
  1161. if (argc) {
  1162. close(fd);
  1163. return BAD_ARG();
  1164. }
  1165. err = bpf_map_freeze(fd);
  1166. close(fd);
  1167. if (err) {
  1168. p_err("failed to freeze map: %s", strerror(errno));
  1169. return err;
  1170. }
  1171. if (json_output)
  1172. jsonw_null(json_wtr);
  1173. return 0;
  1174. }
  1175. static int do_help(int argc, char **argv)
  1176. {
  1177. if (json_output) {
  1178. jsonw_null(json_wtr);
  1179. return 0;
  1180. }
  1181. fprintf(stderr,
  1182. "Usage: %1$s %2$s { show | list } [MAP]\n"
  1183. " %1$s %2$s create FILE type TYPE key KEY_SIZE value VALUE_SIZE \\\n"
  1184. " entries MAX_ENTRIES name NAME [flags FLAGS] \\\n"
  1185. " [inner_map MAP] [dev NAME]\n"
  1186. " %1$s %2$s dump MAP\n"
  1187. " %1$s %2$s update MAP [key DATA] [value VALUE] [UPDATE_FLAGS]\n"
  1188. " %1$s %2$s lookup MAP [key DATA]\n"
  1189. " %1$s %2$s getnext MAP [key DATA]\n"
  1190. " %1$s %2$s delete MAP key DATA\n"
  1191. " %1$s %2$s pin MAP FILE\n"
  1192. " %1$s %2$s event_pipe MAP [cpu N index M]\n"
  1193. " %1$s %2$s peek MAP\n"
  1194. " %1$s %2$s push MAP value VALUE\n"
  1195. " %1$s %2$s pop MAP\n"
  1196. " %1$s %2$s enqueue MAP value VALUE\n"
  1197. " %1$s %2$s dequeue MAP\n"
  1198. " %1$s %2$s freeze MAP\n"
  1199. " %1$s %2$s help\n"
  1200. "\n"
  1201. " " HELP_SPEC_MAP "\n"
  1202. " DATA := { [hex] BYTES }\n"
  1203. " " HELP_SPEC_PROGRAM "\n"
  1204. " VALUE := { DATA | MAP | PROG }\n"
  1205. " UPDATE_FLAGS := { any | exist | noexist }\n"
  1206. " TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
  1207. " percpu_array | stack_trace | cgroup_array | lru_hash |\n"
  1208. " lru_percpu_hash | lpm_trie | array_of_maps | hash_of_maps |\n"
  1209. " devmap | devmap_hash | sockmap | cpumap | xskmap | sockhash |\n"
  1210. " cgroup_storage | reuseport_sockarray | percpu_cgroup_storage |\n"
  1211. " queue | stack | sk_storage | struct_ops | ringbuf | inode_storage |\n"
  1212. " task_storage | bloom_filter | user_ringbuf }\n"
  1213. " " HELP_SPEC_OPTIONS " |\n"
  1214. " {-f|--bpffs} | {-n|--nomount} }\n"
  1215. "",
  1216. bin_name, argv[-2]);
  1217. return 0;
  1218. }
  1219. static const struct cmd cmds[] = {
  1220. { "show", do_show },
  1221. { "list", do_show },
  1222. { "help", do_help },
  1223. { "dump", do_dump },
  1224. { "update", do_update },
  1225. { "lookup", do_lookup },
  1226. { "getnext", do_getnext },
  1227. { "delete", do_delete },
  1228. { "pin", do_pin },
  1229. { "event_pipe", do_event_pipe },
  1230. { "create", do_create },
  1231. { "peek", do_lookup },
  1232. { "push", do_update },
  1233. { "enqueue", do_update },
  1234. { "pop", do_pop_dequeue },
  1235. { "dequeue", do_pop_dequeue },
  1236. { "freeze", do_freeze },
  1237. { 0 }
  1238. };
  1239. int do_map(int argc, char **argv)
  1240. {
  1241. return cmd_select(cmds, argc, argv, do_help);
  1242. }