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