]> git.ipfire.org Git - thirdparty/bird.git/blame - nest/iface.c
Great cleanup of debug messages. LOCAL_DEBUG turned off in most modules,
[thirdparty/bird.git] / nest / iface.c
CommitLineData
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
19static pool *if_pool;
20
4e9498cb
MM
21static void auto_router_id(void);
22
4cc78c50
MM
23list iface_list;
24
9a158361
MM
25void
26ifa_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
34void
35if_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
68void
69if_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
79static inline unsigned
80if_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
95static inline void
4cc78c50 96if_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
102static inline void
103ifa_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
116static void
117ifa_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
126static inline void
127if_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
142static void
9a158361 143if_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
179static unsigned
180if_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
191static void
192if_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
201struct iface *
8a48ecb8
MM
202if_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 236newif:
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
242void
243if_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
256void
257if_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
263void
264if_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
286void
287if_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
304struct iface *
305if_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
315struct iface *
316if_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
326static int
327ifa_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
349struct ifa *
350ifa_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
388void
389ifa_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 413static void
dce26783 414auto_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
434void
435if_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
446struct iface_patt *
447iface_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
472int
473iface_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
496static void
497if_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
518void
519if_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
550void
551if_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}