]>
Commit | Line | Data |
---|---|---|
8a48ecb8 | 1 | /* |
4cc78c50 | 2 | * BIRD -- Management of Interfaces and Neighbor Cache |
8a48ecb8 | 3 | * |
85053fce | 4 | * (c) 1998--2000 Martin Mares <mj@ucw.cz> |
8a48ecb8 MM |
5 | * |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
7 | */ | |
8 | ||
6a9f28b0 | 9 | #undef LOCAL_DEBUG |
4cc78c50 | 10 | |
8a48ecb8 MM |
11 | #include "nest/bird.h" |
12 | #include "nest/iface.h" | |
4cc78c50 | 13 | #include "nest/protocol.h" |
ae97b946 | 14 | #include "nest/cli.h" |
8a48ecb8 | 15 | #include "lib/resource.h" |
ed45f2e1 | 16 | #include "lib/string.h" |
4e9498cb | 17 | #include "conf/conf.h" |
8a48ecb8 | 18 | |
8a48ecb8 MM |
19 | static pool *if_pool; |
20 | ||
4e9498cb MM |
21 | static void auto_router_id(void); |
22 | ||
4cc78c50 MM |
23 | list iface_list; |
24 | ||
9a158361 MM |
25 | void |
26 | ifa_dump(struct ifa *a) | |
27 | { | |
6a636392 | 28 | debug("\t%I, net %I/%-2d bc %I -> %I%s%s%s\n", a->ip, a->prefix, a->pxlen, a->brd, a->opposite, |
9a158361 | 29 | (a->flags & IF_UP) ? "" : " DOWN", |
6a636392 MM |
30 | (a->flags & IA_PRIMARY) ? "" : " SEC", |
31 | (a->flags & IA_UNNUMBERED) ? " UNNUM" : ""); | |
9a158361 MM |
32 | } |
33 | ||
4cc78c50 MM |
34 | void |
35 | if_dump(struct iface *i) | |
36 | { | |
9a158361 MM |
37 | struct ifa *a; |
38 | ||
8a48ecb8 MM |
39 | debug("IF%d: %s", i->index, i->name); |
40 | if (i->flags & IF_ADMIN_DOWN) | |
41 | debug(" ADMIN-DOWN"); | |
42 | if (i->flags & IF_UP) | |
43 | debug(" UP"); | |
bcbd8cc3 MM |
44 | else |
45 | debug(" DOWN"); | |
46 | if (i->flags & IF_LINK_UP) | |
47 | debug(" LINK-UP"); | |
8a48ecb8 MM |
48 | if (i->flags & IF_MULTIACCESS) |
49 | debug(" MA"); | |
8a48ecb8 MM |
50 | if (i->flags & IF_BROADCAST) |
51 | debug(" BC"); | |
52 | if (i->flags & IF_MULTICAST) | |
53 | debug(" MC"); | |
8a48ecb8 MM |
54 | if (i->flags & IF_LOOPBACK) |
55 | debug(" LOOP"); | |
56 | if (i->flags & IF_IGNORE) | |
57 | debug(" IGN"); | |
9a158361 MM |
58 | if (i->flags & IF_TMP_DOWN) |
59 | debug(" TDOWN"); | |
8a48ecb8 | 60 | debug(" MTU=%d\n", i->mtu); |
9a158361 MM |
61 | WALK_LIST(a, i->addrs) |
62 | { | |
63 | ifa_dump(a); | |
64 | ASSERT((a != i->addr) == !(a->flags & IA_PRIMARY)); | |
65 | } | |
8a48ecb8 MM |
66 | } |
67 | ||
68 | void | |
69 | if_dump_all(void) | |
70 | { | |
71 | struct iface *i; | |
72 | ||
620a355a | 73 | debug("Known network interfaces:\n"); |
8a48ecb8 MM |
74 | WALK_LIST(i, iface_list) |
75 | if_dump(i); | |
4e9498cb | 76 | debug("Router ID: %08x\n", config->router_id); |
8a48ecb8 MM |
77 | } |
78 | ||
9a158361 MM |
79 | static inline unsigned |
80 | if_what_changed(struct iface *i, struct iface *j) | |
8a48ecb8 | 81 | { |
9a158361 MM |
82 | unsigned c; |
83 | ||
84 | if (((i->flags ^ j->flags) & ~(IF_UP | IF_ADMIN_DOWN | IF_UPDATED | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED)) | |
85 | || i->index != j->index) | |
86 | return IF_CHANGE_TOO_MUCH; | |
87 | c = 0; | |
88 | if ((i->flags ^ j->flags) & IF_UP) | |
89 | c |= (i->flags & IF_UP) ? IF_CHANGE_DOWN : IF_CHANGE_UP; | |
90 | if (i->mtu != j->mtu) | |
91 | c |= IF_CHANGE_MTU; | |
92 | return c; | |
8a48ecb8 MM |
93 | } |
94 | ||
95 | static inline void | |
4cc78c50 | 96 | if_copy(struct iface *to, struct iface *from) |
8a48ecb8 | 97 | { |
9a158361 | 98 | to->flags = from->flags | (to->flags & IF_TMP_DOWN); |
4cc78c50 | 99 | to->mtu = from->mtu; |
8a48ecb8 MM |
100 | } |
101 | ||
6a9f28b0 MM |
102 | static inline void |
103 | ifa_send_notify(struct proto *p, unsigned c, struct ifa *a) | |
104 | { | |
105 | if (p->ifa_notify) | |
106 | { | |
107 | if (p->debug & D_IFACES) | |
108 | log(L_TRACE "%s < %s address %I/%d on interface %s %s", | |
109 | p->name, (a->flags & IA_PRIMARY) ? "primary" : "secondary", | |
110 | a->prefix, a->pxlen, a->iface->name, | |
111 | (c & IF_CHANGE_UP) ? "added" : "removed"); | |
112 | p->ifa_notify(p, c, a); | |
113 | } | |
114 | } | |
115 | ||
9a158361 MM |
116 | static void |
117 | ifa_notify_change(unsigned c, struct ifa *a) | |
8a48ecb8 | 118 | { |
9a158361 | 119 | struct proto *p; |
8a48ecb8 | 120 | |
6a9f28b0 | 121 | DBG("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip); |
f14a4bec | 122 | WALK_LIST(p, active_proto_list) |
6a9f28b0 MM |
123 | ifa_send_notify(p, c, a); |
124 | } | |
125 | ||
126 | static inline void | |
127 | if_send_notify(struct proto *p, unsigned c, struct iface *i) | |
128 | { | |
129 | if (p->if_notify) | |
130 | { | |
131 | if (p->debug & D_IFACES) | |
132 | log(L_TRACE "%s < interface %s %s", p->name, i->name, | |
133 | (c & IF_CHANGE_UP) ? "goes up" : | |
134 | (c & IF_CHANGE_DOWN) ? "goes down" : | |
135 | (c & IF_CHANGE_MTU) ? "changes MTU" : | |
136 | (c & IF_CHANGE_CREATE) ? "created" : | |
137 | "sends unknown event"); | |
138 | p->if_notify(p, c, i); | |
139 | } | |
8a48ecb8 MM |
140 | } |
141 | ||
142 | static void | |
9a158361 | 143 | if_notify_change(unsigned c, struct iface *i) |
8a48ecb8 | 144 | { |
d9f330c5 | 145 | struct proto *p; |
9a158361 | 146 | struct ifa *a; |
d9f330c5 | 147 | |
9a158361 MM |
148 | if (i->flags & IF_JUST_CREATED) |
149 | { | |
150 | i->flags &= ~IF_JUST_CREATED; | |
151 | c |= IF_CHANGE_CREATE | IF_CHANGE_MTU; | |
152 | } | |
153 | ||
6a9f28b0 | 154 | DBG("Interface change notification (%x) for %s\n", c, i->name); |
9a158361 | 155 | if_dump(i); |
4cc78c50 MM |
156 | |
157 | if (c & IF_CHANGE_UP) | |
9a158361 MM |
158 | neigh_if_up(i); |
159 | if (c & IF_CHANGE_DOWN) | |
160 | WALK_LIST(a, i->addrs) | |
161 | { | |
162 | a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS); | |
163 | ifa_notify_change(IF_CHANGE_DOWN, a); | |
164 | } | |
4cc78c50 | 165 | |
f14a4bec | 166 | WALK_LIST(p, active_proto_list) |
6a9f28b0 | 167 | if_send_notify(p, c, i); |
4cc78c50 | 168 | |
9a158361 MM |
169 | if (c & IF_CHANGE_UP) |
170 | WALK_LIST(a, i->addrs) | |
171 | { | |
172 | a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS); | |
173 | ifa_notify_change(IF_CHANGE_UP, a); | |
174 | } | |
4cc78c50 | 175 | if (c & IF_CHANGE_DOWN) |
9a158361 | 176 | neigh_if_down(i); |
8a48ecb8 MM |
177 | } |
178 | ||
9a158361 MM |
179 | static unsigned |
180 | if_recalc_flags(struct iface *i, unsigned flags) | |
181 | { | |
182 | if ((flags & (IF_ADMIN_DOWN | IF_TMP_DOWN)) || | |
183 | !(flags & IF_LINK_UP) || | |
184 | !i->addr) | |
185 | flags &= ~IF_UP; | |
186 | else | |
187 | flags |= IF_UP; | |
188 | return flags; | |
189 | } | |
190 | ||
191 | static void | |
192 | if_change_flags(struct iface *i, unsigned flags) | |
193 | { | |
194 | unsigned of = i->flags; | |
195 | ||
196 | i->flags = if_recalc_flags(i, flags); | |
197 | if ((i->flags ^ of) & IF_UP) | |
198 | if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i); | |
199 | } | |
200 | ||
201 | struct iface * | |
8a48ecb8 MM |
202 | if_update(struct iface *new) |
203 | { | |
204 | struct iface *i; | |
9a158361 | 205 | struct ifa *a, *b; |
4cc78c50 | 206 | unsigned c; |
8a48ecb8 MM |
207 | |
208 | WALK_LIST(i, iface_list) | |
209 | if (!strcmp(new->name, i->name)) | |
210 | { | |
9a158361 MM |
211 | new->addr = i->addr; |
212 | new->flags = if_recalc_flags(new, new->flags); | |
213 | c = if_what_changed(i, new); | |
214 | if (c & IF_CHANGE_TOO_MUCH) /* Changed a lot, convert it to down/up */ | |
8a48ecb8 | 215 | { |
4cc78c50 | 216 | DBG("Interface %s changed too much -- forcing down/up transition\n", i->name); |
9a158361 | 217 | if_change_flags(i, i->flags | IF_TMP_DOWN); |
8a48ecb8 | 218 | rem_node(&i->n); |
a2697f02 MM |
219 | new->addr = i->addr; |
220 | memcpy(&new->addrs, &i->addrs, sizeof(i->addrs)); | |
221 | memcpy(i, new, sizeof(*i)); | |
4cc78c50 | 222 | goto newif; |
8a48ecb8 | 223 | } |
9a158361 MM |
224 | else if (c) |
225 | { | |
226 | if_copy(i, new); | |
227 | if_notify_change(c, i); | |
228 | } | |
e35ef181 | 229 | i->flags |= IF_UPDATED; |
9a158361 | 230 | return i; |
8a48ecb8 | 231 | } |
4cc78c50 | 232 | i = mb_alloc(if_pool, sizeof(struct iface)); |
4cc78c50 | 233 | memcpy(i, new, sizeof(*i)); |
9a158361 | 234 | init_list(&i->addrs); |
f5ad9f87 | 235 | init_list(&i->neighbors); |
a2697f02 | 236 | newif: |
9a158361 | 237 | i->flags |= IF_UPDATED | IF_TMP_DOWN; /* Tmp down as we don't have addresses yet */ |
8a48ecb8 | 238 | add_tail(&iface_list, &i->n); |
9a158361 | 239 | return i; |
8a48ecb8 MM |
240 | } |
241 | ||
e35ef181 MM |
242 | void |
243 | if_start_update(void) | |
244 | { | |
245 | struct iface *i; | |
9a158361 | 246 | struct ifa *a; |
e35ef181 MM |
247 | |
248 | WALK_LIST(i, iface_list) | |
9a158361 MM |
249 | { |
250 | i->flags &= ~IF_UPDATED; | |
251 | WALK_LIST(a, i->addrs) | |
252 | a->flags &= ~IF_UPDATED; | |
253 | } | |
254 | } | |
255 | ||
256 | void | |
257 | if_end_partial_update(struct iface *i) | |
258 | { | |
259 | if (i->flags & IF_TMP_DOWN) | |
260 | if_change_flags(i, i->flags & ~IF_TMP_DOWN); | |
e35ef181 MM |
261 | } |
262 | ||
8a48ecb8 MM |
263 | void |
264 | if_end_update(void) | |
265 | { | |
266 | struct iface *i, j; | |
9a158361 | 267 | struct ifa *a, *b; |
8a48ecb8 | 268 | |
4e9498cb MM |
269 | if (!config->router_id) |
270 | auto_router_id(); | |
271 | ||
8a48ecb8 | 272 | WALK_LIST(i, iface_list) |
9a158361 MM |
273 | { |
274 | if (!(i->flags & IF_UPDATED)) | |
275 | if_change_flags(i, (i->flags & ~IF_LINK_UP) | IF_ADMIN_DOWN); | |
276 | else | |
277 | { | |
278 | WALK_LIST_DELSAFE(a, b, i->addrs) | |
279 | if (!(a->flags & IF_UPDATED)) | |
280 | ifa_delete(a); | |
281 | if_end_partial_update(i); | |
282 | } | |
283 | } | |
8a48ecb8 MM |
284 | } |
285 | ||
47b79306 MM |
286 | void |
287 | if_feed_baby(struct proto *p) | |
288 | { | |
289 | struct iface *i; | |
9a158361 | 290 | struct ifa *a; |
47b79306 | 291 | |
6a9f28b0 | 292 | if (!p->if_notify && !p->ifa_notify) /* shortcut */ |
47b79306 | 293 | return; |
6a9f28b0 | 294 | DBG("Announcing interfaces to new protocol %s\n", p->name); |
47b79306 | 295 | WALK_LIST(i, iface_list) |
9a158361 | 296 | { |
6a9f28b0 MM |
297 | if_send_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i); |
298 | if (i->flags & IF_UP) | |
9a158361 | 299 | WALK_LIST(a, i->addrs) |
6a9f28b0 | 300 | ifa_send_notify(p, IF_CHANGE_CREATE | IF_CHANGE_UP, a); |
9a158361 | 301 | } |
47b79306 MM |
302 | } |
303 | ||
e35ef181 MM |
304 | struct iface * |
305 | if_find_by_index(unsigned idx) | |
306 | { | |
307 | struct iface *i; | |
308 | ||
309 | WALK_LIST(i, iface_list) | |
310 | if (i->index == idx) | |
311 | return i; | |
312 | return NULL; | |
313 | } | |
314 | ||
9a158361 MM |
315 | struct iface * |
316 | if_find_by_name(char *name) | |
317 | { | |
318 | struct iface *i; | |
319 | ||
320 | WALK_LIST(i, iface_list) | |
321 | if (!strcmp(i->name, name)) | |
322 | return i; | |
323 | return NULL; | |
324 | } | |
325 | ||
326 | static int | |
327 | ifa_recalc_primary(struct iface *i) | |
328 | { | |
329 | struct ifa *a, *b = NULL; | |
330 | int res; | |
331 | ||
332 | WALK_LIST(a, i->addrs) | |
333 | { | |
334 | if (!(a->flags & IA_SECONDARY) && (!b || a->scope > b->scope)) | |
335 | b = a; | |
336 | a->flags &= ~IA_PRIMARY; | |
337 | } | |
338 | res = (b != i->addr); | |
339 | i->addr = b; | |
340 | if (b) | |
341 | { | |
342 | b->flags |= IA_PRIMARY; | |
343 | rem_node(&b->n); | |
344 | add_head(&i->addrs, &b->n); | |
345 | } | |
346 | return res; | |
347 | } | |
348 | ||
349 | struct ifa * | |
350 | ifa_update(struct ifa *a) | |
351 | { | |
352 | struct iface *i = a->iface; | |
353 | struct ifa *b; | |
354 | ||
355 | WALK_LIST(b, i->addrs) | |
356 | if (ipa_equal(b->ip, a->ip)) | |
357 | { | |
358 | if (ipa_equal(b->prefix, a->prefix) && | |
359 | b->pxlen == a->pxlen && | |
360 | ipa_equal(b->brd, a->brd) && | |
361 | ipa_equal(b->opposite, a->opposite) && | |
6a636392 MM |
362 | b->scope == a->scope && |
363 | !((b->flags ^ a->flags) & IA_UNNUMBERED)) | |
9a158361 MM |
364 | { |
365 | b->flags |= IF_UPDATED; | |
366 | return b; | |
367 | } | |
368 | ifa_delete(b); | |
369 | break; | |
370 | } | |
6a636392 MM |
371 | |
372 | if (!(i->flags & IF_MULTIACCESS) && a->pxlen < BITS_PER_IP_ADDRESS - 2) | |
373 | log(L_WARN "Strange prefix length %d for point-to-point interface %s", a->pxlen, i->name); | |
374 | if ((i->flags & IF_BROADCAST) && !ipa_nonzero(a->brd)) | |
375 | log(L_ERR "Missing broadcast address for interface %s", i->name); | |
376 | ||
9a158361 MM |
377 | b = mb_alloc(if_pool, sizeof(struct ifa)); |
378 | memcpy(b, a, sizeof(struct ifa)); | |
379 | add_tail(&i->addrs, &b->n); | |
380 | b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS); | |
381 | if ((!i->addr || i->addr->scope < b->scope) && ifa_recalc_primary(i)) | |
382 | if_change_flags(i, i->flags | IF_TMP_DOWN); | |
383 | if (b->flags & IF_UP) | |
384 | ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b); | |
385 | return b; | |
386 | } | |
387 | ||
388 | void | |
389 | ifa_delete(struct ifa *a) | |
390 | { | |
391 | struct iface *i = a->iface; | |
392 | struct ifa *b; | |
393 | ||
394 | WALK_LIST(b, i->addrs) | |
395 | if (ipa_equal(b->ip, a->ip)) | |
396 | { | |
397 | rem_node(&b->n); | |
398 | if (b->flags & IF_UP) | |
399 | { | |
400 | b->flags &= ~IF_UP; | |
401 | ifa_notify_change(IF_CHANGE_DOWN, b); | |
402 | } | |
403 | if (b->flags & IA_PRIMARY) | |
404 | { | |
405 | if_change_flags(i, i->flags | IF_TMP_DOWN); | |
406 | ifa_recalc_primary(i); | |
407 | } | |
408 | mb_free(b); | |
a2697f02 | 409 | return; |
9a158361 MM |
410 | } |
411 | } | |
412 | ||
4e9498cb | 413 | static void |
dce26783 | 414 | auto_router_id(void) |
7d832907 | 415 | { |
dce26783 | 416 | #ifndef IPV6 |
7d832907 MM |
417 | struct iface *i, *j; |
418 | ||
7d832907 MM |
419 | j = NULL; |
420 | WALK_LIST(i, iface_list) | |
9a158361 | 421 | if ((i->flags & IF_LINK_UP) && |
6a636392 | 422 | !(i->flags & (IF_IGNORE | IF_ADMIN_DOWN)) && |
9a158361 | 423 | i->addr && |
6a636392 | 424 | !(i->addr->flags & IA_UNNUMBERED) && |
9a158361 | 425 | (!j || ipa_to_u32(i->addr->ip) < ipa_to_u32(j->addr->ip))) |
7d832907 | 426 | j = i; |
31b3e1bb | 427 | if (!j) |
4e9498cb | 428 | die("Cannot determine router ID (no suitable network interface found), please configure it manually"); |
6b9fa320 | 429 | log(L_INFO "Guessed router ID %I according to interface %s", j->addr->ip, j->name); |
9a158361 | 430 | config->router_id = ipa_to_u32(j->addr->ip); |
dce26783 | 431 | #endif |
7d832907 MM |
432 | } |
433 | ||
8a48ecb8 MM |
434 | void |
435 | if_init(void) | |
436 | { | |
437 | if_pool = rp_new(&root_pool, "Interfaces"); | |
438 | init_list(&iface_list); | |
85053fce | 439 | neigh_init(if_pool); |
8a48ecb8 | 440 | } |
ed45f2e1 MM |
441 | |
442 | /* | |
443 | * Interface Pattern Lists | |
444 | */ | |
445 | ||
446 | struct iface_patt * | |
447 | iface_patt_match(list *l, struct iface *i) | |
448 | { | |
449 | struct iface_patt *p; | |
450 | ||
451 | WALK_LIST(p, *l) | |
452 | { | |
453 | char *t = p->pattern; | |
454 | int ok = 1; | |
8edf2361 | 455 | if (t) |
ed45f2e1 | 456 | { |
8edf2361 MM |
457 | if (*t == '-') |
458 | { | |
459 | t++; | |
460 | ok = 0; | |
461 | } | |
462 | if (!patmatch(t, i->name)) | |
463 | continue; | |
ed45f2e1 | 464 | } |
8edf2361 MM |
465 | if (!i->addr || !ipa_in_net(i->addr->ip, p->prefix, p->pxlen)) |
466 | continue; | |
467 | return ok ? p : NULL; | |
ed45f2e1 MM |
468 | } |
469 | return NULL; | |
470 | } | |
471 | ||
472 | int | |
473 | iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct iface_patt *)) | |
474 | { | |
475 | struct iface_patt *x, *y; | |
476 | ||
477 | x = HEAD(*a); | |
478 | y = HEAD(*b); | |
479 | while (x->n.next && y->n.next) | |
480 | { | |
8edf2361 MM |
481 | if (strcmp(x->pattern, y->pattern) || |
482 | !ipa_equal(x->prefix, y->prefix) || | |
483 | x->pxlen != y->pxlen || | |
484 | comp && !comp(x, y)) | |
ed45f2e1 MM |
485 | return 0; |
486 | x = (void *) x->n.next; | |
487 | y = (void *) y->n.next; | |
488 | } | |
489 | return (!x->n.next && !y->n.next); | |
490 | } | |
ae97b946 MM |
491 | |
492 | /* | |
493 | * CLI commands. | |
494 | */ | |
495 | ||
496 | static void | |
497 | if_show_addr(struct ifa *a) | |
498 | { | |
499 | byte broad[STD_ADDRESS_P_LENGTH + 16]; | |
500 | byte opp[STD_ADDRESS_P_LENGTH + 16]; | |
501 | ||
502 | if (ipa_nonzero(a->brd)) | |
503 | bsprintf(broad, ", broadcast %I", a->brd); | |
504 | else | |
505 | broad[0] = 0; | |
506 | if (ipa_nonzero(a->opposite)) | |
507 | bsprintf(opp, ", opposite %I", a->opposite); | |
508 | else | |
509 | opp[0] = 0; | |
6a636392 | 510 | cli_msg(-1003, "\t%I/%d (%s%s%s, scope %s%s)", |
ae97b946 MM |
511 | a->ip, a->pxlen, |
512 | (a->flags & IA_PRIMARY) ? "Primary" : (a->flags & IA_SECONDARY) ? "Secondary" : "???", | |
513 | broad, opp, | |
6a636392 MM |
514 | ip_scope_text(a->scope), |
515 | (a->flags & IA_UNNUMBERED) ? ", unnumbered" : ""); | |
ae97b946 MM |
516 | } |
517 | ||
518 | void | |
519 | if_show(void) | |
520 | { | |
521 | struct iface *i; | |
522 | struct ifa *a; | |
523 | char *type; | |
524 | ||
525 | WALK_LIST(i, iface_list) | |
526 | { | |
0d3e6bce | 527 | cli_msg(-1001, "%s %s (index=%d)", i->name, (i->flags & IF_UP) ? "up" : "DOWN", i->index); |
6a636392 | 528 | if (!(i->flags & IF_MULTIACCESS)) |
ae97b946 MM |
529 | type = "PtP"; |
530 | else | |
531 | type = "MultiAccess"; | |
0d3e6bce | 532 | cli_msg(-1004, "\t%s%s%s Admin%s Link%s%s%s MTU=%d", |
ae97b946 MM |
533 | type, |
534 | (i->flags & IF_BROADCAST) ? " Broadcast" : "", | |
535 | (i->flags & IF_MULTICAST) ? " Multicast" : "", | |
536 | (i->flags & IF_ADMIN_DOWN) ? "Down" : "Up", | |
537 | (i->flags & IF_LINK_UP) ? "Up" : "Down", | |
538 | (i->flags & IF_LOOPBACK) ? " Loopback" : "", | |
539 | (i->flags & IF_IGNORE) ? " Ignored" : "", | |
540 | i->mtu); | |
541 | if (i->addr) | |
542 | if_show_addr(i->addr); | |
543 | WALK_LIST(a, i->addrs) | |
544 | if (a != i->addr) | |
545 | if_show_addr(a); | |
546 | } | |
547 | cli_msg(0, ""); | |
548 | } | |
549 | ||
550 | void | |
551 | if_show_summary(void) | |
552 | { | |
553 | struct iface *i; | |
554 | byte addr[STD_ADDRESS_P_LENGTH + 16]; | |
555 | ||
0d3e6bce | 556 | cli_msg(-2005, "interface state address"); |
ae97b946 MM |
557 | WALK_LIST(i, iface_list) |
558 | { | |
559 | if (i->addr) | |
560 | bsprintf(addr, "%I/%d", i->addr->ip, i->addr->pxlen); | |
561 | else | |
562 | addr[0] = 0; | |
0d3e6bce | 563 | cli_msg(-1005, "%-9s %-5s %s", i->name, (i->flags & IF_UP) ? "up" : "DOWN", addr); |
ae97b946 MM |
564 | } |
565 | cli_msg(0, ""); | |
566 | } |