iproute2/ip/ipneigh.c
<<
>>
Prefs
   1/*
   2 * ipneigh.c            "ip neigh".
   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
  13#include <stdio.h>
  14#include <stdlib.h>
  15#include <unistd.h>
  16#include <fcntl.h>
  17#include <string.h>
  18#include <sys/time.h>
  19#include <sys/socket.h>
  20#include <netinet/in.h>
  21#include <netinet/ip.h>
  22
  23#include "rt_names.h"
  24#include "utils.h"
  25#include "ip_common.h"
  26#include "json_print.h"
  27
  28#define NUD_VALID       (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
  29#define MAX_ROUNDS      10
  30
  31static struct
  32{
  33        int family;
  34        int index;
  35        int state;
  36        int unused_only;
  37        inet_prefix pfx;
  38        int flushed;
  39        char *flushb;
  40        int flushp;
  41        int flushe;
  42        int master;
  43        int protocol;
  44        __u8 ndm_flags;
  45} filter;
  46
  47static void usage(void) __attribute__((noreturn));
  48
  49static void usage(void)
  50{
  51        fprintf(stderr,
  52                "Usage: ip neigh { add | del | change | replace }\n"
  53                "                { ADDR [ lladdr LLADDR ] [ nud STATE ] proxy ADDR }\n"
  54                "                [ dev DEV ] [ router ] [ extern_learn ] [ protocol PROTO ]\n"
  55                "\n"
  56                "       ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n"
  57                "                                 [ vrf NAME ]\n"
  58                "\n"
  59                "       ip neigh get { ADDR | proxy ADDR } dev DEV\n"
  60                "\n"
  61                "STATE := { delay | failed | incomplete | noarp | none |\n"
  62                "           permanent | probe | reachable | stale }\n");
  63        exit(-1);
  64}
  65
  66static int nud_state_a2n(unsigned int *state, const char *arg)
  67{
  68        if (matches(arg, "permanent") == 0)
  69                *state = NUD_PERMANENT;
  70        else if (matches(arg, "reachable") == 0)
  71                *state = NUD_REACHABLE;
  72        else if (strcmp(arg, "noarp") == 0)
  73                *state = NUD_NOARP;
  74        else if (strcmp(arg, "none") == 0)
  75                *state = NUD_NONE;
  76        else if (strcmp(arg, "stale") == 0)
  77                *state = NUD_STALE;
  78        else if (strcmp(arg, "incomplete") == 0)
  79                *state = NUD_INCOMPLETE;
  80        else if (strcmp(arg, "delay") == 0)
  81                *state = NUD_DELAY;
  82        else if (strcmp(arg, "probe") == 0)
  83                *state = NUD_PROBE;
  84        else if (matches(arg, "failed") == 0)
  85                *state = NUD_FAILED;
  86        else {
  87                if (get_unsigned(state, arg, 0))
  88                        return -1;
  89                if (*state >= 0x100 || (*state&((*state)-1)))
  90                        return -1;
  91        }
  92        return 0;
  93}
  94
  95static int flush_update(void)
  96{
  97        if (rtnl_send_check(&rth, filter.flushb, filter.flushp) < 0) {
  98                perror("Failed to send flush request");
  99                return -1;
 100        }
 101        filter.flushp = 0;
 102        return 0;
 103}
 104
 105
 106static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
 107{
 108        struct {
 109                struct nlmsghdr n;
 110                struct ndmsg            ndm;
 111                char                    buf[256];
 112        } req = {
 113                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
 114                .n.nlmsg_flags = NLM_F_REQUEST | flags,
 115                .n.nlmsg_type = cmd,
 116                .ndm.ndm_family = preferred_family,
 117                .ndm.ndm_state = NUD_PERMANENT,
 118        };
 119        char  *dev = NULL;
 120        int dst_ok = 0;
 121        int dev_ok = 0;
 122        int lladdr_ok = 0;
 123        char *lla = NULL;
 124        inet_prefix dst;
 125
 126        while (argc > 0) {
 127                if (matches(*argv, "lladdr") == 0) {
 128                        NEXT_ARG();
 129                        if (lladdr_ok)
 130                                duparg("lladdr", *argv);
 131                        lla = *argv;
 132                        lladdr_ok = 1;
 133                } else if (strcmp(*argv, "nud") == 0) {
 134                        unsigned int state;
 135
 136                        NEXT_ARG();
 137                        if (nud_state_a2n(&state, *argv))
 138                                invarg("nud state is bad", *argv);
 139                        req.ndm.ndm_state = state;
 140                } else if (matches(*argv, "proxy") == 0) {
 141                        NEXT_ARG();
 142                        if (matches(*argv, "help") == 0)
 143                                usage();
 144                        if (dst_ok)
 145                                duparg("address", *argv);
 146                        get_addr(&dst, *argv, preferred_family);
 147                        dst_ok = 1;
 148                        dev_ok = 1;
 149                        req.ndm.ndm_flags |= NTF_PROXY;
 150                } else if (strcmp(*argv, "router") == 0) {
 151                        req.ndm.ndm_flags |= NTF_ROUTER;
 152                } else if (matches(*argv, "extern_learn") == 0) {
 153                        req.ndm.ndm_flags |= NTF_EXT_LEARNED;
 154                } else if (strcmp(*argv, "dev") == 0) {
 155                        NEXT_ARG();
 156                        dev = *argv;
 157                        dev_ok = 1;
 158                } else if (matches(*argv, "protocol") == 0) {
 159                        __u32 proto;
 160
 161                        NEXT_ARG();
 162                        if (rtnl_rtprot_a2n(&proto, *argv))
 163                                invarg("\"protocol\" value is invalid\n", *argv);
 164                        if (addattr8(&req.n, sizeof(req), NDA_PROTOCOL, proto))
 165                                return -1;
 166                } else {
 167                        if (strcmp(*argv, "to") == 0) {
 168                                NEXT_ARG();
 169                        }
 170                        if (matches(*argv, "help") == 0) {
 171                                NEXT_ARG();
 172                        }
 173                        if (dst_ok)
 174                                duparg2("to", *argv);
 175                        get_addr(&dst, *argv, preferred_family);
 176                        dst_ok = 1;
 177                }
 178                argc--; argv++;
 179        }
 180        if (!dev_ok || !dst_ok || dst.family == AF_UNSPEC) {
 181                fprintf(stderr, "Device and destination are required arguments.\n");
 182                exit(-1);
 183        }
 184        req.ndm.ndm_family = dst.family;
 185        if (addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen) < 0)
 186                return -1;
 187
 188        if (lla && strcmp(lla, "null")) {
 189                char llabuf[20];
 190                int l;
 191
 192                l = ll_addr_a2n(llabuf, sizeof(llabuf), lla);
 193                if (l < 0)
 194                        return -1;
 195
 196                if (addattr_l(&req.n, sizeof(req), NDA_LLADDR, llabuf, l) < 0)
 197                        return -1;
 198        }
 199
 200        ll_init_map(&rth);
 201
 202        if (dev) {
 203                req.ndm.ndm_ifindex = ll_name_to_index(dev);
 204                if (!req.ndm.ndm_ifindex)
 205                        return nodev(dev);
 206        }
 207
 208        if (rtnl_talk(&rth, &req.n, NULL) < 0)
 209                exit(2);
 210
 211        return 0;
 212}
 213
 214static void print_cacheinfo(const struct nda_cacheinfo *ci)
 215{
 216        static int hz;
 217
 218        if (!hz)
 219                hz = get_user_hz();
 220
 221        if (ci->ndm_refcnt)
 222                print_uint(PRINT_ANY, "refcnt",
 223                                " ref %u", ci->ndm_refcnt);
 224
 225        print_uint(PRINT_ANY, "used", " used %u", ci->ndm_used / hz);
 226        print_uint(PRINT_ANY, "confirmed", "/%u", ci->ndm_confirmed / hz);
 227        print_uint(PRINT_ANY, "updated", "/%u", ci->ndm_updated / hz);
 228}
 229
 230static void print_neigh_state(unsigned int nud)
 231{
 232
 233        open_json_array(PRINT_JSON,
 234                        is_json_context() ?  "state" : "");
 235
 236#define PRINT_FLAG(f)                                           \
 237        if (nud & NUD_##f) {                                    \
 238                nud &= ~NUD_##f;                                \
 239                print_string(PRINT_ANY, NULL, " %s", #f);       \
 240        }
 241
 242        PRINT_FLAG(INCOMPLETE);
 243        PRINT_FLAG(REACHABLE);
 244        PRINT_FLAG(STALE);
 245        PRINT_FLAG(DELAY);
 246        PRINT_FLAG(PROBE);
 247        PRINT_FLAG(FAILED);
 248        PRINT_FLAG(NOARP);
 249        PRINT_FLAG(PERMANENT);
 250#undef PRINT_FLAG
 251
 252        close_json_array(PRINT_JSON, NULL);
 253}
 254
 255static int print_neigh_brief(FILE *fp, struct ndmsg *r, struct rtattr *tb[])
 256{
 257        if (tb[NDA_DST]) {
 258                const char *dst;
 259                int family = r->ndm_family;
 260
 261                if (family == AF_BRIDGE) {
 262                        if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
 263                                family = AF_INET6;
 264                        else
 265                                family = AF_INET;
 266                }
 267
 268                dst = format_host_rta(family, tb[NDA_DST]);
 269                print_color_string(PRINT_ANY, ifa_family_color(family),
 270                                   "dst", "%-39s ", dst);
 271        }
 272
 273        if (!filter.index && r->ndm_ifindex) {
 274                print_color_string(PRINT_ANY, COLOR_IFNAME,
 275                                   "dev", "%-16s ",
 276                                   ll_index_to_name(r->ndm_ifindex));
 277        }
 278
 279        if (tb[NDA_LLADDR]) {
 280                const char *lladdr;
 281
 282                SPRINT_BUF(b1);
 283
 284                lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
 285                                     RTA_PAYLOAD(tb[NDA_LLADDR]),
 286                                     ll_index_to_type(r->ndm_ifindex),
 287                                     b1, sizeof(b1));
 288
 289                print_color_string(PRINT_ANY, COLOR_MAC,
 290                                   "lladdr", "%s", lladdr);
 291        }
 292
 293        print_string(PRINT_FP, NULL, "%s", "\n");
 294        close_json_object();
 295        fflush(fp);
 296
 297        return 0;
 298}
 299
 300int print_neigh(struct nlmsghdr *n, void *arg)
 301{
 302        FILE *fp = (FILE *)arg;
 303        struct ndmsg *r = NLMSG_DATA(n);
 304        int len = n->nlmsg_len;
 305        struct rtattr *tb[NDA_MAX+1];
 306        static int logit = 1;
 307        __u8 protocol = 0;
 308
 309        if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH &&
 310            n->nlmsg_type != RTM_GETNEIGH) {
 311                fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
 312                        n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
 313
 314                return 0;
 315        }
 316        len -= NLMSG_LENGTH(sizeof(*r));
 317        if (len < 0) {
 318                fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
 319                return -1;
 320        }
 321
 322        if (filter.flushb && n->nlmsg_type != RTM_NEWNEIGH)
 323                return 0;
 324
 325        if (filter.family && filter.family != r->ndm_family)
 326                return 0;
 327        if (filter.index && filter.index != r->ndm_ifindex)
 328                return 0;
 329        if (!(filter.state&r->ndm_state) &&
 330            !(r->ndm_flags & NTF_PROXY) &&
 331            !(r->ndm_flags & NTF_EXT_LEARNED) &&
 332            (r->ndm_state || !(filter.state&0x100)))
 333                return 0;
 334
 335        if (filter.master && !(n->nlmsg_flags & NLM_F_DUMP_FILTERED)) {
 336                if (logit) {
 337                        logit = 0;
 338                        fprintf(fp,
 339                                "\nWARNING: Kernel does not support filtering by master device\n\n");
 340                }
 341        }
 342
 343        parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
 344
 345        if (inet_addr_match_rta(&filter.pfx, tb[NDA_DST]))
 346                return 0;
 347
 348        if (tb[NDA_PROTOCOL])
 349                protocol = rta_getattr_u8(tb[NDA_PROTOCOL]);
 350
 351        if (filter.protocol && filter.protocol != protocol)
 352                return 0;
 353
 354        if (filter.unused_only && tb[NDA_CACHEINFO]) {
 355                struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
 356
 357                if (ci->ndm_refcnt)
 358                        return 0;
 359        }
 360
 361        if (filter.flushb) {
 362                struct nlmsghdr *fn;
 363
 364                if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
 365                        if (flush_update())
 366                                return -1;
 367                }
 368                fn = (struct nlmsghdr *)(filter.flushb + NLMSG_ALIGN(filter.flushp));
 369                memcpy(fn, n, n->nlmsg_len);
 370                fn->nlmsg_type = RTM_DELNEIGH;
 371                fn->nlmsg_flags = NLM_F_REQUEST;
 372                fn->nlmsg_seq = ++rth.seq;
 373                filter.flushp = (((char *)fn) + n->nlmsg_len) - filter.flushb;
 374                filter.flushed++;
 375                if (show_stats < 2)
 376                        return 0;
 377        }
 378
 379        open_json_object(NULL);
 380        if (n->nlmsg_type == RTM_DELNEIGH)
 381                print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 382        else if (n->nlmsg_type == RTM_GETNEIGH)
 383                print_null(PRINT_ANY, "miss", "%s ", "miss");
 384
 385        if (brief)
 386                return print_neigh_brief(fp, r, tb);
 387
 388        if (tb[NDA_DST]) {
 389                const char *dst;
 390                int family = r->ndm_family;
 391
 392                if (family == AF_BRIDGE) {
 393                        if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
 394                                family = AF_INET6;
 395                        else
 396                                family = AF_INET;
 397                }
 398
 399                dst = format_host_rta(family, tb[NDA_DST]);
 400                print_color_string(PRINT_ANY,
 401                                   ifa_family_color(family),
 402                                   "dst", "%s ", dst);
 403        }
 404
 405        if (!filter.index && r->ndm_ifindex) {
 406                if (!is_json_context())
 407                        fprintf(fp, "dev ");
 408
 409                print_color_string(PRINT_ANY, COLOR_IFNAME,
 410                                   "dev", "%s ",
 411                                   ll_index_to_name(r->ndm_ifindex));
 412        }
 413
 414        if (tb[NDA_LLADDR]) {
 415                const char *lladdr;
 416                SPRINT_BUF(b1);
 417
 418                lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
 419                                     RTA_PAYLOAD(tb[NDA_LLADDR]),
 420                                     ll_index_to_type(r->ndm_ifindex),
 421                                     b1, sizeof(b1));
 422
 423                if (!is_json_context())
 424                        fprintf(fp, "lladdr ");
 425
 426                print_color_string(PRINT_ANY, COLOR_MAC,
 427                                   "lladdr", "%s", lladdr);
 428        }
 429
 430        if (r->ndm_flags & NTF_ROUTER)
 431                print_null(PRINT_ANY, "router", " %s", "router");
 432
 433        if (r->ndm_flags & NTF_PROXY)
 434                print_null(PRINT_ANY, "proxy", " %s", "proxy");
 435
 436        if (r->ndm_flags & NTF_EXT_LEARNED)
 437                print_null(PRINT_ANY, "extern_learn", " %s ", "extern_learn");
 438
 439        if (r->ndm_flags & NTF_OFFLOADED)
 440                print_null(PRINT_ANY, "offload", " %s", "offload");
 441
 442        if (show_stats) {
 443                if (tb[NDA_CACHEINFO])
 444                        print_cacheinfo(RTA_DATA(tb[NDA_CACHEINFO]));
 445
 446                if (tb[NDA_PROBES])
 447                        print_uint(PRINT_ANY, "probes", " probes %u",
 448                                   rta_getattr_u32(tb[NDA_PROBES]));
 449        }
 450
 451        if (r->ndm_state)
 452                print_neigh_state(r->ndm_state);
 453
 454        if (protocol) {
 455                SPRINT_BUF(b1);
 456
 457                print_string(PRINT_ANY, "protocol", " proto %s ",
 458                             rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
 459        }
 460
 461        print_string(PRINT_FP, NULL, "\n", "");
 462        close_json_object();
 463        fflush(fp);
 464
 465        return 0;
 466}
 467
 468void ipneigh_reset_filter(int ifindex)
 469{
 470        memset(&filter, 0, sizeof(filter));
 471        filter.state = ~0;
 472        filter.index = ifindex;
 473}
 474
 475static int ipneigh_dump_filter(struct nlmsghdr *nlh, int reqlen)
 476{
 477        struct ndmsg *ndm = NLMSG_DATA(nlh);
 478        int err;
 479
 480        ndm->ndm_flags = filter.ndm_flags;
 481
 482        if (filter.index) {
 483                err = addattr32(nlh, reqlen, NDA_IFINDEX, filter.index);
 484                if (err)
 485                        return err;
 486        }
 487        if (filter.master) {
 488                err = addattr32(nlh, reqlen, NDA_MASTER, filter.master);
 489                if (err)
 490                        return err;
 491        }
 492
 493        return 0;
 494}
 495
 496static int do_show_or_flush(int argc, char **argv, int flush)
 497{
 498        char *filter_dev = NULL;
 499        int state_given = 0;
 500
 501        ipneigh_reset_filter(0);
 502
 503        if (!filter.family)
 504                filter.family = preferred_family;
 505
 506        if (flush) {
 507                if (argc <= 0) {
 508                        fprintf(stderr, "Flush requires arguments.\n");
 509                        return -1;
 510                }
 511                filter.state = ~(NUD_PERMANENT|NUD_NOARP);
 512        } else
 513                filter.state = 0xFF & ~NUD_NOARP;
 514
 515        while (argc > 0) {
 516                if (strcmp(*argv, "dev") == 0) {
 517                        NEXT_ARG();
 518                        if (filter_dev)
 519                                duparg("dev", *argv);
 520                        filter_dev = *argv;
 521                } else if (strcmp(*argv, "master") == 0) {
 522                        int ifindex;
 523
 524                        NEXT_ARG();
 525                        ifindex = ll_name_to_index(*argv);
 526                        if (!ifindex)
 527                                invarg("Device does not exist\n", *argv);
 528                        filter.master = ifindex;
 529                } else if (strcmp(*argv, "vrf") == 0) {
 530                        int ifindex;
 531
 532                        NEXT_ARG();
 533                        ifindex = ll_name_to_index(*argv);
 534                        if (!ifindex)
 535                                invarg("Not a valid VRF name\n", *argv);
 536                        if (!name_is_vrf(*argv))
 537                                invarg("Not a valid VRF name\n", *argv);
 538                        filter.master = ifindex;
 539                } else if (strcmp(*argv, "unused") == 0) {
 540                        filter.unused_only = 1;
 541                } else if (strcmp(*argv, "nud") == 0) {
 542                        unsigned int state;
 543
 544                        NEXT_ARG();
 545                        if (!state_given) {
 546                                state_given = 1;
 547                                filter.state = 0;
 548                        }
 549                        if (nud_state_a2n(&state, *argv)) {
 550                                if (strcmp(*argv, "all") != 0)
 551                                        invarg("nud state is bad", *argv);
 552                                state = ~0;
 553                                if (flush)
 554                                        state &= ~NUD_NOARP;
 555                        }
 556                        if (state == 0)
 557                                state = 0x100;
 558                        filter.state |= state;
 559                } else if (strcmp(*argv, "proxy") == 0) {
 560                        filter.ndm_flags = NTF_PROXY;
 561                } else if (matches(*argv, "protocol") == 0) {
 562                        __u32 prot;
 563
 564                        NEXT_ARG();
 565                        if (rtnl_rtprot_a2n(&prot, *argv)) {
 566                                if (strcmp(*argv, "all"))
 567                                        invarg("invalid \"protocol\"\n", *argv);
 568                                prot = 0;
 569                        }
 570                        filter.protocol = prot;
 571                } else {
 572                        if (strcmp(*argv, "to") == 0) {
 573                                NEXT_ARG();
 574                        }
 575                        if (matches(*argv, "help") == 0)
 576                                usage();
 577                        if (get_prefix(&filter.pfx, *argv, filter.family))
 578                                invarg("to value is invalid\n", *argv);
 579                        if (filter.family == AF_UNSPEC)
 580                                filter.family = filter.pfx.family;
 581                }
 582                argc--; argv++;
 583        }
 584
 585        ll_init_map(&rth);
 586
 587        if (filter_dev) {
 588                filter.index = ll_name_to_index(filter_dev);
 589                if (!filter.index)
 590                        return nodev(filter_dev);
 591        }
 592
 593        if (flush) {
 594                int round = 0;
 595                char flushb[4096-512];
 596
 597                filter.flushb = flushb;
 598                filter.flushp = 0;
 599                filter.flushe = sizeof(flushb);
 600
 601                while (round < MAX_ROUNDS) {
 602                        if (rtnl_neighdump_req(&rth, filter.family,
 603                                               ipneigh_dump_filter) < 0) {
 604                                perror("Cannot send dump request");
 605                                exit(1);
 606                        }
 607                        filter.flushed = 0;
 608                        if (rtnl_dump_filter(&rth, print_neigh, stdout) < 0) {
 609                                fprintf(stderr, "Flush terminated\n");
 610                                exit(1);
 611                        }
 612                        if (filter.flushed == 0) {
 613                                if (show_stats) {
 614                                        if (round == 0)
 615                                                printf("Nothing to flush.\n");
 616                                        else
 617                                                printf("*** Flush is complete after %d round%s ***\n", round, round > 1?"s":"");
 618                                }
 619                                fflush(stdout);
 620                                return 0;
 621                        }
 622                        round++;
 623                        if (flush_update() < 0)
 624                                exit(1);
 625                        if (show_stats) {
 626                                printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed);
 627                                fflush(stdout);
 628                        }
 629                        filter.state &= ~NUD_FAILED;
 630                }
 631                printf("*** Flush not complete bailing out after %d rounds\n",
 632                        MAX_ROUNDS);
 633                return 1;
 634        }
 635
 636        if (rtnl_neighdump_req(&rth, filter.family, ipneigh_dump_filter) < 0) {
 637                perror("Cannot send dump request");
 638                exit(1);
 639        }
 640
 641        new_json_obj(json);
 642        if (rtnl_dump_filter(&rth, print_neigh, stdout) < 0) {
 643                fprintf(stderr, "Dump terminated\n");
 644                exit(1);
 645        }
 646        delete_json_obj();
 647
 648        return 0;
 649}
 650
 651static int ipneigh_get(int argc, char **argv)
 652{
 653        struct {
 654                struct nlmsghdr n;
 655                struct ndmsg            ndm;
 656                char                    buf[1024];
 657        } req = {
 658                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
 659                .n.nlmsg_flags = NLM_F_REQUEST,
 660                .n.nlmsg_type = RTM_GETNEIGH,
 661                .ndm.ndm_family = preferred_family,
 662        };
 663        struct nlmsghdr *answer;
 664        char  *d = NULL;
 665        int dst_ok = 0;
 666        int dev_ok = 0;
 667        inet_prefix dst;
 668
 669        while (argc > 0) {
 670                if (strcmp(*argv, "dev") == 0) {
 671                        NEXT_ARG();
 672                        d = *argv;
 673                        dev_ok = 1;
 674                } else if (matches(*argv, "proxy") == 0) {
 675                        NEXT_ARG();
 676                        if (matches(*argv, "help") == 0)
 677                                usage();
 678                        if (dst_ok)
 679                                duparg("address", *argv);
 680                        get_addr(&dst, *argv, preferred_family);
 681                        dst_ok = 1;
 682                        dev_ok = 1;
 683                        req.ndm.ndm_flags |= NTF_PROXY;
 684                } else {
 685                        if (strcmp(*argv, "to") == 0)
 686                                NEXT_ARG();
 687
 688                        if (matches(*argv, "help") == 0)
 689                                usage();
 690                        if (dst_ok)
 691                                duparg2("to", *argv);
 692                        get_addr(&dst, *argv, preferred_family);
 693                        dst_ok = 1;
 694                }
 695                argc--; argv++;
 696        }
 697
 698        if (!dev_ok || !dst_ok || dst.family == AF_UNSPEC) {
 699                fprintf(stderr, "Device and address are required arguments.\n");
 700                return -1;
 701        }
 702
 703        req.ndm.ndm_family = dst.family;
 704        if (addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen) < 0)
 705                return -1;
 706
 707        if (d) {
 708                req.ndm.ndm_ifindex = ll_name_to_index(d);
 709                if (!req.ndm.ndm_ifindex) {
 710                        fprintf(stderr, "Cannot find device \"%s\"\n", d);
 711                        return -1;
 712                }
 713        }
 714
 715        if (rtnl_talk(&rth, &req.n, &answer) < 0)
 716                return -2;
 717
 718        ipneigh_reset_filter(0);
 719        if (print_neigh(answer, stdout) < 0) {
 720                fprintf(stderr, "An error :-)\n");
 721                return -1;
 722        }
 723
 724        return 0;
 725}
 726
 727int do_ipneigh(int argc, char **argv)
 728{
 729        if (argc > 0) {
 730                if (matches(*argv, "add") == 0)
 731                        return ipneigh_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
 732                if (matches(*argv, "change") == 0 ||
 733                    strcmp(*argv, "chg") == 0)
 734                        return ipneigh_modify(RTM_NEWNEIGH, NLM_F_REPLACE, argc-1, argv+1);
 735                if (matches(*argv, "replace") == 0)
 736                        return ipneigh_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
 737                if (matches(*argv, "delete") == 0)
 738                        return ipneigh_modify(RTM_DELNEIGH, 0, argc-1, argv+1);
 739                if (matches(*argv, "get") == 0)
 740                        return ipneigh_get(argc-1, argv+1);
 741                if (matches(*argv, "show") == 0 ||
 742                    matches(*argv, "lst") == 0 ||
 743                    matches(*argv, "list") == 0)
 744                        return do_show_or_flush(argc-1, argv+1, 0);
 745                if (matches(*argv, "flush") == 0)
 746                        return do_show_or_flush(argc-1, argv+1, 1);
 747                if (matches(*argv, "help") == 0)
 748                        usage();
 749        } else
 750                return do_show_or_flush(0, NULL, 0);
 751
 752        fprintf(stderr, "Command \"%s\" is unknown, try \"ip neigh help\".\n", *argv);
 753        exit(-1);
 754}
 755