Statistics
| Branch: | Revision:

iof-bird-daemon / nest / iface.c @ 62e64905

History | View | Annotate | Download (17.5 KB)

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