]>
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 | ||
3d675cdb MM |
9 | /** |
10 | * DOC: Interfaces | |
11 | * | |
12 | * The interface module keeps track of all network interfaces in the | |
13 | * system and their addresses. | |
14 | * | |
15 | * Each interface is represented by an &iface structure which carries | |
16 | * interface capability flags (%IF_MULTIACCESS, %IF_BROADCAST etc.), | |
17 | * MTU, interface name and index and finally a linked list of network | |
18 | * prefixes assigned to the interface, each one represented by | |
19 | * struct &ifa. | |
20 | * | |
21 | * The interface module keeps a `soft-up' state for each &iface which | |
22 | * is a conjunction of link being up, the interface being of a `sane' | |
23 | * type and at least one IP address assigned to it. | |
24 | */ | |
25 | ||
6a9f28b0 | 26 | #undef LOCAL_DEBUG |
4cc78c50 | 27 | |
8a48ecb8 MM |
28 | #include "nest/bird.h" |
29 | #include "nest/iface.h" | |
4cc78c50 | 30 | #include "nest/protocol.h" |
ae97b946 | 31 | #include "nest/cli.h" |
8a48ecb8 | 32 | #include "lib/resource.h" |
ed45f2e1 | 33 | #include "lib/string.h" |
4e9498cb | 34 | #include "conf/conf.h" |
8a48ecb8 | 35 | |
8a48ecb8 MM |
36 | static pool *if_pool; |
37 | ||
4cc78c50 MM |
38 | list iface_list; |
39 | ||
3d675cdb MM |
40 | /** |
41 | * ifa_dump - dump interface address | |
42 | * @a: interface address descriptor | |
43 | * | |
44 | * This function dumps contents of an &ifa to the debug output. | |
45 | */ | |
9a158361 MM |
46 | void |
47 | ifa_dump(struct ifa *a) | |
48 | { | |
6a636392 | 49 | debug("\t%I, net %I/%-2d bc %I -> %I%s%s%s\n", a->ip, a->prefix, a->pxlen, a->brd, a->opposite, |
9a158361 | 50 | (a->flags & IF_UP) ? "" : " DOWN", |
6a636392 | 51 | (a->flags & IA_PRIMARY) ? "" : " SEC", |
52a43ae3 | 52 | (a->flags & IA_PEER) ? "PEER" : ""); |
9a158361 MM |
53 | } |
54 | ||
3d675cdb MM |
55 | /** |
56 | * if_dump - dump interface | |
57 | * @i: interface to dump | |
58 | * | |
59 | * This function dumps all information associated with a given | |
60 | * network interface to the debug output. | |
61 | */ | |
4cc78c50 MM |
62 | void |
63 | if_dump(struct iface *i) | |
64 | { | |
9a158361 MM |
65 | struct ifa *a; |
66 | ||
8a48ecb8 | 67 | debug("IF%d: %s", i->index, i->name); |
f25cb0ef OZ |
68 | if (i->flags & IF_SHUTDOWN) |
69 | debug(" SHUTDOWN"); | |
8a48ecb8 MM |
70 | if (i->flags & IF_UP) |
71 | debug(" UP"); | |
bcbd8cc3 MM |
72 | else |
73 | debug(" DOWN"); | |
f25cb0ef | 74 | if (i->flags & IF_ADMIN_UP) |
bcbd8cc3 | 75 | debug(" LINK-UP"); |
8a48ecb8 MM |
76 | if (i->flags & IF_MULTIACCESS) |
77 | debug(" MA"); | |
8a48ecb8 MM |
78 | if (i->flags & IF_BROADCAST) |
79 | debug(" BC"); | |
80 | if (i->flags & IF_MULTICAST) | |
81 | debug(" MC"); | |
8a48ecb8 MM |
82 | if (i->flags & IF_LOOPBACK) |
83 | debug(" LOOP"); | |
84 | if (i->flags & IF_IGNORE) | |
85 | debug(" IGN"); | |
9a158361 MM |
86 | if (i->flags & IF_TMP_DOWN) |
87 | debug(" TDOWN"); | |
8a48ecb8 | 88 | debug(" MTU=%d\n", i->mtu); |
9a158361 MM |
89 | WALK_LIST(a, i->addrs) |
90 | { | |
91 | ifa_dump(a); | |
92 | ASSERT((a != i->addr) == !(a->flags & IA_PRIMARY)); | |
93 | } | |
8a48ecb8 MM |
94 | } |
95 | ||
3d675cdb MM |
96 | /** |
97 | * if_dump_all - dump all interfaces | |
98 | * | |
99 | * This function dumps information about all known network | |
100 | * interfaces to the debug output. | |
101 | */ | |
8a48ecb8 MM |
102 | void |
103 | if_dump_all(void) | |
104 | { | |
105 | struct iface *i; | |
106 | ||
620a355a | 107 | debug("Known network interfaces:\n"); |
8a48ecb8 MM |
108 | WALK_LIST(i, iface_list) |
109 | if_dump(i); | |
4e9498cb | 110 | debug("Router ID: %08x\n", config->router_id); |
8a48ecb8 MM |
111 | } |
112 | ||
9a158361 MM |
113 | static inline unsigned |
114 | if_what_changed(struct iface *i, struct iface *j) | |
8a48ecb8 | 115 | { |
9a158361 MM |
116 | unsigned c; |
117 | ||
fe181e7c | 118 | if (((i->flags ^ j->flags) & ~(IF_UP | IF_SHUTDOWN | IF_UPDATED | IF_ADMIN_UP | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED)) |
9a158361 MM |
119 | || i->index != j->index) |
120 | return IF_CHANGE_TOO_MUCH; | |
121 | c = 0; | |
122 | if ((i->flags ^ j->flags) & IF_UP) | |
123 | c |= (i->flags & IF_UP) ? IF_CHANGE_DOWN : IF_CHANGE_UP; | |
f25cb0ef OZ |
124 | if ((i->flags ^ j->flags) & IF_LINK_UP) |
125 | c |= IF_CHANGE_LINK; | |
9a158361 MM |
126 | if (i->mtu != j->mtu) |
127 | c |= IF_CHANGE_MTU; | |
128 | return c; | |
8a48ecb8 MM |
129 | } |
130 | ||
131 | static inline void | |
4cc78c50 | 132 | if_copy(struct iface *to, struct iface *from) |
8a48ecb8 | 133 | { |
9a158361 | 134 | to->flags = from->flags | (to->flags & IF_TMP_DOWN); |
4cc78c50 | 135 | to->mtu = from->mtu; |
8a48ecb8 MM |
136 | } |
137 | ||
6a9f28b0 MM |
138 | static inline void |
139 | ifa_send_notify(struct proto *p, unsigned c, struct ifa *a) | |
140 | { | |
141 | if (p->ifa_notify) | |
142 | { | |
143 | if (p->debug & D_IFACES) | |
144 | log(L_TRACE "%s < %s address %I/%d on interface %s %s", | |
145 | p->name, (a->flags & IA_PRIMARY) ? "primary" : "secondary", | |
146 | a->prefix, a->pxlen, a->iface->name, | |
147 | (c & IF_CHANGE_UP) ? "added" : "removed"); | |
148 | p->ifa_notify(p, c, a); | |
149 | } | |
150 | } | |
151 | ||
9a158361 | 152 | static void |
cf7f0645 | 153 | ifa_notify_change_dep(unsigned c, struct ifa *a) |
8a48ecb8 | 154 | { |
9a158361 | 155 | struct proto *p; |
8a48ecb8 | 156 | |
6a9f28b0 | 157 | DBG("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip); |
cf7f0645 | 158 | |
f14a4bec | 159 | WALK_LIST(p, active_proto_list) |
6a9f28b0 MM |
160 | ifa_send_notify(p, c, a); |
161 | } | |
162 | ||
cf7f0645 OZ |
163 | static inline void |
164 | ifa_notify_change(unsigned c, struct ifa *a) | |
165 | { | |
166 | neigh_ifa_update(a); | |
167 | ifa_notify_change_dep(c, a); | |
168 | } | |
169 | ||
6a9f28b0 MM |
170 | static inline void |
171 | if_send_notify(struct proto *p, unsigned c, struct iface *i) | |
172 | { | |
173 | if (p->if_notify) | |
174 | { | |
175 | if (p->debug & D_IFACES) | |
176 | log(L_TRACE "%s < interface %s %s", p->name, i->name, | |
177 | (c & IF_CHANGE_UP) ? "goes up" : | |
178 | (c & IF_CHANGE_DOWN) ? "goes down" : | |
179 | (c & IF_CHANGE_MTU) ? "changes MTU" : | |
f25cb0ef | 180 | (c & IF_CHANGE_LINK) ? "changes link" : |
6a9f28b0 MM |
181 | (c & IF_CHANGE_CREATE) ? "created" : |
182 | "sends unknown event"); | |
183 | p->if_notify(p, c, i); | |
184 | } | |
8a48ecb8 MM |
185 | } |
186 | ||
187 | static void | |
9a158361 | 188 | if_notify_change(unsigned c, struct iface *i) |
8a48ecb8 | 189 | { |
d9f330c5 | 190 | struct proto *p; |
9a158361 | 191 | struct ifa *a; |
d9f330c5 | 192 | |
9a158361 MM |
193 | if (i->flags & IF_JUST_CREATED) |
194 | { | |
195 | i->flags &= ~IF_JUST_CREATED; | |
196 | c |= IF_CHANGE_CREATE | IF_CHANGE_MTU; | |
197 | } | |
198 | ||
6a9f28b0 | 199 | DBG("Interface change notification (%x) for %s\n", c, i->name); |
9a220cab | 200 | #ifdef LOCAL_DEBUG |
9a158361 | 201 | if_dump(i); |
9a220cab | 202 | #endif |
4cc78c50 MM |
203 | |
204 | if (c & IF_CHANGE_UP) | |
9a158361 | 205 | neigh_if_up(i); |
cf7f0645 | 206 | |
9a158361 MM |
207 | if (c & IF_CHANGE_DOWN) |
208 | WALK_LIST(a, i->addrs) | |
209 | { | |
210 | a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS); | |
cf7f0645 | 211 | ifa_notify_change_dep(IF_CHANGE_DOWN, a); |
9a158361 | 212 | } |
4cc78c50 | 213 | |
f14a4bec | 214 | WALK_LIST(p, active_proto_list) |
6a9f28b0 | 215 | if_send_notify(p, c, i); |
4cc78c50 | 216 | |
9a158361 MM |
217 | if (c & IF_CHANGE_UP) |
218 | WALK_LIST(a, i->addrs) | |
219 | { | |
220 | a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS); | |
cf7f0645 | 221 | ifa_notify_change_dep(IF_CHANGE_UP, a); |
9a158361 | 222 | } |
fe181e7c OZ |
223 | |
224 | if ((c & (IF_CHANGE_UP | IF_CHANGE_DOWN | IF_CHANGE_LINK)) == IF_CHANGE_LINK) | |
225 | neigh_if_link(i); | |
226 | ||
4cc78c50 | 227 | if (c & IF_CHANGE_DOWN) |
9a158361 | 228 | neigh_if_down(i); |
8a48ecb8 MM |
229 | } |
230 | ||
9a158361 MM |
231 | static unsigned |
232 | if_recalc_flags(struct iface *i, unsigned flags) | |
233 | { | |
f25cb0ef OZ |
234 | if ((flags & (IF_SHUTDOWN | IF_TMP_DOWN)) || |
235 | !(flags & IF_ADMIN_UP) || | |
9a158361 MM |
236 | !i->addr) |
237 | flags &= ~IF_UP; | |
238 | else | |
239 | flags |= IF_UP; | |
240 | return flags; | |
241 | } | |
242 | ||
243 | static void | |
244 | if_change_flags(struct iface *i, unsigned flags) | |
245 | { | |
246 | unsigned of = i->flags; | |
247 | ||
248 | i->flags = if_recalc_flags(i, flags); | |
249 | if ((i->flags ^ of) & IF_UP) | |
250 | if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i); | |
251 | } | |
252 | ||
732a0a25 OZ |
253 | /** |
254 | * if_delete - remove interface | |
255 | * @old: interface | |
256 | * | |
257 | * This function is called by the low-level platform dependent code | |
258 | * whenever it notices an interface disappears. It is just a shorthand | |
259 | * for if_update(). | |
260 | */ | |
261 | ||
262 | void | |
263 | if_delete(struct iface *old) | |
264 | { | |
265 | struct iface f = {}; | |
266 | strncpy(f.name, old->name, sizeof(f.name)-1); | |
267 | f.flags = IF_SHUTDOWN; | |
268 | if_update(&f); | |
269 | } | |
270 | ||
3d675cdb MM |
271 | /** |
272 | * if_update - update interface status | |
273 | * @new: new interface status | |
274 | * | |
275 | * if_update() is called by the low-level platform dependent code | |
276 | * whenever it notices an interface change. | |
277 | * | |
5c18880e | 278 | * There exist two types of interface updates -- synchronous and asynchronous |
3d675cdb MM |
279 | * ones. In the synchronous case, the low-level code calls if_start_update(), |
280 | * scans all interfaces reported by the OS, uses if_update() and ifa_update() | |
281 | * to pass them to the core and then it finishes the update sequence by | |
282 | * calling if_end_update(). When working asynchronously, the sysdep code | |
283 | * calls if_update() and ifa_update() whenever it notices a change. | |
284 | * | |
285 | * if_update() will automatically notify all other modules about the change. | |
286 | */ | |
9a158361 | 287 | struct iface * |
8a48ecb8 MM |
288 | if_update(struct iface *new) |
289 | { | |
290 | struct iface *i; | |
4cc78c50 | 291 | unsigned c; |
8a48ecb8 MM |
292 | |
293 | WALK_LIST(i, iface_list) | |
294 | if (!strcmp(new->name, i->name)) | |
295 | { | |
9a158361 MM |
296 | new->addr = i->addr; |
297 | new->flags = if_recalc_flags(new, new->flags); | |
298 | c = if_what_changed(i, new); | |
299 | if (c & IF_CHANGE_TOO_MUCH) /* Changed a lot, convert it to down/up */ | |
8a48ecb8 | 300 | { |
4cc78c50 | 301 | DBG("Interface %s changed too much -- forcing down/up transition\n", i->name); |
9a158361 | 302 | if_change_flags(i, i->flags | IF_TMP_DOWN); |
8a48ecb8 | 303 | rem_node(&i->n); |
a2697f02 MM |
304 | new->addr = i->addr; |
305 | memcpy(&new->addrs, &i->addrs, sizeof(i->addrs)); | |
306 | memcpy(i, new, sizeof(*i)); | |
09686693 | 307 | i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */ |
4cc78c50 | 308 | goto newif; |
8a48ecb8 | 309 | } |
bc092571 OZ |
310 | |
311 | if_copy(i, new); | |
312 | if (c) | |
313 | if_notify_change(c, i); | |
314 | ||
e35ef181 | 315 | i->flags |= IF_UPDATED; |
9a158361 | 316 | return i; |
8a48ecb8 | 317 | } |
4cc78c50 | 318 | i = mb_alloc(if_pool, sizeof(struct iface)); |
4cc78c50 | 319 | memcpy(i, new, sizeof(*i)); |
9a158361 | 320 | init_list(&i->addrs); |
a2697f02 | 321 | newif: |
287111fe | 322 | init_list(&i->neighbors); |
9a158361 | 323 | i->flags |= IF_UPDATED | IF_TMP_DOWN; /* Tmp down as we don't have addresses yet */ |
8a48ecb8 | 324 | add_tail(&iface_list, &i->n); |
9a158361 | 325 | return i; |
8a48ecb8 MM |
326 | } |
327 | ||
e35ef181 MM |
328 | void |
329 | if_start_update(void) | |
330 | { | |
331 | struct iface *i; | |
9a158361 | 332 | struct ifa *a; |
e35ef181 MM |
333 | |
334 | WALK_LIST(i, iface_list) | |
9a158361 MM |
335 | { |
336 | i->flags &= ~IF_UPDATED; | |
337 | WALK_LIST(a, i->addrs) | |
338 | a->flags &= ~IF_UPDATED; | |
339 | } | |
340 | } | |
341 | ||
342 | void | |
343 | if_end_partial_update(struct iface *i) | |
344 | { | |
345 | if (i->flags & IF_TMP_DOWN) | |
346 | if_change_flags(i, i->flags & ~IF_TMP_DOWN); | |
e35ef181 MM |
347 | } |
348 | ||
8a48ecb8 MM |
349 | void |
350 | if_end_update(void) | |
351 | { | |
93a786cb | 352 | struct iface *i; |
9a158361 | 353 | struct ifa *a, *b; |
8a48ecb8 MM |
354 | |
355 | WALK_LIST(i, iface_list) | |
9a158361 MM |
356 | { |
357 | if (!(i->flags & IF_UPDATED)) | |
f25cb0ef | 358 | if_change_flags(i, (i->flags & ~IF_ADMIN_UP) | IF_SHUTDOWN); |
9a158361 MM |
359 | else |
360 | { | |
361 | WALK_LIST_DELSAFE(a, b, i->addrs) | |
362 | if (!(a->flags & IF_UPDATED)) | |
363 | ifa_delete(a); | |
364 | if_end_partial_update(i); | |
365 | } | |
366 | } | |
8a48ecb8 MM |
367 | } |
368 | ||
53434e44 OZ |
369 | void |
370 | if_flush_ifaces(struct proto *p) | |
371 | { | |
372 | if (p->debug & D_EVENTS) | |
373 | log(L_TRACE "%s: Flushing interfaces", p->name); | |
374 | if_start_update(); | |
375 | if_end_update(); | |
376 | } | |
377 | ||
3d675cdb MM |
378 | /** |
379 | * if_feed_baby - advertise interfaces to a new protocol | |
380 | * @p: protocol to feed | |
381 | * | |
382 | * When a new protocol starts, this function sends it a series | |
383 | * of notifications about all existing interfaces. | |
384 | */ | |
47b79306 MM |
385 | void |
386 | if_feed_baby(struct proto *p) | |
387 | { | |
388 | struct iface *i; | |
9a158361 | 389 | struct ifa *a; |
47b79306 | 390 | |
6a9f28b0 | 391 | if (!p->if_notify && !p->ifa_notify) /* shortcut */ |
47b79306 | 392 | return; |
6a9f28b0 | 393 | DBG("Announcing interfaces to new protocol %s\n", p->name); |
47b79306 | 394 | WALK_LIST(i, iface_list) |
9a158361 | 395 | { |
6a9f28b0 MM |
396 | if_send_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i); |
397 | if (i->flags & IF_UP) | |
9a158361 | 398 | WALK_LIST(a, i->addrs) |
6a9f28b0 | 399 | ifa_send_notify(p, IF_CHANGE_CREATE | IF_CHANGE_UP, a); |
9a158361 | 400 | } |
47b79306 MM |
401 | } |
402 | ||
3d675cdb MM |
403 | /** |
404 | * if_find_by_index - find interface by ifindex | |
405 | * @idx: ifindex | |
406 | * | |
407 | * This function finds an &iface structure corresponding to an interface | |
408 | * of the given index @idx. Returns a pointer to the structure or %NULL | |
409 | * if no such structure exists. | |
410 | */ | |
e35ef181 MM |
411 | struct iface * |
412 | if_find_by_index(unsigned idx) | |
413 | { | |
414 | struct iface *i; | |
415 | ||
416 | WALK_LIST(i, iface_list) | |
732a0a25 | 417 | if (i->index == idx && !(i->flags & IF_SHUTDOWN)) |
e35ef181 MM |
418 | return i; |
419 | return NULL; | |
420 | } | |
421 | ||
3d675cdb MM |
422 | /** |
423 | * if_find_by_name - find interface by name | |
424 | * @name: interface name | |
425 | * | |
426 | * This function finds an &iface structure corresponding to an interface | |
427 | * of the given name @name. Returns a pointer to the structure or %NULL | |
428 | * if no such structure exists. | |
429 | */ | |
9a158361 MM |
430 | struct iface * |
431 | if_find_by_name(char *name) | |
432 | { | |
433 | struct iface *i; | |
434 | ||
435 | WALK_LIST(i, iface_list) | |
436 | if (!strcmp(i->name, name)) | |
437 | return i; | |
438 | return NULL; | |
439 | } | |
440 | ||
69a8259c OZ |
441 | struct iface * |
442 | if_get_by_name(char *name) | |
443 | { | |
444 | struct iface *i; | |
445 | ||
446 | if (i = if_find_by_name(name)) | |
447 | return i; | |
448 | ||
449 | /* No active iface, create a dummy */ | |
450 | i = mb_allocz(if_pool, sizeof(struct iface)); | |
451 | strncpy(i->name, name, sizeof(i->name)-1); | |
452 | i->flags = IF_SHUTDOWN; | |
453 | init_list(&i->addrs); | |
454 | init_list(&i->neighbors); | |
455 | add_tail(&iface_list, &i->n); | |
456 | return i; | |
457 | } | |
458 | ||
874b8685 OZ |
459 | struct ifa *kif_choose_primary(struct iface *i); |
460 | ||
9a158361 MM |
461 | static int |
462 | ifa_recalc_primary(struct iface *i) | |
463 | { | |
874b8685 | 464 | struct ifa *a = kif_choose_primary(i); |
9a158361 | 465 | |
874b8685 OZ |
466 | if (a == i->addr) |
467 | return 0; | |
468 | ||
469 | if (i->addr) | |
470 | i->addr->flags &= ~IA_PRIMARY; | |
471 | ||
472 | if (a) | |
9a158361 | 473 | { |
874b8685 OZ |
474 | a->flags |= IA_PRIMARY; |
475 | rem_node(&a->n); | |
476 | add_head(&i->addrs, &a->n); | |
9a158361 | 477 | } |
874b8685 OZ |
478 | |
479 | i->addr = a; | |
480 | return 1; | |
481 | } | |
482 | ||
483 | void | |
484 | ifa_recalc_all_primary_addresses(void) | |
485 | { | |
486 | struct iface *i; | |
487 | ||
488 | WALK_LIST(i, iface_list) | |
9a158361 | 489 | { |
874b8685 OZ |
490 | if (ifa_recalc_primary(i)) |
491 | if_change_flags(i, i->flags | IF_TMP_DOWN); | |
9a158361 | 492 | } |
9a158361 MM |
493 | } |
494 | ||
a506476a OZ |
495 | static inline int |
496 | ifa_same(struct ifa *a, struct ifa *b) | |
497 | { | |
498 | return ipa_equal(a->ip, b->ip) && ipa_equal(a->prefix, b->prefix) && | |
499 | a->pxlen == b->pxlen; | |
500 | } | |
501 | ||
874b8685 | 502 | |
3d675cdb MM |
503 | /** |
504 | * ifa_update - update interface address | |
505 | * @a: new interface address | |
506 | * | |
507 | * This function adds address information to a network | |
508 | * interface. It's called by the platform dependent code during | |
509 | * the interface update process described under if_update(). | |
510 | */ | |
9a158361 MM |
511 | struct ifa * |
512 | ifa_update(struct ifa *a) | |
513 | { | |
514 | struct iface *i = a->iface; | |
515 | struct ifa *b; | |
516 | ||
517 | WALK_LIST(b, i->addrs) | |
a506476a | 518 | if (ifa_same(b, a)) |
9a158361 | 519 | { |
a506476a | 520 | if (ipa_equal(b->brd, a->brd) && |
9a158361 | 521 | ipa_equal(b->opposite, a->opposite) && |
6a636392 | 522 | b->scope == a->scope && |
52a43ae3 | 523 | !((b->flags ^ a->flags) & IA_PEER)) |
9a158361 MM |
524 | { |
525 | b->flags |= IF_UPDATED; | |
526 | return b; | |
527 | } | |
528 | ifa_delete(b); | |
529 | break; | |
530 | } | |
6a636392 | 531 | |
85a291ff | 532 | #ifndef IPV6 |
6a636392 MM |
533 | if ((i->flags & IF_BROADCAST) && !ipa_nonzero(a->brd)) |
534 | log(L_ERR "Missing broadcast address for interface %s", i->name); | |
85a291ff | 535 | #endif |
6a636392 | 536 | |
9a158361 MM |
537 | b = mb_alloc(if_pool, sizeof(struct ifa)); |
538 | memcpy(b, a, sizeof(struct ifa)); | |
539 | add_tail(&i->addrs, &b->n); | |
540 | b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS); | |
874b8685 | 541 | if (ifa_recalc_primary(i)) |
9a158361 MM |
542 | if_change_flags(i, i->flags | IF_TMP_DOWN); |
543 | if (b->flags & IF_UP) | |
544 | ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b); | |
545 | return b; | |
546 | } | |
547 | ||
3d675cdb MM |
548 | /** |
549 | * ifa_delete - remove interface address | |
550 | * @a: interface address | |
551 | * | |
552 | * This function removes address information from a network | |
553 | * interface. It's called by the platform dependent code during | |
554 | * the interface update process described under if_update(). | |
555 | */ | |
9a158361 MM |
556 | void |
557 | ifa_delete(struct ifa *a) | |
558 | { | |
559 | struct iface *i = a->iface; | |
560 | struct ifa *b; | |
561 | ||
562 | WALK_LIST(b, i->addrs) | |
a506476a | 563 | if (ifa_same(b, a)) |
9a158361 MM |
564 | { |
565 | rem_node(&b->n); | |
566 | if (b->flags & IF_UP) | |
567 | { | |
568 | b->flags &= ~IF_UP; | |
569 | ifa_notify_change(IF_CHANGE_DOWN, b); | |
570 | } | |
571 | if (b->flags & IA_PRIMARY) | |
572 | { | |
573 | if_change_flags(i, i->flags | IF_TMP_DOWN); | |
574 | ifa_recalc_primary(i); | |
575 | } | |
576 | mb_free(b); | |
a2697f02 | 577 | return; |
9a158361 MM |
578 | } |
579 | } | |
580 | ||
79b4e12e OZ |
581 | u32 |
582 | if_choose_router_id(struct iface_patt *mask, u32 old_id) | |
7d832907 | 583 | { |
dce26783 | 584 | #ifndef IPV6 |
79b4e12e OZ |
585 | struct iface *i; |
586 | struct ifa *a, *b; | |
7d832907 | 587 | |
79b4e12e | 588 | b = NULL; |
7d832907 | 589 | WALK_LIST(i, iface_list) |
79b4e12e OZ |
590 | { |
591 | if (!(i->flags & IF_ADMIN_UP) || | |
cd3b02d1 | 592 | (i->flags & IF_SHUTDOWN)) |
79b4e12e OZ |
593 | continue; |
594 | ||
595 | WALK_LIST(a, i->addrs) | |
596 | { | |
597 | if (a->flags & IA_SECONDARY) | |
598 | continue; | |
599 | ||
600 | if (a->scope <= SCOPE_LINK) | |
601 | continue; | |
602 | ||
79b4e12e OZ |
603 | /* Check pattern if specified */ |
604 | if (mask && !iface_patt_match(mask, i, a)) | |
605 | continue; | |
606 | ||
607 | /* No pattern or pattern matched */ | |
608 | if (!b || ipa_to_u32(a->ip) < ipa_to_u32(b->ip)) | |
609 | b = a; | |
610 | } | |
611 | } | |
612 | ||
613 | if (!b) | |
614 | return 0; | |
615 | ||
616 | u32 id = ipa_to_u32(b->ip); | |
617 | if (id != old_id) | |
618 | log(L_INFO "Chosen router ID %R according to interface %s", id, b->iface->name); | |
619 | ||
620 | return id; | |
621 | ||
622 | #else | |
623 | return 0; | |
dce26783 | 624 | #endif |
7d832907 MM |
625 | } |
626 | ||
3d675cdb MM |
627 | /** |
628 | * if_init - initialize interface module | |
629 | * | |
630 | * This function is called during BIRD startup to initialize | |
631 | * all data structures of the interface module. | |
632 | */ | |
8a48ecb8 MM |
633 | void |
634 | if_init(void) | |
635 | { | |
636 | if_pool = rp_new(&root_pool, "Interfaces"); | |
637 | init_list(&iface_list); | |
85053fce | 638 | neigh_init(if_pool); |
8a48ecb8 | 639 | } |
ed45f2e1 MM |
640 | |
641 | /* | |
642 | * Interface Pattern Lists | |
643 | */ | |
644 | ||
0aad2b92 OZ |
645 | int |
646 | iface_patt_match(struct iface_patt *ifp, struct iface *i, struct ifa *a) | |
ed45f2e1 | 647 | { |
20e94fb8 | 648 | struct iface_patt_node *p; |
ed45f2e1 | 649 | |
20e94fb8 | 650 | WALK_LIST(p, ifp->ipn_list) |
ed45f2e1 MM |
651 | { |
652 | char *t = p->pattern; | |
20e94fb8 OZ |
653 | int pos = p->positive; |
654 | ||
8edf2361 | 655 | if (t) |
ed45f2e1 | 656 | { |
8edf2361 MM |
657 | if (*t == '-') |
658 | { | |
659 | t++; | |
20e94fb8 | 660 | pos = !pos; |
8edf2361 | 661 | } |
20e94fb8 | 662 | |
8edf2361 MM |
663 | if (!patmatch(t, i->name)) |
664 | continue; | |
ed45f2e1 | 665 | } |
20e94fb8 | 666 | |
5d53b807 OZ |
667 | if (p->pxlen == 0) |
668 | return pos; | |
20e94fb8 | 669 | |
5d53b807 OZ |
670 | if (!a) |
671 | continue; | |
672 | ||
673 | if (ipa_in_net(a->ip, p->prefix, p->pxlen)) | |
674 | return pos; | |
675 | ||
52a43ae3 | 676 | if ((a->flags & IA_PEER) && |
5d53b807 OZ |
677 | ipa_in_net(a->opposite, p->prefix, p->pxlen)) |
678 | return pos; | |
679 | ||
680 | continue; | |
ed45f2e1 | 681 | } |
20e94fb8 OZ |
682 | |
683 | return 0; | |
684 | } | |
685 | ||
686 | struct iface_patt * | |
0aad2b92 | 687 | iface_patt_find(list *l, struct iface *i, struct ifa *a) |
20e94fb8 OZ |
688 | { |
689 | struct iface_patt *p; | |
690 | ||
691 | WALK_LIST(p, *l) | |
0aad2b92 | 692 | if (iface_patt_match(p, i, a)) |
20e94fb8 OZ |
693 | return p; |
694 | ||
ed45f2e1 MM |
695 | return NULL; |
696 | } | |
697 | ||
20e94fb8 OZ |
698 | static int |
699 | iface_plists_equal(struct iface_patt *pa, struct iface_patt *pb) | |
700 | { | |
701 | struct iface_patt_node *x, *y; | |
702 | ||
703 | x = HEAD(pa->ipn_list); | |
704 | y = HEAD(pb->ipn_list); | |
705 | while (x->n.next && y->n.next) | |
706 | { | |
707 | if ((x->positive != y->positive) || | |
708 | (!x->pattern && y->pattern) || /* This nasty lines where written by me... :-( Feela */ | |
709 | (!y->pattern && x->pattern) || | |
710 | ((x->pattern != y->pattern) && strcmp(x->pattern, y->pattern)) || | |
711 | !ipa_equal(x->prefix, y->prefix) || | |
712 | (x->pxlen != y->pxlen)) | |
713 | return 0; | |
714 | x = (void *) x->n.next; | |
715 | y = (void *) y->n.next; | |
716 | } | |
717 | return (!x->n.next && !y->n.next); | |
718 | } | |
719 | ||
ed45f2e1 MM |
720 | int |
721 | iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct iface_patt *)) | |
722 | { | |
723 | struct iface_patt *x, *y; | |
724 | ||
725 | x = HEAD(*a); | |
726 | y = HEAD(*b); | |
727 | while (x->n.next && y->n.next) | |
728 | { | |
20e94fb8 OZ |
729 | if (!iface_plists_equal(x, y) || |
730 | (comp && !comp(x, y))) | |
ed45f2e1 MM |
731 | return 0; |
732 | x = (void *) x->n.next; | |
733 | y = (void *) y->n.next; | |
734 | } | |
735 | return (!x->n.next && !y->n.next); | |
736 | } | |
ae97b946 MM |
737 | |
738 | /* | |
739 | * CLI commands. | |
740 | */ | |
741 | ||
742 | static void | |
743 | if_show_addr(struct ifa *a) | |
744 | { | |
ae97b946 MM |
745 | byte opp[STD_ADDRESS_P_LENGTH + 16]; |
746 | ||
ae97b946 MM |
747 | if (ipa_nonzero(a->opposite)) |
748 | bsprintf(opp, ", opposite %I", a->opposite); | |
749 | else | |
750 | opp[0] = 0; | |
52a43ae3 | 751 | cli_msg(-1003, "\t%I/%d (%s%s, scope %s)", |
ae97b946 | 752 | a->ip, a->pxlen, |
7b7a7b43 | 753 | (a->flags & IA_PRIMARY) ? "Primary" : (a->flags & IA_SECONDARY) ? "Secondary" : "Unselected", |
52a43ae3 | 754 | opp, ip_scope_text(a->scope)); |
ae97b946 MM |
755 | } |
756 | ||
757 | void | |
758 | if_show(void) | |
759 | { | |
760 | struct iface *i; | |
761 | struct ifa *a; | |
762 | char *type; | |
763 | ||
764 | WALK_LIST(i, iface_list) | |
765 | { | |
f25cb0ef OZ |
766 | if (i->flags & IF_SHUTDOWN) |
767 | continue; | |
768 | ||
0d3e6bce | 769 | cli_msg(-1001, "%s %s (index=%d)", i->name, (i->flags & IF_UP) ? "up" : "DOWN", i->index); |
6a636392 | 770 | if (!(i->flags & IF_MULTIACCESS)) |
ae97b946 MM |
771 | type = "PtP"; |
772 | else | |
773 | type = "MultiAccess"; | |
0d3e6bce | 774 | cli_msg(-1004, "\t%s%s%s Admin%s Link%s%s%s MTU=%d", |
ae97b946 MM |
775 | type, |
776 | (i->flags & IF_BROADCAST) ? " Broadcast" : "", | |
777 | (i->flags & IF_MULTICAST) ? " Multicast" : "", | |
f25cb0ef | 778 | (i->flags & IF_ADMIN_UP) ? "Up" : "Down", |
ae97b946 MM |
779 | (i->flags & IF_LINK_UP) ? "Up" : "Down", |
780 | (i->flags & IF_LOOPBACK) ? " Loopback" : "", | |
781 | (i->flags & IF_IGNORE) ? " Ignored" : "", | |
782 | i->mtu); | |
783 | if (i->addr) | |
784 | if_show_addr(i->addr); | |
785 | WALK_LIST(a, i->addrs) | |
786 | if (a != i->addr) | |
787 | if_show_addr(a); | |
788 | } | |
789 | cli_msg(0, ""); | |
790 | } | |
791 | ||
792 | void | |
793 | if_show_summary(void) | |
794 | { | |
795 | struct iface *i; | |
796 | byte addr[STD_ADDRESS_P_LENGTH + 16]; | |
797 | ||
0d3e6bce | 798 | cli_msg(-2005, "interface state address"); |
ae97b946 MM |
799 | WALK_LIST(i, iface_list) |
800 | { | |
801 | if (i->addr) | |
802 | bsprintf(addr, "%I/%d", i->addr->ip, i->addr->pxlen); | |
803 | else | |
804 | addr[0] = 0; | |
0d3e6bce | 805 | cli_msg(-1005, "%-9s %-5s %s", i->name, (i->flags & IF_UP) ? "up" : "DOWN", addr); |
ae97b946 MM |
806 | } |
807 | cli_msg(0, ""); | |
808 | } |