]> git.ipfire.org Git - thirdparty/bird.git/blob - nest/iface.c
`show interfaces' and `show protocols' works.
[thirdparty/bird.git] / nest / iface.c
1 /*
2 * BIRD -- Management of Interfaces and Neighbor Cache
3 *
4 * (c) 1998--1999 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #define LOCAL_DEBUG
10
11 #include "nest/bird.h"
12 #include "nest/iface.h"
13 #include "nest/protocol.h"
14 #include "nest/cli.h"
15 #include "lib/resource.h"
16 #include "lib/string.h"
17 #include "conf/conf.h"
18
19 static pool *if_pool;
20
21 static void auto_router_id(void);
22
23 /*
24 * Neighbor Cache
25 *
26 * FIXME: Use hashing to get some real speed.
27 */
28
29 static slab *neigh_slab;
30 static list neigh_list;
31
32 static int
33 if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */
34 {
35 struct ifa *b;
36
37 if (!(i->flags & IF_UP))
38 return 0;
39 if ((i->flags & IF_UNNUMBERED) && ipa_equal(*a, i->addr->opposite))
40 return 1;
41 WALK_LIST(b, i->addrs)
42 if (ipa_in_net(*a, b->prefix, b->pxlen))
43 {
44 if (ipa_equal(*a, b->prefix) || /* Network address */
45 ipa_equal(*a, b->brd) || /* Broadcast */
46 ipa_equal(*a, b->ip)) /* Our own address */
47 return -1;
48 return 1;
49 }
50 return 0;
51 }
52
53 neighbor *
54 neigh_find(struct proto *p, ip_addr *a, unsigned flags)
55 {
56 neighbor *n;
57 int class;
58 struct iface *i, *j;
59
60 WALK_LIST(n, neigh_list)
61 if (n->proto == p && ipa_equal(*a, n->addr))
62 return n;
63
64 class = ipa_classify(*a);
65 if (class < 0) /* Invalid address */
66 return NULL;
67 if ((class & IADDR_SCOPE_MASK) < SCOPE_SITE ||
68 !(class & IADDR_HOST))
69 return NULL; /* Bad scope or a somecast */
70
71 j = NULL;
72 WALK_LIST(i, iface_list)
73 switch (if_connected(a, i))
74 {
75 case -1:
76 return NULL;
77 case 1:
78 if (!j) /* FIXME: Search for _optimal_ iface route? */
79 j = i;
80 /* Fall-thru */
81 }
82 if (!j && !(flags & NEF_STICKY))
83 return NULL;
84
85 n = sl_alloc(neigh_slab);
86 n->addr = *a;
87 n->iface = j;
88 add_tail(&neigh_list, &n->n);
89 if (j)
90 {
91 n->sibling = j->neigh;
92 j->neigh = n;
93 }
94 else
95 n->sibling = NULL;
96 n->proto = p;
97 n->data = NULL;
98 n->flags = flags;
99 return n;
100 }
101
102 void
103 neigh_dump(neighbor *n)
104 {
105 debug("%p %I ", n, n->addr);
106 if (n->iface)
107 debug("%s ", n->iface->name);
108 else
109 debug("[] ");
110 debug("%s %p", n->proto->name, n->data);
111 if (n->flags & NEF_STICKY)
112 debug(" STICKY");
113 debug("\n");
114 }
115
116 void
117 neigh_dump_all(void)
118 {
119 neighbor *n;
120
121 debug("Known neighbors:\n");
122 WALK_LIST(n, neigh_list)
123 neigh_dump(n);
124 debug("\n");
125 }
126
127 static void
128 neigh_if_up(struct iface *i)
129 {
130 neighbor *n;
131
132 WALK_LIST(n, neigh_list)
133 if (!n->iface &&
134 if_connected(&n->addr, i) > 0)
135 {
136 n->iface = i;
137 n->sibling = i->neigh;
138 i->neigh = n;
139 DBG("Waking up sticky neighbor %I\n", n->addr);
140 if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
141 n->proto->neigh_notify(n);
142 }
143 }
144
145 static void
146 neigh_if_down(struct iface *i)
147 {
148 neighbor *n, *m;
149
150 for(m=i->neigh; n = m;)
151 {
152 m = n->sibling;
153 DBG("Flushing neighbor %I on %s\n", n->addr, i->name);
154 n->iface = NULL;
155 if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
156 n->proto->neigh_notify(n);
157 if (!(n->flags & NEF_STICKY))
158 {
159 rem_node(&n->n);
160 sl_free(neigh_slab, n);
161 }
162 }
163 i->neigh = NULL;
164 }
165
166 void
167 neigh_prune(void)
168 {
169 neighbor *n, *m, **N;
170 struct iface *i;
171
172 DBG("Pruning neighbors\n");
173 WALK_LIST(i, iface_list)
174 {
175 N = &i->neigh;
176 while (n = *N)
177 {
178 if (n->proto->core_state == FS_FLUSHING)
179 {
180 *N = n->sibling;
181 rem_node(&n->n);
182 sl_free(neigh_slab, n);
183 continue;
184 }
185 N = &n->sibling;
186 }
187 }
188 }
189
190 /*
191 * The Interface List
192 */
193
194 list iface_list;
195
196 void
197 ifa_dump(struct ifa *a)
198 {
199 debug("\t%I, net %I/%-2d bc %I -> %I%s%s\n", a->ip, a->prefix, a->pxlen, a->brd, a->opposite,
200 (a->flags & IF_UP) ? "" : " DOWN",
201 (a->flags & IA_PRIMARY) ? "" : " SEC");
202 }
203
204 void
205 if_dump(struct iface *i)
206 {
207 struct ifa *a;
208
209 debug("IF%d: %s", i->index, i->name);
210 if (i->flags & IF_ADMIN_DOWN)
211 debug(" ADMIN-DOWN");
212 if (i->flags & IF_UP)
213 debug(" UP");
214 else
215 debug(" DOWN");
216 if (i->flags & IF_LINK_UP)
217 debug(" LINK-UP");
218 if (i->flags & IF_MULTIACCESS)
219 debug(" MA");
220 if (i->flags & IF_UNNUMBERED)
221 debug(" UNNUM");
222 if (i->flags & IF_BROADCAST)
223 debug(" BC");
224 if (i->flags & IF_MULTICAST)
225 debug(" MC");
226 if (i->flags & IF_TUNNEL)
227 debug(" TUNL");
228 if (i->flags & IF_LOOPBACK)
229 debug(" LOOP");
230 if (i->flags & IF_IGNORE)
231 debug(" IGN");
232 if (i->flags & IF_TMP_DOWN)
233 debug(" TDOWN");
234 debug(" MTU=%d\n", i->mtu);
235 WALK_LIST(a, i->addrs)
236 {
237 ifa_dump(a);
238 ASSERT((a != i->addr) == !(a->flags & IA_PRIMARY));
239 }
240 }
241
242 void
243 if_dump_all(void)
244 {
245 struct iface *i;
246
247 debug("Known network interfaces:\n");
248 WALK_LIST(i, iface_list)
249 if_dump(i);
250 debug("Router ID: %08x\n", config->router_id);
251 }
252
253 static inline unsigned
254 if_what_changed(struct iface *i, struct iface *j)
255 {
256 unsigned c;
257
258 if (((i->flags ^ j->flags) & ~(IF_UP | IF_ADMIN_DOWN | IF_UPDATED | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED))
259 || i->index != j->index)
260 return IF_CHANGE_TOO_MUCH;
261 c = 0;
262 if ((i->flags ^ j->flags) & IF_UP)
263 c |= (i->flags & IF_UP) ? IF_CHANGE_DOWN : IF_CHANGE_UP;
264 if (i->mtu != j->mtu)
265 c |= IF_CHANGE_MTU;
266 return c;
267 }
268
269 static inline void
270 if_copy(struct iface *to, struct iface *from)
271 {
272 to->flags = from->flags | (to->flags & IF_TMP_DOWN);
273 to->mtu = from->mtu;
274 }
275
276 static void
277 ifa_notify_change(unsigned c, struct ifa *a)
278 {
279 struct proto *p;
280
281 debug("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip);
282 WALK_LIST(p, proto_list)
283 if (p->ifa_notify)
284 p->ifa_notify(p, c, a);
285 }
286
287 static void
288 if_notify_change(unsigned c, struct iface *i)
289 {
290 struct proto *p;
291 struct ifa *a;
292
293 if (i->flags & IF_JUST_CREATED)
294 {
295 i->flags &= ~IF_JUST_CREATED;
296 c |= IF_CHANGE_CREATE | IF_CHANGE_MTU;
297 }
298
299 debug("Interface change notification (%x) for %s\n", c, i->name);
300 if_dump(i);
301
302 if (c & IF_CHANGE_UP)
303 neigh_if_up(i);
304 if (c & IF_CHANGE_DOWN)
305 WALK_LIST(a, i->addrs)
306 {
307 a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
308 ifa_notify_change(IF_CHANGE_DOWN, a);
309 }
310
311 WALK_LIST(p, proto_list)
312 if (p->if_notify)
313 p->if_notify(p, c, i);
314
315 if (c & IF_CHANGE_UP)
316 WALK_LIST(a, i->addrs)
317 {
318 a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
319 ifa_notify_change(IF_CHANGE_UP, a);
320 }
321 if (c & IF_CHANGE_DOWN)
322 neigh_if_down(i);
323 }
324
325 static unsigned
326 if_recalc_flags(struct iface *i, unsigned flags)
327 {
328 if ((flags & (IF_ADMIN_DOWN | IF_TMP_DOWN)) ||
329 !(flags & IF_LINK_UP) ||
330 !i->addr)
331 flags &= ~IF_UP;
332 else
333 flags |= IF_UP;
334 return flags;
335 }
336
337 static void
338 if_change_flags(struct iface *i, unsigned flags)
339 {
340 unsigned of = i->flags;
341
342 i->flags = if_recalc_flags(i, flags);
343 if ((i->flags ^ of) & IF_UP)
344 if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i);
345 }
346
347 struct iface *
348 if_update(struct iface *new)
349 {
350 struct iface *i;
351 struct ifa *a, *b;
352 unsigned c;
353
354 WALK_LIST(i, iface_list)
355 if (!strcmp(new->name, i->name))
356 {
357 new->addr = i->addr;
358 new->flags = if_recalc_flags(new, new->flags);
359 c = if_what_changed(i, new);
360 if (c & IF_CHANGE_TOO_MUCH) /* Changed a lot, convert it to down/up */
361 {
362 DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
363 if_change_flags(i, i->flags | IF_TMP_DOWN);
364 rem_node(&i->n);
365 new->addr = i->addr;
366 memcpy(&new->addrs, &i->addrs, sizeof(i->addrs));
367 memcpy(i, new, sizeof(*i));
368 goto newif;
369 }
370 else if (c)
371 {
372 if_copy(i, new);
373 if_notify_change(c, i);
374 }
375 i->flags |= IF_UPDATED;
376 return i;
377 }
378 i = mb_alloc(if_pool, sizeof(struct iface));
379 memcpy(i, new, sizeof(*i));
380 init_list(&i->addrs);
381 newif:
382 i->flags |= IF_UPDATED | IF_TMP_DOWN; /* Tmp down as we don't have addresses yet */
383 add_tail(&iface_list, &i->n);
384 return i;
385 }
386
387 void
388 if_start_update(void)
389 {
390 struct iface *i;
391 struct ifa *a;
392
393 WALK_LIST(i, iface_list)
394 {
395 i->flags &= ~IF_UPDATED;
396 WALK_LIST(a, i->addrs)
397 a->flags &= ~IF_UPDATED;
398 }
399 }
400
401 void
402 if_end_partial_update(struct iface *i)
403 {
404 if (i->flags & IF_TMP_DOWN)
405 if_change_flags(i, i->flags & ~IF_TMP_DOWN);
406 }
407
408 void
409 if_end_update(void)
410 {
411 struct iface *i, j;
412 struct ifa *a, *b;
413
414 if (!config->router_id)
415 auto_router_id();
416
417 WALK_LIST(i, iface_list)
418 {
419 if (!(i->flags & IF_UPDATED))
420 if_change_flags(i, (i->flags & ~IF_LINK_UP) | IF_ADMIN_DOWN);
421 else
422 {
423 WALK_LIST_DELSAFE(a, b, i->addrs)
424 if (!(a->flags & IF_UPDATED))
425 ifa_delete(a);
426 if_end_partial_update(i);
427 }
428 }
429 }
430
431 void
432 if_feed_baby(struct proto *p)
433 {
434 struct iface *i;
435 struct ifa *a;
436
437 if (!p->if_notify && !p->ifa_notify)
438 return;
439 debug("Announcing interfaces to new protocol %s\n", p->name);
440 WALK_LIST(i, iface_list)
441 {
442 if (p->if_notify)
443 p->if_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i);
444 if (p->ifa_notify && (i->flags & IF_UP))
445 WALK_LIST(a, i->addrs)
446 p->ifa_notify(p, IF_CHANGE_CREATE | IF_CHANGE_UP, a);
447 }
448 }
449
450 struct iface *
451 if_find_by_index(unsigned idx)
452 {
453 struct iface *i;
454
455 WALK_LIST(i, iface_list)
456 if (i->index == idx)
457 return i;
458 return NULL;
459 }
460
461 struct iface *
462 if_find_by_name(char *name)
463 {
464 struct iface *i;
465
466 WALK_LIST(i, iface_list)
467 if (!strcmp(i->name, name))
468 return i;
469 return NULL;
470 }
471
472 static int
473 ifa_recalc_primary(struct iface *i)
474 {
475 struct ifa *a, *b = NULL;
476 int res;
477
478 WALK_LIST(a, i->addrs)
479 {
480 if (!(a->flags & IA_SECONDARY) && (!b || a->scope > b->scope))
481 b = a;
482 a->flags &= ~IA_PRIMARY;
483 }
484 res = (b != i->addr);
485 i->addr = b;
486 if (b)
487 {
488 b->flags |= IA_PRIMARY;
489 rem_node(&b->n);
490 add_head(&i->addrs, &b->n);
491 }
492 return res;
493 }
494
495 struct ifa *
496 ifa_update(struct ifa *a)
497 {
498 struct iface *i = a->iface;
499 struct ifa *b;
500
501 WALK_LIST(b, i->addrs)
502 if (ipa_equal(b->ip, a->ip))
503 {
504 if (ipa_equal(b->prefix, a->prefix) &&
505 b->pxlen == a->pxlen &&
506 ipa_equal(b->brd, a->brd) &&
507 ipa_equal(b->opposite, a->opposite) &&
508 b->scope == a->scope)
509 {
510 b->flags |= IF_UPDATED;
511 return b;
512 }
513 ifa_delete(b);
514 break;
515 }
516 b = mb_alloc(if_pool, sizeof(struct ifa));
517 memcpy(b, a, sizeof(struct ifa));
518 add_tail(&i->addrs, &b->n);
519 b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
520 if ((!i->addr || i->addr->scope < b->scope) && ifa_recalc_primary(i))
521 if_change_flags(i, i->flags | IF_TMP_DOWN);
522 if (b->flags & IF_UP)
523 ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
524 return b;
525 }
526
527 void
528 ifa_delete(struct ifa *a)
529 {
530 struct iface *i = a->iface;
531 struct ifa *b;
532
533 WALK_LIST(b, i->addrs)
534 if (ipa_equal(b->ip, a->ip))
535 {
536 rem_node(&b->n);
537 if (b->flags & IF_UP)
538 {
539 b->flags &= ~IF_UP;
540 ifa_notify_change(IF_CHANGE_DOWN, b);
541 }
542 if (b->flags & IA_PRIMARY)
543 {
544 if_change_flags(i, i->flags | IF_TMP_DOWN);
545 ifa_recalc_primary(i);
546 }
547 mb_free(b);
548 return;
549 }
550 }
551
552 static void
553 auto_router_id(void)
554 {
555 #ifndef IPV6
556 struct iface *i, *j;
557
558 j = NULL;
559 WALK_LIST(i, iface_list)
560 if ((i->flags & IF_LINK_UP) &&
561 !(i->flags & (IF_UNNUMBERED | IF_IGNORE | IF_ADMIN_DOWN)) &&
562 i->addr &&
563 (!j || ipa_to_u32(i->addr->ip) < ipa_to_u32(j->addr->ip)))
564 j = i;
565 if (!j)
566 die("Cannot determine router ID (no suitable network interface found), please configure it manually");
567 debug("Guessed router ID %I (%s)\n", j->addr->ip, j->name);
568 config->router_id = ipa_to_u32(j->addr->ip);
569 #endif
570 }
571
572 void
573 if_init(void)
574 {
575 if_pool = rp_new(&root_pool, "Interfaces");
576 init_list(&iface_list);
577 neigh_slab = sl_new(if_pool, sizeof(neighbor));
578 init_list(&neigh_list);
579 }
580
581 /*
582 * Interface Pattern Lists
583 */
584
585 struct iface_patt *
586 iface_patt_match(list *l, struct iface *i)
587 {
588 struct iface_patt *p;
589
590 WALK_LIST(p, *l)
591 {
592 char *t = p->pattern;
593 int ok = 1;
594 if (t)
595 {
596 if (*t == '-')
597 {
598 t++;
599 ok = 0;
600 }
601 if (!patmatch(t, i->name))
602 continue;
603 }
604 if (!i->addr || !ipa_in_net(i->addr->ip, p->prefix, p->pxlen))
605 continue;
606 return ok ? p : NULL;
607 }
608 return NULL;
609 }
610
611 int
612 iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct iface_patt *))
613 {
614 struct iface_patt *x, *y;
615
616 x = HEAD(*a);
617 y = HEAD(*b);
618 while (x->n.next && y->n.next)
619 {
620 if (strcmp(x->pattern, y->pattern) ||
621 !ipa_equal(x->prefix, y->prefix) ||
622 x->pxlen != y->pxlen ||
623 comp && !comp(x, y))
624 return 0;
625 x = (void *) x->n.next;
626 y = (void *) y->n.next;
627 }
628 return (!x->n.next && !y->n.next);
629 }
630
631 /*
632 * CLI commands.
633 */
634
635 static void
636 if_show_addr(struct ifa *a)
637 {
638 byte broad[STD_ADDRESS_P_LENGTH + 16];
639 byte opp[STD_ADDRESS_P_LENGTH + 16];
640
641 if (ipa_nonzero(a->brd))
642 bsprintf(broad, ", broadcast %I", a->brd);
643 else
644 broad[0] = 0;
645 if (ipa_nonzero(a->opposite))
646 bsprintf(opp, ", opposite %I", a->opposite);
647 else
648 opp[0] = 0;
649 cli_msg(-1003, "\t%I/%d (%s%s%s, scope %s)",
650 a->ip, a->pxlen,
651 (a->flags & IA_PRIMARY) ? "Primary" : (a->flags & IA_SECONDARY) ? "Secondary" : "???",
652 broad, opp,
653 ip_scope_text(a->scope));
654 }
655
656 void
657 if_show(void)
658 {
659 struct iface *i;
660 struct ifa *a;
661 char *type;
662
663 WALK_LIST(i, iface_list)
664 {
665 cli_msg(-1001, "%s %s (index=%d)", i->name, (i->flags & IF_UP) ? "up" : "DOWN", i->index);
666 if (i->flags & IF_UNNUMBERED)
667 type = "UnNum-PtP";
668 else if (!(i->flags & IF_MULTIACCESS))
669 type = "PtP";
670 else
671 type = "MultiAccess";
672 cli_msg(-1004, "\t%s%s%s Admin%s Link%s%s%s MTU=%d",
673 type,
674 (i->flags & IF_BROADCAST) ? " Broadcast" : "",
675 (i->flags & IF_MULTICAST) ? " Multicast" : "",
676 (i->flags & IF_ADMIN_DOWN) ? "Down" : "Up",
677 (i->flags & IF_LINK_UP) ? "Up" : "Down",
678 (i->flags & IF_LOOPBACK) ? " Loopback" : "",
679 (i->flags & IF_IGNORE) ? " Ignored" : "",
680 i->mtu);
681 if (i->addr)
682 if_show_addr(i->addr);
683 WALK_LIST(a, i->addrs)
684 if (a != i->addr)
685 if_show_addr(a);
686 }
687 cli_msg(0, "");
688 }
689
690 void
691 if_show_summary(void)
692 {
693 struct iface *i;
694 byte addr[STD_ADDRESS_P_LENGTH + 16];
695
696 cli_msg(-2005, "interface state address");
697 WALK_LIST(i, iface_list)
698 {
699 if (i->addr)
700 bsprintf(addr, "%I/%d", i->addr->ip, i->addr->pxlen);
701 else
702 addr[0] = 0;
703 cli_msg(-1005, "%-9s %-5s %s", i->name, (i->flags & IF_UP) ? "up" : "DOWN", addr);
704 }
705 cli_msg(0, "");
706 }