Fix build break in 64bit architectures
[platform/upstream/iproute2.git] / tc / e_bpf.c
1 /*
2  * e_bpf.c      BPF exec proxy
3  *
4  *              This program is free software; you can distribute it and/or
5  *              modify it under the terms of the GNU General Public License
6  *              as published by the Free Software Foundation; either version
7  *              2 of the License, or (at your option) any later version.
8  *
9  * Authors:     Daniel Borkmann <daniel@iogearbox.net>
10  */
11
12 #include <stdio.h>
13 #include <unistd.h>
14
15 #include "utils.h"
16
17 #include "tc_util.h"
18
19 #include "bpf_util.h"
20 #include "bpf_elf.h"
21 #include "bpf_scm.h"
22
23 #define BPF_DEFAULT_CMD "/bin/sh"
24
25 static char *argv_default[] = { BPF_DEFAULT_CMD, NULL };
26
27 static void explain(void)
28 {
29         fprintf(stderr,
30                 "Usage: ... bpf [ import UDS_FILE ] [ run CMD ]\n"
31                 "       ... bpf [ debug ]\n"
32                 "       ... bpf [ graft MAP_FILE ] [ key KEY ]\n"
33                 "          `... [ object-file OBJ_FILE ] [ type TYPE ] [ section NAME ] [ verbose ]\n"
34                 "          `... [ object-pinned PROG_FILE ]\n"
35                 "\n"
36                 "Where UDS_FILE provides the name of a unix domain socket file\n"
37                 "to import eBPF maps and the optional CMD denotes the command\n"
38                 "to be executed (default: \'%s\').\n"
39                 "Where MAP_FILE points to a pinned map, OBJ_FILE to an object file\n"
40                 "and PROG_FILE to a pinned program. TYPE can be {cls, act}, where\n"
41                 "\'cls\' is default. KEY is optional and can be inferred from the\n"
42                 "section name, otherwise it needs to be provided.\n",
43                 BPF_DEFAULT_CMD);
44 }
45
46 static int bpf_num_env_entries(void)
47 {
48         char **envp;
49         int num;
50
51         for (num = 0, envp = environ; *envp != NULL; envp++)
52                 num++;
53         return num;
54 }
55
56 static int parse_bpf(struct exec_util *eu, int argc, char **argv)
57 {
58         char **argv_run = argv_default, **envp_run, *tmp;
59         int ret, i, env_old, env_num, env_map;
60         const char *bpf_uds_name = NULL;
61         int fds[BPF_SCM_MAX_FDS] = {};
62         struct bpf_map_aux aux = {};
63
64         if (argc == 0)
65                 return 0;
66
67         while (argc > 0) {
68                 if (matches(*argv, "run") == 0) {
69                         NEXT_ARG();
70                         argv_run = argv;
71                         break;
72                 } else if (matches(*argv, "import") == 0) {
73                         NEXT_ARG();
74                         bpf_uds_name = *argv;
75                 } else if (matches(*argv, "debug") == 0 ||
76                            matches(*argv, "dbg") == 0) {
77                         if (bpf_trace_pipe())
78                                 fprintf(stderr,
79                                         "No trace pipe, tracefs not mounted?\n");
80                         return -1;
81                 } else if (matches(*argv, "graft") == 0) {
82                         const char *bpf_map_path;
83                         bool has_key = false;
84                         uint32_t key;
85
86                         NEXT_ARG();
87                         bpf_map_path = *argv;
88                         NEXT_ARG();
89                         if (matches(*argv, "key") == 0) {
90                                 NEXT_ARG();
91                                 if (get_unsigned(&key, *argv, 0)) {
92                                         fprintf(stderr, "Illegal \"key\"\n");
93                                         return -1;
94                                 }
95                                 has_key = true;
96                                 NEXT_ARG();
97                         }
98                         return bpf_graft_map(bpf_map_path, has_key ?
99                                              &key : NULL, argc, argv);
100                 } else {
101                         explain();
102                         return -1;
103                 }
104
105                 NEXT_ARG_FWD();
106         }
107
108         if (!bpf_uds_name) {
109                 fprintf(stderr, "bpf: No import parameter provided!\n");
110                 explain();
111                 return -1;
112         }
113
114         if (argv_run != argv_default && argc == 0) {
115                 fprintf(stderr, "bpf: No run command provided!\n");
116                 explain();
117                 return -1;
118         }
119
120         ret = bpf_recv_map_fds(bpf_uds_name, fds, &aux, ARRAY_SIZE(fds));
121         if (ret < 0) {
122                 fprintf(stderr, "bpf: Could not receive fds!\n");
123                 return -1;
124         }
125
126         if (aux.num_ent == 0) {
127                 envp_run = environ;
128                 goto out;
129         }
130
131         env_old = bpf_num_env_entries();
132         env_num = env_old + aux.num_ent + 2;
133         env_map = env_old + 1;
134
135         envp_run = malloc(sizeof(*envp_run) * env_num);
136         if (!envp_run) {
137                 fprintf(stderr, "bpf: No memory left to allocate env!\n");
138                 goto err;
139         }
140
141         for (i = 0; i < env_old; i++)
142                 envp_run[i] = environ[i];
143
144         ret = asprintf(&tmp, "BPF_NUM_MAPS=%u", aux.num_ent);
145         if (ret < 0)
146                 goto err_free;
147
148         envp_run[env_old] = tmp;
149
150         for (i = env_map; i < env_num - 1; i++) {
151                 ret = asprintf(&tmp, "BPF_MAP%u=%u",
152                                aux.ent[i - env_map].id,
153                                fds[i - env_map]);
154                 if (ret < 0)
155                         goto err_free_env;
156
157                 envp_run[i] = tmp;
158         }
159
160         envp_run[env_num - 1] = NULL;
161 out:
162         return execvpe(argv_run[0], argv_run, envp_run);
163
164 err_free_env:
165         for (--i; i >= env_old; i--)
166                 free(envp_run[i]);
167 err_free:
168         free(envp_run);
169 err:
170         for (i = 0; i < aux.num_ent; i++)
171                 close(fds[i]);
172         return -1;
173 }
174
175 struct exec_util bpf_exec_util = {
176         .id             = "bpf",
177         .parse_eopt     = parse_bpf,
178 };