iproute2/ip/ip.c
<<
>>
Prefs
   1/*
   2 * ip.c         "ip" utility frontend.
   3 *
   4 *              This program is free software; you can redistribute 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:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  10 */
  11
  12#include <stdio.h>
  13#include <stdlib.h>
  14#include <unistd.h>
  15#include <fcntl.h>
  16#include <sys/socket.h>
  17#include <netinet/in.h>
  18#include <string.h>
  19#include <errno.h>
  20
  21#include "version.h"
  22#include "utils.h"
  23#include "ip_common.h"
  24#include "namespace.h"
  25#include "color.h"
  26#include "rt_names.h"
  27#include "bpf_util.h"
  28
  29#ifndef LIBDIR
  30#define LIBDIR "/usr/lib"
  31#endif
  32
  33int preferred_family = AF_UNSPEC;
  34int human_readable;
  35int use_iec;
  36int show_stats;
  37int show_details;
  38int oneline;
  39int brief;
  40int json;
  41int timestamp;
  42int force;
  43int max_flush_loops = 10;
  44int batch_mode;
  45bool do_all;
  46
  47struct rtnl_handle rth = { .fd = -1 };
  48
  49const char *get_ip_lib_dir(void)
  50{
  51        const char *lib_dir;
  52
  53        lib_dir = getenv("IP_LIB_DIR");
  54        if (!lib_dir)
  55                lib_dir = LIBDIR "/ip";
  56
  57        return lib_dir;
  58}
  59
  60static void usage(void) __attribute__((noreturn));
  61
  62static void usage(void)
  63{
  64        fprintf(stderr,
  65                "Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n"
  66                "       ip [ -force ] -batch filename\n"
  67                "where  OBJECT := { address | addrlabel | fou | help | ila | ioam | l2tp | link |\n"
  68                "                   macsec | maddress | monitor | mptcp | mroute | mrule |\n"
  69                "                   neighbor | neighbour | netconf | netns | nexthop | ntable |\n"
  70                "                   ntbl | route | rule | sr | tap | tcpmetrics |\n"
  71                "                   token | tunnel | tuntap | vrf | xfrm }\n"
  72                "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
  73                "                    -h[uman-readable] | -iec | -j[son] | -p[retty] |\n"
  74                "                    -f[amily] { inet | inet6 | mpls | bridge | link } |\n"
  75                "                    -4 | -6 | -M | -B | -0 |\n"
  76                "                    -l[oops] { maximum-addr-flush-attempts } | -br[ief] |\n"
  77                "                    -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n"
  78                "                    -rc[vbuf] [size] | -n[etns] name | -N[umeric] | -a[ll] |\n"
  79                "                    -c[olor]}\n");
  80        exit(-1);
  81}
  82
  83static int do_help(int argc, char **argv)
  84{
  85        usage();
  86        return 0;
  87}
  88
  89static const struct cmd {
  90        const char *cmd;
  91        int (*func)(int argc, char **argv);
  92} cmds[] = {
  93        { "address",    do_ipaddr },
  94        { "addrlabel",  do_ipaddrlabel },
  95        { "maddress",   do_multiaddr },
  96        { "route",      do_iproute },
  97        { "rule",       do_iprule },
  98        { "neighbor",   do_ipneigh },
  99        { "neighbour",  do_ipneigh },
 100        { "ntable",     do_ipntable },
 101        { "ntbl",       do_ipntable },
 102        { "link",       do_iplink },
 103        { "l2tp",       do_ipl2tp },
 104        { "fou",        do_ipfou },
 105        { "ila",        do_ipila },
 106        { "macsec",     do_ipmacsec },
 107        { "tunnel",     do_iptunnel },
 108        { "tunl",       do_iptunnel },
 109        { "tuntap",     do_iptuntap },
 110        { "tap",        do_iptuntap },
 111        { "token",      do_iptoken },
 112        { "tcpmetrics", do_tcp_metrics },
 113        { "tcp_metrics", do_tcp_metrics },
 114        { "monitor",    do_ipmonitor },
 115        { "xfrm",       do_xfrm },
 116        { "mroute",     do_multiroute },
 117        { "mrule",      do_multirule },
 118        { "netns",      do_netns },
 119        { "netconf",    do_ipnetconf },
 120        { "vrf",        do_ipvrf},
 121        { "sr",         do_seg6 },
 122        { "nexthop",    do_ipnh },
 123        { "mptcp",      do_mptcp },
 124        { "ioam",       do_ioam6 },
 125        { "help",       do_help },
 126        { 0 }
 127};
 128
 129static int do_cmd(const char *argv0, int argc, char **argv, bool final)
 130{
 131        const struct cmd *c;
 132
 133        for (c = cmds; c->cmd; ++c) {
 134                if (matches(argv0, c->cmd) == 0)
 135                        return -(c->func(argc-1, argv+1));
 136        }
 137
 138        if (final)
 139                fprintf(stderr, "Object \"%s\" is unknown, try \"ip help\".\n", argv0);
 140        return EXIT_FAILURE;
 141}
 142
 143static int ip_batch_cmd(int argc, char *argv[], void *data)
 144{
 145        const int *orig_family = data;
 146
 147        preferred_family = *orig_family;
 148        return do_cmd(argv[0], argc, argv, true);
 149}
 150
 151static int batch(const char *name)
 152{
 153        int orig_family = preferred_family;
 154        int ret;
 155
 156        if (rtnl_open(&rth, 0) < 0) {
 157                fprintf(stderr, "Cannot open rtnetlink\n");
 158                return EXIT_FAILURE;
 159        }
 160
 161        batch_mode = 1;
 162        ret = do_batch(name, force, ip_batch_cmd, &orig_family);
 163
 164        rtnl_close(&rth);
 165        return ret;
 166}
 167
 168int main(int argc, char **argv)
 169{
 170        const char *libbpf_version;
 171        char *batch_file = NULL;
 172        char *basename;
 173        int color = 0;
 174
 175        /* to run vrf exec without root, capabilities might be set, drop them
 176         * if not needed as the first thing.
 177         * execv will drop them for the child command.
 178         * vrf exec requires:
 179         * - cap_dac_override to create the cgroup subdir in /sys
 180         * - cap_sys_admin to load the BPF program
 181         * - cap_net_admin to set the socket into the cgroup
 182         */
 183        if (argc < 3 || strcmp(argv[1], "vrf") != 0 ||
 184                        strcmp(argv[2], "exec") != 0)
 185                drop_cap();
 186
 187        basename = strrchr(argv[0], '/');
 188        if (basename == NULL)
 189                basename = argv[0];
 190        else
 191                basename++;
 192
 193        while (argc > 1) {
 194                char *opt = argv[1];
 195
 196                if (strcmp(opt, "--") == 0) {
 197                        argc--; argv++;
 198                        break;
 199                }
 200                if (opt[0] != '-')
 201                        break;
 202                if (opt[1] == '-')
 203                        opt++;
 204                if (matches(opt, "-loops") == 0) {
 205                        argc--;
 206                        argv++;
 207                        if (argc <= 1)
 208                                usage();
 209                        max_flush_loops = atoi(argv[1]);
 210                } else if (matches(opt, "-family") == 0) {
 211                        argc--;
 212                        argv++;
 213                        if (argc <= 1)
 214                                usage();
 215                        if (strcmp(argv[1], "help") == 0)
 216                                usage();
 217                        else
 218                                preferred_family = read_family(argv[1]);
 219                        if (preferred_family == AF_UNSPEC)
 220                                invarg("invalid protocol family", argv[1]);
 221                } else if (strcmp(opt, "-4") == 0) {
 222                        preferred_family = AF_INET;
 223                } else if (strcmp(opt, "-6") == 0) {
 224                        preferred_family = AF_INET6;
 225                } else if (strcmp(opt, "-0") == 0) {
 226                        preferred_family = AF_PACKET;
 227                } else if (strcmp(opt, "-M") == 0) {
 228                        preferred_family = AF_MPLS;
 229                } else if (strcmp(opt, "-B") == 0) {
 230                        preferred_family = AF_BRIDGE;
 231                } else if (matches(opt, "-human") == 0 ||
 232                           matches(opt, "-human-readable") == 0) {
 233                        ++human_readable;
 234                } else if (matches(opt, "-iec") == 0) {
 235                        ++use_iec;
 236                } else if (matches(opt, "-stats") == 0 ||
 237                           matches(opt, "-statistics") == 0) {
 238                        ++show_stats;
 239                } else if (matches(opt, "-details") == 0) {
 240                        ++show_details;
 241                } else if (matches(opt, "-resolve") == 0) {
 242                        ++resolve_hosts;
 243                } else if (matches(opt, "-oneline") == 0) {
 244                        ++oneline;
 245                } else if (matches(opt, "-timestamp") == 0) {
 246                        ++timestamp;
 247                } else if (matches(opt, "-tshort") == 0) {
 248                        ++timestamp;
 249                        ++timestamp_short;
 250                } else if (matches(opt, "-Version") == 0) {
 251                        printf("ip utility, iproute2-%s", version);
 252                        libbpf_version = get_libbpf_version();
 253                        if (libbpf_version)
 254                                printf(", libbpf %s", libbpf_version);
 255                        printf("\n");
 256                        exit(0);
 257                } else if (matches(opt, "-force") == 0) {
 258                        ++force;
 259                } else if (matches(opt, "-batch") == 0) {
 260                        argc--;
 261                        argv++;
 262                        if (argc <= 1)
 263                                usage();
 264                        batch_file = argv[1];
 265                } else if (matches(opt, "-brief") == 0) {
 266                        ++brief;
 267                } else if (matches(opt, "-json") == 0) {
 268                        ++json;
 269                } else if (matches(opt, "-pretty") == 0) {
 270                        ++pretty;
 271                } else if (matches(opt, "-rcvbuf") == 0) {
 272                        unsigned int size;
 273
 274                        argc--;
 275                        argv++;
 276                        if (argc <= 1)
 277                                usage();
 278                        if (get_unsigned(&size, argv[1], 0)) {
 279                                fprintf(stderr, "Invalid rcvbuf size '%s'\n",
 280                                        argv[1]);
 281                                exit(-1);
 282                        }
 283                        rcvbuf = size;
 284                } else if (matches_color(opt, &color)) {
 285                } else if (matches(opt, "-help") == 0) {
 286                        usage();
 287                } else if (matches(opt, "-netns") == 0) {
 288                        NEXT_ARG();
 289                        if (netns_switch(argv[1]))
 290                                exit(-1);
 291                } else if (matches(opt, "-Numeric") == 0) {
 292                        ++numeric;
 293                } else if (matches(opt, "-all") == 0) {
 294                        do_all = true;
 295                } else {
 296                        fprintf(stderr,
 297                                "Option \"%s\" is unknown, try \"ip -help\".\n",
 298                                opt);
 299                        exit(-1);
 300                }
 301                argc--; argv++;
 302        }
 303
 304        _SL_ = oneline ? "\\" : "\n";
 305
 306        check_enable_color(color, json);
 307
 308        if (batch_file)
 309                return batch(batch_file);
 310
 311        if (rtnl_open(&rth, 0) < 0)
 312                exit(1);
 313
 314        rtnl_set_strict_dump(&rth);
 315
 316        if (strlen(basename) > 2) {
 317                int ret = do_cmd(basename+2, argc, argv, false);
 318                if (ret != EXIT_FAILURE)
 319                        return ret;
 320        }
 321
 322        if (argc > 1)
 323                return do_cmd(argv[1], argc-1, argv+1, true);
 324
 325        rtnl_close(&rth);
 326        usage();
 327}
 328