diff options
| author | Chenbo Feng <fengc@google.com> | 2017-04-05 22:00:56 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2017-04-08 11:07:01 -0400 |
| commit | 00f660eaf37808aa0a537c288c9e2dee73bd4316 (patch) | |
| tree | 566ff6609ee3fc6ff216b9c18d3118dc50b3bf30 /samples | |
| parent | 5daab9db7b65df87da26fd8cfa695fb9546a1ddb (diff) | |
Sample program using SO_COOKIE
Added a per socket traffic monitoring option to illustrate the usage
of new getsockopt SO_COOKIE. The program is based on the socket traffic
monitoring program using xt_eBPF and in the new option the data entry
can be directly accessed using socket cookie. The cookie retrieved
allow us to lookup an element in the eBPF for a specific socket.
Signed-off-by: Chenbo Feng <fengc@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'samples')
| -rw-r--r-- | samples/bpf/cookie_uid_helper_example.c | 146 | ||||
| -rwxr-xr-x[-rw-r--r--] | samples/bpf/run_cookie_uid_helper_example.sh | 4 |
2 files changed, 127 insertions, 23 deletions
diff --git a/samples/bpf/cookie_uid_helper_example.c b/samples/bpf/cookie_uid_helper_example.c index f6e5e58931c5..ad5afedf2e70 100644 --- a/samples/bpf/cookie_uid_helper_example.c +++ b/samples/bpf/cookie_uid_helper_example.c | |||
| @@ -4,10 +4,11 @@ | |||
| 4 | * program into the xt_bpf match. | 4 | * program into the xt_bpf match. |
| 5 | * | 5 | * |
| 6 | * TEST: | 6 | * TEST: |
| 7 | * ./run_cookie_uid_helper_example.sh | 7 | * ./run_cookie_uid_helper_example.sh -option |
| 8 | * Then generate some traffic in variate ways. ping 0 -c 10 would work | 8 | * option: |
| 9 | * but the cookie and uid in this case could both be 0. A sample output | 9 | * -t: do traffic monitoring test, the program will continuously |
| 10 | * with some traffic generated by web browser is shown below: | 10 | * print out network traffic happens after program started A sample |
| 11 | * output is shown below: | ||
| 11 | * | 12 | * |
| 12 | * cookie: 877, uid: 0x3e8, Pakcet Count: 20, Bytes Count: 11058 | 13 | * cookie: 877, uid: 0x3e8, Pakcet Count: 20, Bytes Count: 11058 |
| 13 | * cookie: 132, uid: 0x0, Pakcet Count: 2, Bytes Count: 286 | 14 | * cookie: 132, uid: 0x0, Pakcet Count: 2, Bytes Count: 286 |
| @@ -18,6 +19,10 @@ | |||
| 18 | * cookie: 0, uid: 0x0, Pakcet Count: 6, Bytes Count: 712 | 19 | * cookie: 0, uid: 0x0, Pakcet Count: 6, Bytes Count: 712 |
| 19 | * cookie: 880, uid: 0xfffe, Pakcet Count: 1, Bytes Count: 70 | 20 | * cookie: 880, uid: 0xfffe, Pakcet Count: 1, Bytes Count: 70 |
| 20 | * | 21 | * |
| 22 | * -s: do getsockopt SO_COOKIE test, the program will set up a pair of | ||
| 23 | * UDP sockets and send packets between them. And read out the traffic data | ||
| 24 | * directly from the ebpf map based on the socket cookie. | ||
| 25 | * | ||
| 21 | * Clean up: if using shell script, the script file will delete the iptables | 26 | * Clean up: if using shell script, the script file will delete the iptables |
| 22 | * rule and unmount the bpf program when exit. Else the iptables rule need | 27 | * rule and unmount the bpf program when exit. Else the iptables rule need |
| 23 | * to be deleted by hand, see run_cookie_uid_helper_example.sh for detail. | 28 | * to be deleted by hand, see run_cookie_uid_helper_example.sh for detail. |
| @@ -34,6 +39,8 @@ | |||
| 34 | #include <limits.h> | 39 | #include <limits.h> |
| 35 | #include <linux/bpf.h> | 40 | #include <linux/bpf.h> |
| 36 | #include <linux/if_ether.h> | 41 | #include <linux/if_ether.h> |
| 42 | #include <net/if.h> | ||
| 43 | #include <signal.h> | ||
| 37 | #include <stdbool.h> | 44 | #include <stdbool.h> |
| 38 | #include <stdint.h> | 45 | #include <stdint.h> |
| 39 | #include <stdio.h> | 46 | #include <stdio.h> |
| @@ -46,6 +53,8 @@ | |||
| 46 | #include <bpf/bpf.h> | 53 | #include <bpf/bpf.h> |
| 47 | #include "libbpf.h" | 54 | #include "libbpf.h" |
| 48 | 55 | ||
| 56 | #define PORT 8888 | ||
| 57 | |||
| 49 | struct stats { | 58 | struct stats { |
| 50 | uint32_t uid; | 59 | uint32_t uid; |
| 51 | uint64_t packets; | 60 | uint64_t packets; |
| @@ -54,6 +63,8 @@ struct stats { | |||
| 54 | 63 | ||
| 55 | static int map_fd, prog_fd; | 64 | static int map_fd, prog_fd; |
| 56 | 65 | ||
| 66 | static bool test_finish; | ||
| 67 | |||
| 57 | static void maps_create(void) | 68 | static void maps_create(void) |
| 58 | { | 69 | { |
| 59 | map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(uint32_t), | 70 | map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(uint32_t), |
| @@ -164,7 +175,7 @@ static void prog_attach_iptables(char *file) | |||
| 164 | printf("file path too long: %s\n", file); | 175 | printf("file path too long: %s\n", file); |
| 165 | exit(1); | 176 | exit(1); |
| 166 | } | 177 | } |
| 167 | sprintf(rules, "iptables -A INPUT -m bpf --object-pinned %s -j ACCEPT", | 178 | sprintf(rules, "iptables -A OUTPUT -m bpf --object-pinned %s -j ACCEPT", |
| 168 | file); | 179 | file); |
| 169 | ret = system(rules); | 180 | ret = system(rules); |
| 170 | if (ret < 0) { | 181 | if (ret < 0) { |
| @@ -177,7 +188,8 @@ static void print_table(void) | |||
| 177 | { | 188 | { |
| 178 | struct stats curEntry; | 189 | struct stats curEntry; |
| 179 | uint32_t curN = UINT32_MAX; | 190 | uint32_t curN = UINT32_MAX; |
| 180 | uint32_t nextN, res; | 191 | uint32_t nextN; |
| 192 | int res; | ||
| 181 | 193 | ||
| 182 | while (bpf_map_get_next_key(map_fd, &curN, &nextN) > -1) { | 194 | while (bpf_map_get_next_key(map_fd, &curN, &nextN) > -1) { |
| 183 | curN = nextN; | 195 | curN = nextN; |
| @@ -193,25 +205,117 @@ static void print_table(void) | |||
| 193 | } | 205 | } |
| 194 | } | 206 | } |
| 195 | 207 | ||
| 196 | int main(int argc, char *argv[]) | 208 | static void udp_client(void) |
| 197 | { | 209 | { |
| 198 | if (argc > 2) { | 210 | struct sockaddr_in si_other = {0}; |
| 199 | printf("Too many argument provided\n"); | 211 | struct sockaddr_in si_me = {0}; |
| 200 | return 1; | 212 | struct stats dataEntry; |
| 201 | } else if (argc < 2) { | 213 | int s_rcv, s_send, i, recv_len; |
| 202 | printf("Usage: %s bpfObjName\n", argv[0]); | 214 | char message = 'a'; |
| 203 | return 1; | 215 | char buf; |
| 216 | uint64_t cookie; | ||
| 217 | int res; | ||
| 218 | socklen_t cookie_len = sizeof(cookie); | ||
| 219 | socklen_t slen = sizeof(si_other); | ||
| 220 | |||
| 221 | s_rcv = socket(PF_INET, SOCK_DGRAM, 0); | ||
| 222 | if (s_rcv < 0) | ||
| 223 | error(1, errno, "rcv socket creat failed!\n"); | ||
| 224 | si_other.sin_family = AF_INET; | ||
| 225 | si_other.sin_port = htons(PORT); | ||
| 226 | if (inet_aton("127.0.0.1", &si_other.sin_addr) == 0) | ||
| 227 | error(1, errno, "inet_aton\n"); | ||
| 228 | if (bind(s_rcv, (struct sockaddr *)&si_other, sizeof(si_other)) == -1) | ||
| 229 | error(1, errno, "bind\n"); | ||
| 230 | s_send = socket(PF_INET, SOCK_DGRAM, 0); | ||
| 231 | if (s_send < 0) | ||
| 232 | error(1, errno, "send socket creat failed!\n"); | ||
| 233 | res = getsockopt(s_send, SOL_SOCKET, SO_COOKIE, &cookie, &cookie_len); | ||
| 234 | if (res < 0) | ||
| 235 | printf("get cookie failed: %s\n", strerror(errno)); | ||
| 236 | res = bpf_map_lookup_elem(map_fd, &cookie, &dataEntry); | ||
| 237 | if (res != -1) | ||
| 238 | error(1, errno, "socket stat found while flow not active\n"); | ||
| 239 | for (i = 0; i < 10; i++) { | ||
| 240 | res = sendto(s_send, &message, sizeof(message), 0, | ||
| 241 | (struct sockaddr *)&si_other, slen); | ||
| 242 | if (res == -1) | ||
| 243 | error(1, errno, "send\n"); | ||
| 244 | if (res != sizeof(message)) | ||
| 245 | error(1, 0, "%uB != %luB\n", res, sizeof(message)); | ||
| 246 | recv_len = recvfrom(s_rcv, &buf, sizeof(buf), 0, | ||
| 247 | (struct sockaddr *)&si_me, &slen); | ||
| 248 | if (recv_len < 0) | ||
| 249 | error(1, errno, "revieve\n"); | ||
| 250 | res = memcmp(&(si_other.sin_addr), &(si_me.sin_addr), | ||
| 251 | sizeof(si_me.sin_addr)); | ||
| 252 | if (res != 0) | ||
| 253 | error(1, EFAULT, "sender addr error: %d\n", res); | ||
| 254 | printf("Message received: %c\n", buf); | ||
| 255 | res = bpf_map_lookup_elem(map_fd, &cookie, &dataEntry); | ||
| 256 | if (res < 0) | ||
| 257 | error(1, errno, "lookup sk stat failed, cookie: %lu\n", | ||
| 258 | cookie); | ||
| 259 | printf("cookie: %lu, uid: 0x%x, Packet Count: %lu," | ||
| 260 | " Bytes Count: %lu\n\n", cookie, dataEntry.uid, | ||
| 261 | dataEntry.packets, dataEntry.bytes); | ||
| 204 | } | 262 | } |
| 263 | close(s_send); | ||
| 264 | close(s_rcv); | ||
| 265 | } | ||
| 205 | 266 | ||
| 206 | maps_create(); | 267 | static int usage(void) |
| 207 | prog_load(); | 268 | { |
| 208 | prog_attach_iptables(argv[1]); | 269 | printf("Usage: ./run_cookie_uid_helper_example.sh" |
| 270 | " bpfObjName -option\n" | ||
| 271 | " -t traffic monitor test\n" | ||
| 272 | " -s getsockopt cookie test\n"); | ||
| 273 | return 1; | ||
| 274 | } | ||
| 209 | 275 | ||
| 210 | while (true) { | 276 | void finish(int ret) |
| 211 | print_table(); | 277 | { |
| 212 | printf("\n"); | 278 | test_finish = true; |
| 213 | sleep(1); | 279 | } |
| 214 | }; | 280 | |
| 281 | int main(int argc, char *argv[]) | ||
| 282 | { | ||
| 283 | int opt; | ||
| 284 | bool cfg_test_traffic = false; | ||
| 285 | bool cfg_test_cookie = false; | ||
| 286 | |||
| 287 | if (argc != 3) | ||
| 288 | return usage(); | ||
| 289 | while ((opt = getopt(argc, argv, "ts")) != -1) { | ||
| 290 | switch (opt) { | ||
| 291 | case 't': | ||
| 292 | cfg_test_traffic = true; | ||
| 293 | break; | ||
