linux/samples/bpf/xdp_adjust_tail_user.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0
   2 * Copyright (c) 2018 Facebook
   3 *
   4 * This program is free software; you can redistribute it and/or
   5 * modify it under the terms of version 2 of the GNU General Public
   6 * License as published by the Free Software Foundation.
   7 */
   8#include <linux/bpf.h>
   9#include <linux/if_link.h>
  10#include <assert.h>
  11#include <errno.h>
  12#include <signal.h>
  13#include <stdio.h>
  14#include <stdlib.h>
  15#include <string.h>
  16#include <net/if.h>
  17#include <sys/resource.h>
  18#include <arpa/inet.h>
  19#include <netinet/ether.h>
  20#include <unistd.h>
  21#include <time.h>
  22#include <bpf/bpf.h>
  23#include <bpf/libbpf.h>
  24
  25#define STATS_INTERVAL_S 2U
  26#define MAX_PCKT_SIZE 600
  27
  28static int ifindex = -1;
  29static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
  30static __u32 prog_id;
  31
  32static void int_exit(int sig)
  33{
  34        __u32 curr_prog_id = 0;
  35
  36        if (ifindex > -1) {
  37                if (bpf_get_link_xdp_id(ifindex, &curr_prog_id, xdp_flags)) {
  38                        printf("bpf_get_link_xdp_id failed\n");
  39                        exit(1);
  40                }
  41                if (prog_id == curr_prog_id)
  42                        bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
  43                else if (!curr_prog_id)
  44                        printf("couldn't find a prog id on a given iface\n");
  45                else
  46                        printf("program on interface changed, not removing\n");
  47        }
  48        exit(0);
  49}
  50
  51/* simple "icmp packet too big sent" counter
  52 */
  53static void poll_stats(unsigned int map_fd, unsigned int kill_after_s)
  54{
  55        time_t started_at = time(NULL);
  56        __u64 value = 0;
  57        int key = 0;
  58
  59
  60        while (!kill_after_s || time(NULL) - started_at <= kill_after_s) {
  61                sleep(STATS_INTERVAL_S);
  62
  63                assert(bpf_map_lookup_elem(map_fd, &key, &value) == 0);
  64
  65                printf("icmp \"packet too big\" sent: %10llu pkts\n", value);
  66        }
  67}
  68
  69static void usage(const char *cmd)
  70{
  71        printf("Start a XDP prog which send ICMP \"packet too big\" \n"
  72                "messages if ingress packet is bigger then MAX_SIZE bytes\n");
  73        printf("Usage: %s [...]\n", cmd);
  74        printf("    -i <ifname|ifindex> Interface\n");
  75        printf("    -T <stop-after-X-seconds> Default: 0 (forever)\n");
  76        printf("    -P <MAX_PCKT_SIZE> Default: %u\n", MAX_PCKT_SIZE);
  77        printf("    -S use skb-mode\n");
  78        printf("    -N enforce native mode\n");
  79        printf("    -F force loading prog\n");
  80        printf("    -h Display this help\n");
  81}
  82
  83int main(int argc, char **argv)
  84{
  85        struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
  86        struct bpf_prog_load_attr prog_load_attr = {
  87                .prog_type      = BPF_PROG_TYPE_XDP,
  88        };
  89        unsigned char opt_flags[256] = {};
  90        const char *optstr = "i:T:P:SNFh";
  91        struct bpf_prog_info info = {};
  92        __u32 info_len = sizeof(info);
  93        unsigned int kill_after_s = 0;
  94        int i, prog_fd, map_fd, opt;
  95        struct bpf_object *obj;
  96        __u32 max_pckt_size = 0;
  97        __u32 key = 0;
  98        char filename[256];
  99        int err;
 100
 101        for (i = 0; i < strlen(optstr); i++)
 102                if (optstr[i] != 'h' && 'a' <= optstr[i] && optstr[i] <= 'z')
 103                        opt_flags[(unsigned char)optstr[i]] = 1;
 104
 105        while ((opt = getopt(argc, argv, optstr)) != -1) {
 106
 107                switch (opt) {
 108                case 'i':
 109                        ifindex = if_nametoindex(optarg);
 110                        if (!ifindex)
 111                                ifindex = atoi(optarg);
 112                        break;
 113                case 'T':
 114                        kill_after_s = atoi(optarg);
 115                        break;
 116                case 'P':
 117                        max_pckt_size = atoi(optarg);
 118                        break;
 119                case 'S':
 120                        xdp_flags |= XDP_FLAGS_SKB_MODE;
 121                        break;
 122                case 'N':
 123                        /* default, set below */
 124                        break;
 125                case 'F':
 126                        xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
 127                        break;
 128                default:
 129                        usage(argv[0]);
 130                        return 1;
 131                }
 132                opt_flags[opt] = 0;
 133        }
 134
 135        if (!(xdp_flags & XDP_FLAGS_SKB_MODE))
 136                xdp_flags |= XDP_FLAGS_DRV_MODE;
 137
 138        for (i = 0; i < strlen(optstr); i++) {
 139                if (opt_flags[(unsigned int)optstr[i]]) {
 140                        fprintf(stderr, "Missing argument -%c\n", optstr[i]);
 141                        usage(argv[0]);
 142                        return 1;
 143                }
 144        }
 145
 146        if (setrlimit(RLIMIT_MEMLOCK, &r)) {
 147                perror("setrlimit(RLIMIT_MEMLOCK, RLIM_INFINITY)");
 148                return 1;
 149        }
 150
 151        if (!ifindex) {
 152                fprintf(stderr, "Invalid ifname\n");
 153                return 1;
 154        }
 155
 156        snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
 157        prog_load_attr.file = filename;
 158
 159        if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
 160                return 1;
 161
 162        /* static global var 'max_pcktsz' is accessible from .data section */
 163        if (max_pckt_size) {
 164                map_fd = bpf_object__find_map_fd_by_name(obj, "xdp_adju.data");
 165                if (map_fd < 0) {
 166                        printf("finding a max_pcktsz map in obj file failed\n");
 167                        return 1;
 168                }
 169                bpf_map_update_elem(map_fd, &key, &max_pckt_size, BPF_ANY);
 170        }
 171
 172        /* fetch icmpcnt map */
 173        map_fd = bpf_object__find_map_fd_by_name(obj, "icmpcnt");
 174        if (map_fd < 0) {
 175                printf("finding a icmpcnt map in obj file failed\n");
 176                return 1;
 177        }
 178
 179        signal(SIGINT, int_exit);
 180        signal(SIGTERM, int_exit);
 181
 182        if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) {
 183                printf("link set xdp fd failed\n");
 184                return 1;
 185        }
 186
 187        err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
 188        if (err) {
 189                printf("can't get prog info - %s\n", strerror(errno));
 190                return 1;
 191        }
 192        prog_id = info.id;
 193
 194        poll_stats(map_fd, kill_after_s);
 195        int_exit(0);
 196
 197        return 0;
 198}
 199