blob: 518d8cdba7c487b5127e20088a10c94dea03e06c [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
2 * ipaddress.c "ip address".
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 * Changes:
12 * Laszlo Valko <valko@linux.karinthy.hu> 990223: address label must be zero terminated
13 */
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <unistd.h>
18#include <syslog.h>
19#include <fcntl.h>
20#include <sys/ioctl.h>
21#include <sys/socket.h>
22#include <sys/ioctl.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000023#include <netinet/in.h>
24#include <arpa/inet.h>
25#include <string.h>
26#include <fnmatch.h>
27
osdl.org!shemmingere5779fb2004-06-09 22:56:28 +000028#include <linux/netdevice.h>
29#include <linux/if_arp.h>
30#include <linux/sockios.h>
31
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000032#include "rt_names.h"
33#include "utils.h"
34#include "ll_map.h"
35#include "ip_common.h"
36
37static struct
38{
39 int ifindex;
40 int family;
41 int oneline;
42 int showqueue;
43 inet_prefix pfx;
44 int scope, scopemask;
45 int flags, flagmask;
46 int up;
47 char *label;
48 int flushed;
49 char *flushb;
50 int flushp;
51 int flushe;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000052} filter;
53
54static int do_link;
55
56static void usage(void) __attribute__((noreturn));
57
58static void usage(void)
59{
60 if (do_link) {
61 iplink_usage();
62 }
Noriaki TAKAMIYA0aef3662006-11-24 12:26:58 +090063 fprintf(stderr, "Usage: ip addr {add|change|replace} IFADDR dev STRING [ LIFETIME ]\n");
Noriaki TAKAMIYAbac735c2007-03-08 03:15:43 +090064 fprintf(stderr, " [ CONFFLAG-LIST]\n");
Masahide NAKAMURA35546df2006-11-24 12:26:55 +090065 fprintf(stderr, " ip addr del IFADDR dev STRING\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000066 fprintf(stderr, " ip addr {show|flush} [ dev STRING ] [ scope SCOPE-ID ]\n");
67 fprintf(stderr, " [ to PREFIX ] [ FLAG-LIST ] [ label PATTERN ]\n");
68 fprintf(stderr, "IFADDR := PREFIX | ADDR peer PREFIX\n");
69 fprintf(stderr, " [ broadcast ADDR ] [ anycast ADDR ]\n");
70 fprintf(stderr, " [ label STRING ] [ scope SCOPE-ID ]\n");
71 fprintf(stderr, "SCOPE-ID := [ host | link | global | NUMBER ]\n");
72 fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n");
73 fprintf(stderr, "FLAG := [ permanent | dynamic | secondary | primary |\n");
Noriaki TAKAMIYAbac735c2007-03-08 03:15:43 +090074 fprintf(stderr, " tentative | deprecated | CONFFLAG-LIST ]\n");
75 fprintf(stderr, "CONFFLAG-LIST := [ CONFFLAG-LIST ] CONFFLAG\n");
76 fprintf(stderr, "CONFFLAG := [ home | nodad ]\n");
Masahide NAKAMURA35546df2006-11-24 12:26:55 +090077 fprintf(stderr, "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n");
78 fprintf(stderr, "LFT := forever | SECONDS\n");
79
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000080 exit(-1);
81}
82
83void print_link_flags(FILE *fp, unsigned flags, unsigned mdown)
84{
85 fprintf(fp, "<");
net[shemminger]!shemminger73b49e92005-03-14 18:47:38 +000086 if (flags & IFF_UP && !(flags & IFF_RUNNING))
87 fprintf(fp, "NO-CARRIER%s", flags ? "," : "");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000088 flags &= ~IFF_RUNNING;
89#define _PF(f) if (flags&IFF_##f) { \
90 flags &= ~IFF_##f ; \
91 fprintf(fp, #f "%s", flags ? "," : ""); }
92 _PF(LOOPBACK);
93 _PF(BROADCAST);
94 _PF(POINTOPOINT);
95 _PF(MULTICAST);
96 _PF(NOARP);
97 _PF(ALLMULTI);
98 _PF(PROMISC);
99 _PF(MASTER);
100 _PF(SLAVE);
101 _PF(DEBUG);
102 _PF(DYNAMIC);
103 _PF(AUTOMEDIA);
104 _PF(PORTSEL);
105 _PF(NOTRAILERS);
106 _PF(UP);
Thomas Grafdcb283c2007-06-19 16:40:40 -0700107 _PF(LOWER_UP);
108 _PF(DORMANT);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000109#undef _PF
110 if (flags)
111 fprintf(fp, "%x", flags);
112 if (mdown)
113 fprintf(fp, ",M-DOWN");
114 fprintf(fp, "> ");
115}
116
117void print_queuelen(char *name)
118{
119 struct ifreq ifr;
120 int s;
121
122 s = socket(AF_INET, SOCK_STREAM, 0);
123 if (s < 0)
124 return;
125
126 memset(&ifr, 0, sizeof(ifr));
127 strcpy(ifr.ifr_name, name);
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800128 if (ioctl(s, SIOCGIFTXQLEN, &ifr) < 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000129 perror("SIOCGIFXQLEN");
130 close(s);
131 return;
132 }
133 close(s);
134
135 if (ifr.ifr_qlen)
136 printf("qlen %d", ifr.ifr_qlen);
137}
138
Patrick McHardy1d934832007-08-22 10:49:01 -0700139static void print_linktype(FILE *fp, struct rtattr *tb)
140{
141 struct rtattr *linkinfo[IFLA_INFO_MAX+1];
142 struct link_util *lu;
143 char *kind;
144
145 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb);
146
147 if (!linkinfo[IFLA_INFO_KIND])
148 return;
149 kind = RTA_DATA(linkinfo[IFLA_INFO_KIND]);
150
151 fprintf(fp, "%s", _SL_);
152 fprintf(fp, " %s ", kind);
153
154 lu = get_link_kind(kind);
155 if (!lu || !lu->print_opt)
156 return;
157
158 if (1) {
159 struct rtattr *attr[lu->maxattr+1], **data = NULL;
160
161 if (linkinfo[IFLA_INFO_DATA]) {
162 parse_rtattr_nested(attr, lu->maxattr,
163 linkinfo[IFLA_INFO_DATA]);
164 data = attr;
165 }
166 lu->print_opt(lu, fp, data);
167
168 if (linkinfo[IFLA_INFO_XSTATS] && show_stats &&
169 lu->print_xstats)
170 lu->print_xstats(lu, fp, linkinfo[IFLA_INFO_XSTATS]);
171 }
172}
173
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800174int print_linkinfo(const struct sockaddr_nl *who,
osdl.net!shemminger50772dc2004-12-07 21:48:29 +0000175 struct nlmsghdr *n, void *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000176{
177 FILE *fp = (FILE*)arg;
178 struct ifinfomsg *ifi = NLMSG_DATA(n);
179 struct rtattr * tb[IFLA_MAX+1];
180 int len = n->nlmsg_len;
181 unsigned m_flag = 0;
182
183 if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
184 return 0;
185
186 len -= NLMSG_LENGTH(sizeof(*ifi));
187 if (len < 0)
188 return -1;
189
190 if (filter.ifindex && ifi->ifi_index != filter.ifindex)
191 return 0;
192 if (filter.up && !(ifi->ifi_flags&IFF_UP))
193 return 0;
194
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000195 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
196 if (tb[IFLA_IFNAME] == NULL) {
197 fprintf(stderr, "BUG: nil ifname\n");
198 return -1;
199 }
200 if (filter.label &&
201 (!filter.family || filter.family == AF_PACKET) &&
202 fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
203 return 0;
204
205 if (n->nlmsg_type == RTM_DELLINK)
206 fprintf(fp, "Deleted ");
207
208 fprintf(fp, "%d: %s", ifi->ifi_index,
209 tb[IFLA_IFNAME] ? (char*)RTA_DATA(tb[IFLA_IFNAME]) : "<nil>");
210
211 if (tb[IFLA_LINK]) {
212 SPRINT_BUF(b1);
213 int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]);
214 if (iflink == 0)
215 fprintf(fp, "@NONE: ");
216 else {
217 fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1));
218 m_flag = ll_index_to_flags(iflink);
219 m_flag = !(m_flag & IFF_UP);
220 }
221 } else {
222 fprintf(fp, ": ");
223 }
224 print_link_flags(fp, ifi->ifi_flags, m_flag);
225
226 if (tb[IFLA_MTU])
227 fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
228 if (tb[IFLA_QDISC])
229 fprintf(fp, "qdisc %s ", (char*)RTA_DATA(tb[IFLA_QDISC]));
230#ifdef IFLA_MASTER
231 if (tb[IFLA_MASTER]) {
232 SPRINT_BUF(b1);
233 fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
234 }
235#endif
236 if (filter.showqueue)
237 print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME]));
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800238
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000239 if (!filter.family || filter.family == AF_PACKET) {
240 SPRINT_BUF(b1);
241 fprintf(fp, "%s", _SL_);
242 fprintf(fp, " link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
243
244 if (tb[IFLA_ADDRESS]) {
245 fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
246 RTA_PAYLOAD(tb[IFLA_ADDRESS]),
247 ifi->ifi_type,
248 b1, sizeof(b1)));
249 }
250 if (tb[IFLA_BROADCAST]) {
251 if (ifi->ifi_flags&IFF_POINTOPOINT)
252 fprintf(fp, " peer ");
253 else
254 fprintf(fp, " brd ");
255 fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
256 RTA_PAYLOAD(tb[IFLA_BROADCAST]),
257 ifi->ifi_type,
258 b1, sizeof(b1)));
259 }
260 }
Patrick McHardy1d934832007-08-22 10:49:01 -0700261
262 if (do_link && tb[IFLA_LINKINFO] && show_details)
263 print_linktype(fp, tb[IFLA_LINKINFO]);
264
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000265 if (do_link && tb[IFLA_STATS] && show_stats) {
net[shemminger]!shemmingerae0f1442004-10-19 19:57:38 +0000266 struct rtnl_link_stats slocal;
267 struct rtnl_link_stats *s = RTA_DATA(tb[IFLA_STATS]);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000268 if (((unsigned long)s) & (sizeof(unsigned long)-1)) {
269 memcpy(&slocal, s, sizeof(slocal));
270 s = &slocal;
271 }
272 fprintf(fp, "%s", _SL_);
273 fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
274 s->rx_compressed ? "compressed" : "", _SL_);
net[shemminger]!shemmingerae0f1442004-10-19 19:57:38 +0000275 fprintf(fp, " %-10u %-8u %-7u %-7u %-7u %-7u",
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000276 s->rx_bytes, s->rx_packets, s->rx_errors,
277 s->rx_dropped, s->rx_over_errors,
278 s->multicast
279 );
280 if (s->rx_compressed)
net[shemminger]!shemmingerae0f1442004-10-19 19:57:38 +0000281 fprintf(fp, " %-7u", s->rx_compressed);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000282 if (show_stats > 1) {
283 fprintf(fp, "%s", _SL_);
284 fprintf(fp, " RX errors: length crc frame fifo missed%s", _SL_);
net[shemminger]!shemmingerae0f1442004-10-19 19:57:38 +0000285 fprintf(fp, " %-7u %-7u %-7u %-7u %-7u",
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000286 s->rx_length_errors,
287 s->rx_crc_errors,
288 s->rx_frame_errors,
289 s->rx_fifo_errors,
290 s->rx_missed_errors
291 );
292 }
293 fprintf(fp, "%s", _SL_);
294 fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
295 s->tx_compressed ? "compressed" : "", _SL_);
net[shemminger]!shemmingerae0f1442004-10-19 19:57:38 +0000296 fprintf(fp, " %-10u %-8u %-7u %-7u %-7u %-7u",
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000297 s->tx_bytes, s->tx_packets, s->tx_errors,
298 s->tx_dropped, s->tx_carrier_errors, s->collisions);
299 if (s->tx_compressed)
net[shemminger]!shemmingerae0f1442004-10-19 19:57:38 +0000300 fprintf(fp, " %-7u", s->tx_compressed);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000301 if (show_stats > 1) {
302 fprintf(fp, "%s", _SL_);
303 fprintf(fp, " TX errors: aborted fifo window heartbeat%s", _SL_);
net[shemminger]!shemmingerae0f1442004-10-19 19:57:38 +0000304 fprintf(fp, " %-7u %-7u %-7u %-7u",
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000305 s->tx_aborted_errors,
306 s->tx_fifo_errors,
307 s->tx_window_errors,
308 s->tx_heartbeat_errors
309 );
310 }
311 }
312 fprintf(fp, "\n");
313 fflush(fp);
314 return 0;
315}
316
317static int flush_update(void)
318{
shemminger351efcd2005-09-01 19:21:50 +0000319 if (rtnl_send(&rth, filter.flushb, filter.flushp) < 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000320 perror("Failed to send flush request\n");
321 return -1;
322 }
323 filter.flushp = 0;
324 return 0;
325}
326
Masahide NAKAMURA35546df2006-11-24 12:26:55 +0900327static int set_lifetime(unsigned int *lifetime, char *argv)
328{
329 if (strcmp(argv, "forever") == 0)
Masahide NAKAMURA141bb602006-11-24 12:27:01 +0900330 *lifetime = INFINITY_LIFE_TIME;
Masahide NAKAMURA35546df2006-11-24 12:26:55 +0900331 else if (get_u32(lifetime, argv, 0))
332 return -1;
333
334 return 0;
335}
336
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800337int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000338 void *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000339{
340 FILE *fp = (FILE*)arg;
341 struct ifaddrmsg *ifa = NLMSG_DATA(n);
342 int len = n->nlmsg_len;
343 struct rtattr * rta_tb[IFA_MAX+1];
344 char abuf[256];
345 SPRINT_BUF(b1);
346
347 if (n->nlmsg_type != RTM_NEWADDR && n->nlmsg_type != RTM_DELADDR)
348 return 0;
349 len -= NLMSG_LENGTH(sizeof(*ifa));
350 if (len < 0) {
351 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
352 return -1;
353 }
354
355 if (filter.flushb && n->nlmsg_type != RTM_NEWADDR)
356 return 0;
357
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000358 parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
359
360 if (!rta_tb[IFA_LOCAL])
361 rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
362 if (!rta_tb[IFA_ADDRESS])
363 rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
364
365 if (filter.ifindex && filter.ifindex != ifa->ifa_index)
366 return 0;
367 if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
368 return 0;
369 if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
370 return 0;
371 if (filter.label) {
372 SPRINT_BUF(b1);
373 const char *label;
374 if (rta_tb[IFA_LABEL])
375 label = RTA_DATA(rta_tb[IFA_LABEL]);
376 else
377 label = ll_idx_n2a(ifa->ifa_index, b1);
378 if (fnmatch(filter.label, label, 0) != 0)
379 return 0;
380 }
381 if (filter.pfx.family) {
382 if (rta_tb[IFA_LOCAL]) {
383 inet_prefix dst;
384 memset(&dst, 0, sizeof(dst));
385 dst.family = ifa->ifa_family;
386 memcpy(&dst.data, RTA_DATA(rta_tb[IFA_LOCAL]), RTA_PAYLOAD(rta_tb[IFA_LOCAL]));
387 if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
388 return 0;
389 }
390 }
391
net[shemminger]!shemminger3eb17312005-02-07 18:28:31 +0000392 if (filter.family && filter.family != ifa->ifa_family)
393 return 0;
394
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000395 if (filter.flushb) {
396 struct nlmsghdr *fn;
397 if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
398 if (flush_update())
399 return -1;
400 }
401 fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
402 memcpy(fn, n, n->nlmsg_len);
403 fn->nlmsg_type = RTM_DELADDR;
404 fn->nlmsg_flags = NLM_F_REQUEST;
shemminger351efcd2005-09-01 19:21:50 +0000405 fn->nlmsg_seq = ++rth.seq;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000406 filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
407 filter.flushed++;
408 if (show_stats < 2)
409 return 0;
410 }
411
412 if (n->nlmsg_type == RTM_DELADDR)
413 fprintf(fp, "Deleted ");
414
415 if (filter.oneline || filter.flushb)
416 fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index));
417 if (ifa->ifa_family == AF_INET)
418 fprintf(fp, " inet ");
419 else if (ifa->ifa_family == AF_INET6)
420 fprintf(fp, " inet6 ");
421 else if (ifa->ifa_family == AF_DECnet)
422 fprintf(fp, " dnet ");
423 else if (ifa->ifa_family == AF_IPX)
424 fprintf(fp, " ipx ");
425 else
426 fprintf(fp, " family %d ", ifa->ifa_family);
427
428 if (rta_tb[IFA_LOCAL]) {
429 fprintf(fp, "%s", rt_addr_n2a(ifa->ifa_family,
430 RTA_PAYLOAD(rta_tb[IFA_LOCAL]),
431 RTA_DATA(rta_tb[IFA_LOCAL]),
432 abuf, sizeof(abuf)));
433
434 if (rta_tb[IFA_ADDRESS] == NULL ||
435 memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), RTA_DATA(rta_tb[IFA_LOCAL]), 4) == 0) {
436 fprintf(fp, "/%d ", ifa->ifa_prefixlen);
437 } else {
438 fprintf(fp, " peer %s/%d ",
439 rt_addr_n2a(ifa->ifa_family,
440 RTA_PAYLOAD(rta_tb[IFA_ADDRESS]),
441 RTA_DATA(rta_tb[IFA_ADDRESS]),
442 abuf, sizeof(abuf)),
443 ifa->ifa_prefixlen);
444 }
445 }
446
447 if (rta_tb[IFA_BROADCAST]) {
448 fprintf(fp, "brd %s ",
449 rt_addr_n2a(ifa->ifa_family,
450 RTA_PAYLOAD(rta_tb[IFA_BROADCAST]),
451 RTA_DATA(rta_tb[IFA_BROADCAST]),
452 abuf, sizeof(abuf)));
453 }
454 if (rta_tb[IFA_ANYCAST]) {
455 fprintf(fp, "any %s ",
456 rt_addr_n2a(ifa->ifa_family,
457 RTA_PAYLOAD(rta_tb[IFA_ANYCAST]),
458 RTA_DATA(rta_tb[IFA_ANYCAST]),
459 abuf, sizeof(abuf)));
460 }
461 fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
462 if (ifa->ifa_flags&IFA_F_SECONDARY) {
463 ifa->ifa_flags &= ~IFA_F_SECONDARY;
464 fprintf(fp, "secondary ");
465 }
466 if (ifa->ifa_flags&IFA_F_TENTATIVE) {
467 ifa->ifa_flags &= ~IFA_F_TENTATIVE;
468 fprintf(fp, "tentative ");
469 }
470 if (ifa->ifa_flags&IFA_F_DEPRECATED) {
471 ifa->ifa_flags &= ~IFA_F_DEPRECATED;
472 fprintf(fp, "deprecated ");
473 }
Noriaki TAKAMIYAbac735c2007-03-08 03:15:43 +0900474 if (ifa->ifa_flags&IFA_F_HOMEADDRESS) {
475 ifa->ifa_flags &= ~IFA_F_HOMEADDRESS;
476 fprintf(fp, "home ");
477 }
478 if (ifa->ifa_flags&IFA_F_NODAD) {
479 ifa->ifa_flags &= ~IFA_F_NODAD;
480 fprintf(fp, "nodad ");
481 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000482 if (!(ifa->ifa_flags&IFA_F_PERMANENT)) {
483 fprintf(fp, "dynamic ");
484 } else
485 ifa->ifa_flags &= ~IFA_F_PERMANENT;
486 if (ifa->ifa_flags)
487 fprintf(fp, "flags %02x ", ifa->ifa_flags);
488 if (rta_tb[IFA_LABEL])
489 fprintf(fp, "%s", (char*)RTA_DATA(rta_tb[IFA_LABEL]));
490 if (rta_tb[IFA_CACHEINFO]) {
491 struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
492 char buf[128];
493 fprintf(fp, "%s", _SL_);
Masahide NAKAMURA141bb602006-11-24 12:27:01 +0900494 if (ci->ifa_valid == INFINITY_LIFE_TIME)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000495 sprintf(buf, "valid_lft forever");
496 else
Masahide NAKAMURA0cc5ebf2006-11-24 12:26:53 +0900497 sprintf(buf, "valid_lft %usec", ci->ifa_valid);
Masahide NAKAMURA141bb602006-11-24 12:27:01 +0900498 if (ci->ifa_prefered == INFINITY_LIFE_TIME)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000499 sprintf(buf+strlen(buf), " preferred_lft forever");
500 else
Masahide NAKAMURA0cc5ebf2006-11-24 12:26:53 +0900501 sprintf(buf+strlen(buf), " preferred_lft %usec",
502 ci->ifa_prefered);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000503 fprintf(fp, " %s", buf);
504 }
505 fprintf(fp, "\n");
506 fflush(fp);
507 return 0;
508}
509
510
511struct nlmsg_list
512{
513 struct nlmsg_list *next;
514 struct nlmsghdr h;
515};
516
517int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo, FILE *fp)
518{
519 for ( ;ainfo ; ainfo = ainfo->next) {
520 struct nlmsghdr *n = &ainfo->h;
521 struct ifaddrmsg *ifa = NLMSG_DATA(n);
522
523 if (n->nlmsg_type != RTM_NEWADDR)
524 continue;
525
526 if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa)))
527 return -1;
528
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800529 if (ifa->ifa_index != ifindex ||
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000530 (filter.family && filter.family != ifa->ifa_family))
531 continue;
532
533 print_addrinfo(NULL, n, fp);
534 }
535 return 0;
536}
537
538
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800539static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000540 void *arg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000541{
542 struct nlmsg_list **linfo = (struct nlmsg_list**)arg;
543 struct nlmsg_list *h;
544 struct nlmsg_list **lp;
545
546 h = malloc(n->nlmsg_len+sizeof(void*));
547 if (h == NULL)
548 return -1;
549
550 memcpy(&h->h, n, n->nlmsg_len);
551 h->next = NULL;
552
553 for (lp = linfo; *lp; lp = &(*lp)->next) /* NOTHING */;
554 *lp = h;
555
556 ll_remember_index(who, n, NULL);
557 return 0;
558}
559
560int ipaddr_list_or_flush(int argc, char **argv, int flush)
561{
562 struct nlmsg_list *linfo = NULL;
563 struct nlmsg_list *ainfo = NULL;
shemminger8ed63ab2005-09-21 19:33:17 +0000564 struct nlmsg_list *l, *n;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000565 char *filter_dev = NULL;
566 int no_link = 0;
567
568 ipaddr_reset_filter(oneline);
569 filter.showqueue = 1;
570
571 if (filter.family == AF_UNSPEC)
572 filter.family = preferred_family;
573
574 if (flush) {
575 if (argc <= 0) {
576 fprintf(stderr, "Flush requires arguments.\n");
577 return -1;
578 }
579 if (filter.family == AF_PACKET) {
580 fprintf(stderr, "Cannot flush link addresses.\n");
581 return -1;
582 }
583 }
584
585 while (argc > 0) {
586 if (strcmp(*argv, "to") == 0) {
587 NEXT_ARG();
588 get_prefix(&filter.pfx, *argv, filter.family);
589 if (filter.family == AF_UNSPEC)
590 filter.family = filter.pfx.family;
591 } else if (strcmp(*argv, "scope") == 0) {
shemmingerf332d162005-07-05 22:37:15 +0000592 unsigned scope = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000593 NEXT_ARG();
594 filter.scopemask = -1;
595 if (rtnl_rtscope_a2n(&scope, *argv)) {
596 if (strcmp(*argv, "all") != 0)
597 invarg("invalid \"scope\"\n", *argv);
598 scope = RT_SCOPE_NOWHERE;
599 filter.scopemask = 0;
600 }
601 filter.scope = scope;
602 } else if (strcmp(*argv, "up") == 0) {
603 filter.up = 1;
604 } else if (strcmp(*argv, "dynamic") == 0) {
605 filter.flags &= ~IFA_F_PERMANENT;
606 filter.flagmask |= IFA_F_PERMANENT;
607 } else if (strcmp(*argv, "permanent") == 0) {
608 filter.flags |= IFA_F_PERMANENT;
609 filter.flagmask |= IFA_F_PERMANENT;
610 } else if (strcmp(*argv, "secondary") == 0) {
611 filter.flags |= IFA_F_SECONDARY;
612 filter.flagmask |= IFA_F_SECONDARY;
613 } else if (strcmp(*argv, "primary") == 0) {
614 filter.flags &= ~IFA_F_SECONDARY;
615 filter.flagmask |= IFA_F_SECONDARY;
616 } else if (strcmp(*argv, "tentative") == 0) {
617 filter.flags |= IFA_F_TENTATIVE;
618 filter.flagmask |= IFA_F_TENTATIVE;
619 } else if (strcmp(*argv, "deprecated") == 0) {
620 filter.flags |= IFA_F_DEPRECATED;
621 filter.flagmask |= IFA_F_DEPRECATED;
Noriaki TAKAMIYAbac735c2007-03-08 03:15:43 +0900622 } else if (strcmp(*argv, "home") == 0) {
623 filter.flags |= IFA_F_HOMEADDRESS;
624 filter.flagmask |= IFA_F_HOMEADDRESS;
625 } else if (strcmp(*argv, "nodad") == 0) {
626 filter.flags |= IFA_F_NODAD;
627 filter.flagmask |= IFA_F_NODAD;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000628 } else if (strcmp(*argv, "label") == 0) {
629 NEXT_ARG();
630 filter.label = *argv;
631 } else {
632 if (strcmp(*argv, "dev") == 0) {
633 NEXT_ARG();
634 }
635 if (matches(*argv, "help") == 0)
636 usage();
637 if (filter_dev)
638 duparg2("dev", *argv);
639 filter_dev = *argv;
640 }
641 argv++; argc--;
642 }
643
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000644 if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) {
645 perror("Cannot send dump request");
646 exit(1);
647 }
648
649 if (rtnl_dump_filter(&rth, store_nlmsg, &linfo, NULL, NULL) < 0) {
650 fprintf(stderr, "Dump terminated\n");
651 exit(1);
652 }
653
654 if (filter_dev) {
655 filter.ifindex = ll_name_to_index(filter_dev);
656 if (filter.ifindex <= 0) {
657 fprintf(stderr, "Device \"%s\" does not exist.\n", filter_dev);
658 return -1;
659 }
660 }
661
662 if (flush) {
663 int round = 0;
664 char flushb[4096-512];
665
666 filter.flushb = flushb;
667 filter.flushp = 0;
668 filter.flushe = sizeof(flushb);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000669
670 for (;;) {
671 if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
672 perror("Cannot send dump request");
673 exit(1);
674 }
675 filter.flushed = 0;
676 if (rtnl_dump_filter(&rth, print_addrinfo, stdout, NULL, NULL) < 0) {
677 fprintf(stderr, "Flush terminated\n");
678 exit(1);
679 }
680 if (filter.flushed == 0) {
681 if (round == 0) {
682 fprintf(stderr, "Nothing to flush.\n");
683 } else if (show_stats)
684 printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":"");
685 fflush(stdout);
686 return 0;
687 }
688 round++;
689 if (flush_update() < 0)
shemminger351efcd2005-09-01 19:21:50 +0000690 return 1;
691
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000692 if (show_stats) {
693 printf("\n*** Round %d, deleting %d addresses ***\n", round, filter.flushed);
694 fflush(stdout);
695 }
696 }
697 }
698
699 if (filter.family != AF_PACKET) {
700 if (rtnl_wilddump_request(&rth, filter.family, RTM_GETADDR) < 0) {
701 perror("Cannot send dump request");
702 exit(1);
703 }
704
705 if (rtnl_dump_filter(&rth, store_nlmsg, &ainfo, NULL, NULL) < 0) {
706 fprintf(stderr, "Dump terminated\n");
707 exit(1);
708 }
709 }
710
711
712 if (filter.family && filter.family != AF_PACKET) {
713 struct nlmsg_list **lp;
714 lp=&linfo;
715
716 if (filter.oneline)
717 no_link = 1;
718
719 while ((l=*lp)!=NULL) {
720 int ok = 0;
721 struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
722 struct nlmsg_list *a;
723
724 for (a=ainfo; a; a=a->next) {
725 struct nlmsghdr *n = &a->h;
726 struct ifaddrmsg *ifa = NLMSG_DATA(n);
727
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800728 if (ifa->ifa_index != ifi->ifi_index ||
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000729 (filter.family && filter.family != ifa->ifa_family))
730 continue;
731 if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
732 continue;
733 if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
734 continue;
735 if (filter.pfx.family || filter.label) {
736 struct rtattr *tb[IFA_MAX+1];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000737 parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
738 if (!tb[IFA_LOCAL])
739 tb[IFA_LOCAL] = tb[IFA_ADDRESS];
740
741 if (filter.pfx.family && tb[IFA_LOCAL]) {
742 inet_prefix dst;
743 memset(&dst, 0, sizeof(dst));
744 dst.family = ifa->ifa_family;
745 memcpy(&dst.data, RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_LOCAL]));
746 if (inet_addr_match(&dst, &filter.pfx, filter.pfx.bitlen))
747 continue;
748 }
749 if (filter.label) {
750 SPRINT_BUF(b1);
751 const char *label;
752 if (tb[IFA_LABEL])
753 label = RTA_DATA(tb[IFA_LABEL]);
754 else
755 label = ll_idx_n2a(ifa->ifa_index, b1);
756 if (fnmatch(filter.label, label, 0) != 0)
757 continue;
758 }
759 }
760
761 ok = 1;
762 break;
763 }
764 if (!ok)
765 *lp = l->next;
766 else
767 lp = &l->next;
768 }
769 }
770
shemminger8ed63ab2005-09-21 19:33:17 +0000771 for (l=linfo; l; l = n) {
772 n = l->next;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000773 if (no_link || print_linkinfo(NULL, &l->h, stdout) == 0) {
774 struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
775 if (filter.family != AF_PACKET)
776 print_selected_addrinfo(ifi->ifi_index, ainfo, stdout);
777 }
778 fflush(stdout);
shemminger8ed63ab2005-09-21 19:33:17 +0000779 free(l);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000780 }
781
shemminger351efcd2005-09-01 19:21:50 +0000782 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000783}
784
785int ipaddr_list_link(int argc, char **argv)
786{
787 preferred_family = AF_PACKET;
788 do_link = 1;
789 return ipaddr_list_or_flush(argc, argv, 0);
790}
791
792void ipaddr_reset_filter(int oneline)
793{
794 memset(&filter, 0, sizeof(filter));
795 filter.oneline = oneline;
796}
797
798int default_scope(inet_prefix *lcl)
799{
800 if (lcl->family == AF_INET) {
801 if (lcl->bytelen >= 1 && *(__u8*)&lcl->data == 127)
802 return RT_SCOPE_HOST;
803 }
804 return 0;
805}
806
Noriaki TAKAMIYA0aef3662006-11-24 12:26:58 +0900807int ipaddr_modify(int cmd, int flags, int argc, char **argv)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000808{
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000809 struct {
810 struct nlmsghdr n;
811 struct ifaddrmsg ifa;
812 char buf[256];
813 } req;
814 char *d = NULL;
815 char *l = NULL;
net[shemminger]!shemmingerf082b642005-03-30 18:16:10 +0000816 char *lcl_arg = NULL;
Masahide NAKAMURA35546df2006-11-24 12:26:55 +0900817 char *valid_lftp = NULL;
818 char *preferred_lftp = NULL;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000819 inet_prefix lcl;
820 inet_prefix peer;
821 int local_len = 0;
822 int peer_len = 0;
823 int brd_len = 0;
824 int any_len = 0;
825 int scoped = 0;
Masahide NAKAMURA141bb602006-11-24 12:27:01 +0900826 __u32 preferred_lft = INFINITY_LIFE_TIME;
827 __u32 valid_lft = INFINITY_LIFE_TIME;
Masahide NAKAMURA35546df2006-11-24 12:26:55 +0900828 struct ifa_cacheinfo cinfo;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000829
830 memset(&req, 0, sizeof(req));
831
832 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
Noriaki TAKAMIYA0aef3662006-11-24 12:26:58 +0900833 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000834 req.n.nlmsg_type = cmd;
835 req.ifa.ifa_family = preferred_family;
836
837 while (argc > 0) {
838 if (strcmp(*argv, "peer") == 0 ||
839 strcmp(*argv, "remote") == 0) {
840 NEXT_ARG();
841
842 if (peer_len)
843 duparg("peer", *argv);
844 get_prefix(&peer, *argv, req.ifa.ifa_family);
845 peer_len = peer.bytelen;
846 if (req.ifa.ifa_family == AF_UNSPEC)
847 req.ifa.ifa_family = peer.family;
848 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen);
849 req.ifa.ifa_prefixlen = peer.bitlen;
850 } else if (matches(*argv, "broadcast") == 0 ||
851 strcmp(*argv, "brd") == 0) {
852 inet_prefix addr;
853 NEXT_ARG();
854 if (brd_len)
855 duparg("broadcast", *argv);
856 if (strcmp(*argv, "+") == 0)
857 brd_len = -1;
858 else if (strcmp(*argv, "-") == 0)
859 brd_len = -2;
860 else {
861 get_addr(&addr, *argv, req.ifa.ifa_family);
862 if (req.ifa.ifa_family == AF_UNSPEC)
863 req.ifa.ifa_family = addr.family;
864 addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen);
865 brd_len = addr.bytelen;
866 }
867 } else if (strcmp(*argv, "anycast") == 0) {
868 inet_prefix addr;
869 NEXT_ARG();
870 if (any_len)
871 duparg("anycast", *argv);
872 get_addr(&addr, *argv, req.ifa.ifa_family);
873 if (req.ifa.ifa_family == AF_UNSPEC)
874 req.ifa.ifa_family = addr.family;
875 addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen);
876 any_len = addr.bytelen;
877 } else if (strcmp(*argv, "scope") == 0) {
shemmingerf332d162005-07-05 22:37:15 +0000878 unsigned scope = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000879 NEXT_ARG();
880 if (rtnl_rtscope_a2n(&scope, *argv))
881 invarg(*argv, "invalid scope value.");
882 req.ifa.ifa_scope = scope;
883 scoped = 1;
884 } else if (strcmp(*argv, "dev") == 0) {
885 NEXT_ARG();
886 d = *argv;
887 } else if (strcmp(*argv, "label") == 0) {
888 NEXT_ARG();
889 l = *argv;
890 addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1);
Masahide NAKAMURA35546df2006-11-24 12:26:55 +0900891 } else if (matches(*argv, "valid_lft") == 0) {
892 if (valid_lftp)
893 duparg("valid_lft", *argv);
894 NEXT_ARG();
895 valid_lftp = *argv;
896 if (set_lifetime(&valid_lft, *argv))
897 invarg("valid_lft value", *argv);
898 } else if (matches(*argv, "preferred_lft") == 0) {
899 if (preferred_lftp)
900 duparg("preferred_lft", *argv);
901 NEXT_ARG();
902 preferred_lftp = *argv;
903 if (set_lifetime(&preferred_lft, *argv))
904 invarg("preferred_lft value", *argv);
Noriaki TAKAMIYAbac735c2007-03-08 03:15:43 +0900905 } else if (strcmp(*argv, "home") == 0) {
906 req.ifa.ifa_flags |= IFA_F_HOMEADDRESS;
907 } else if (strcmp(*argv, "nodad") == 0) {
908 req.ifa.ifa_flags |= IFA_F_NODAD;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000909 } else {
910 if (strcmp(*argv, "local") == 0) {
911 NEXT_ARG();
912 }
913 if (matches(*argv, "help") == 0)
914 usage();
915 if (local_len)
916 duparg2("local", *argv);
net[shemminger]!shemmingerf082b642005-03-30 18:16:10 +0000917 lcl_arg = *argv;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000918 get_prefix(&lcl, *argv, req.ifa.ifa_family);
919 if (req.ifa.ifa_family == AF_UNSPEC)
920 req.ifa.ifa_family = lcl.family;
921 addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen);
922 local_len = lcl.bytelen;
923 }
924 argc--; argv++;
925 }
926 if (d == NULL) {
927 fprintf(stderr, "Not enough information: \"dev\" argument is required.\n");
928 return -1;
929 }
930 if (l && matches(d, l) != 0) {
931 fprintf(stderr, "\"dev\" (%s) must match \"label\" (%s).\n", d, l);
932 exit(1);
933 }
934
net[shemminger]!shemmingerf082b642005-03-30 18:16:10 +0000935 if (peer_len == 0 && local_len) {
936 if (cmd == RTM_DELADDR && lcl.family == AF_INET && !(lcl.flags & PREFIXLEN_SPECIFIED)) {
937 fprintf(stderr,
938 "Warning: Executing wildcard deletion to stay compatible with old scripts.\n" \
939 " Explicitly specify the prefix length (%s/%d) to avoid this warning.\n" \
940 " This special behaviour is likely to disappear in further releases,\n" \
941 " fix your scripts!\n", lcl_arg, local_len*8);
942 } else {
943 peer = lcl;
944 addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen);
945 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000946 }
947 if (req.ifa.ifa_prefixlen == 0)
948 req.ifa.ifa_prefixlen = lcl.bitlen;
949
950 if (brd_len < 0 && cmd != RTM_DELADDR) {
951 inet_prefix brd;
952 int i;
953 if (req.ifa.ifa_family != AF_INET) {
954 fprintf(stderr, "Broadcast can be set only for IPv4 addresses\n");
955 return -1;
956 }
957 brd = peer;
958 if (brd.bitlen <= 30) {
959 for (i=31; i>=brd.bitlen; i--) {
960 if (brd_len == -1)
961 brd.data[0] |= htonl(1<<(31-i));
962 else
963 brd.data[0] &= ~htonl(1<<(31-i));
964 }
965 addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen);
966 brd_len = brd.bytelen;
967 }
968 }
969 if (!scoped && cmd != RTM_DELADDR)
970 req.ifa.ifa_scope = default_scope(&lcl);
971
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000972 ll_init_map(&rth);
973
974 if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) {
975 fprintf(stderr, "Cannot find device \"%s\"\n", d);
976 return -1;
977 }
978
Masahide NAKAMURA35546df2006-11-24 12:26:55 +0900979 if (valid_lftp || preferred_lftp) {
980 if (!valid_lft) {
981 fprintf(stderr, "valid_lft is zero\n");
982 return -1;
983 }
984 if (valid_lft < preferred_lft) {
985 fprintf(stderr, "preferred_lft is greater than valid_lft\n");
986 return -1;
987 }
988
989 memset(&cinfo, 0, sizeof(cinfo));
990 cinfo.ifa_prefered = preferred_lft;
991 cinfo.ifa_valid = valid_lft;
992 addattr_l(&req.n, sizeof(req), IFA_CACHEINFO, &cinfo,
993 sizeof(cinfo));
994 }
995
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000996 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
997 exit(2);
998
shemminger351efcd2005-09-01 19:21:50 +0000999 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001000}
1001
1002int do_ipaddr(int argc, char **argv)
1003{
1004 if (argc < 1)
1005 return ipaddr_list_or_flush(0, NULL, 0);
1006 if (matches(*argv, "add") == 0)
Noriaki TAKAMIYA0aef3662006-11-24 12:26:58 +09001007 return ipaddr_modify(RTM_NEWADDR, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
1008 if (matches(*argv, "change") == 0 ||
1009 strcmp(*argv, "chg") == 0)
1010 return ipaddr_modify(RTM_NEWADDR, NLM_F_REPLACE, argc-1, argv+1);
1011 if (matches(*argv, "replace") == 0)
1012 return ipaddr_modify(RTM_NEWADDR, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001013 if (matches(*argv, "delete") == 0)
Noriaki TAKAMIYA0aef3662006-11-24 12:26:58 +09001014 return ipaddr_modify(RTM_DELADDR, 0, argc-1, argv+1);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001015 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
1016 || matches(*argv, "lst") == 0)
1017 return ipaddr_list_or_flush(argc-1, argv+1, 0);
1018 if (matches(*argv, "flush") == 0)
1019 return ipaddr_list_or_flush(argc-1, argv+1, 1);
1020 if (matches(*argv, "help") == 0)
1021 usage();
1022 fprintf(stderr, "Command \"%s\" is unknown, try \"ip address help\".\n", *argv);
1023 exit(-1);
1024}
1025