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