Revision 9a158361 nest/iface.c

View differences:

nest/iface.c
31 31
static int
32 32
if_connected(ip_addr *a, struct iface *i) /* -1=error, 1=match, 0=no match */
33 33
{
34
  struct ifa *b;
35

  
34 36
  if (!(i->flags & IF_UP))
35 37
    return 0;
36
  if ((i->flags & IF_UNNUMBERED) && ipa_equal(*a, i->opposite))
38
  if ((i->flags & IF_UNNUMBERED) && ipa_equal(*a, i->addr->opposite))
37 39
    return 1;
38
  if (!ipa_in_net(*a, i->prefix, i->pxlen))
39
    return 0;
40
  if (ipa_equal(*a, i->prefix) ||	/* Network address */
41
      ipa_equal(*a, i->brd) ||		/* Broadcast */
42
      ipa_equal(*a, i->ip))		/* Our own address */
43
    return -1;
44
  return 1;
40
  WALK_LIST(b, i->addrs)
41
    if (ipa_in_net(*a, b->prefix, b->pxlen))
42
      {
43
	if (ipa_equal(*a, b->prefix) ||	/* Network address */
44
	    ipa_equal(*a, b->brd) ||	/* Broadcast */
45
	    ipa_equal(*a, b->ip))	/* Our own address */
46
	  return -1;
47
	return 1;
48
      }
49
  return 0;
45 50
}
46 51

  
47 52
neighbor *
......
69 74
      case -1:
70 75
	return NULL;
71 76
      case 1:
72
	if (!j || j->pxlen > i->pxlen)
77
	if (!j)				/* FIXME: Search for _optimal_ iface route? */
73 78
	  j = i;
74 79
	/* Fall-thru */
75 80
      }
......
188 193
list iface_list;
189 194

  
190 195
void
196
ifa_dump(struct ifa *a)
197
{
198
  debug("\t%I, net %I/%-2d bc %I -> %I%s%s\n", a->ip, a->prefix, a->pxlen, a->brd, a->opposite,
199
	(a->flags & IF_UP) ? "" : " DOWN",
200
	(a->flags & IA_PRIMARY) ? "" : " SEC");
201
}
202

  
203
void
191 204
if_dump(struct iface *i)
192 205
{
206
  struct ifa *a;
207

  
193 208
  debug("IF%d: %s", i->index, i->name);
194 209
  if (i->flags & IF_ADMIN_DOWN)
195 210
    debug(" ADMIN-DOWN");
......
213 228
    debug(" LOOP");
214 229
  if (i->flags & IF_IGNORE)
215 230
    debug(" IGN");
231
  if (i->flags & IF_TMP_DOWN)
232
    debug(" TDOWN");
216 233
  debug(" MTU=%d\n", i->mtu);
217
  debug("\t%I, net %I/%-2d bc %I -> %I\n", i->ip, i->prefix, i->pxlen, i->brd, i->opposite);
234
  WALK_LIST(a, i->addrs)
235
    {
236
      ifa_dump(a);
237
      ASSERT((a != i->addr) == !(a->flags & IA_PRIMARY));
238
    }
218 239
}
219 240

  
220 241
void
......
228 249
  debug("Router ID: %08x\n", config->router_id);
229 250
}
230 251

  
231
static inline int
232
if_change_too_big_p(struct iface *i, struct iface *j)
252
static inline unsigned
253
if_what_changed(struct iface *i, struct iface *j)
233 254
{
234
  if (!ipa_equal(i->ip, j->ip) ||	/* Address change isn't */
235
      !ipa_equal(i->prefix, j->prefix) ||
236
      i->pxlen != j->pxlen ||
237
      !ipa_equal(i->brd, j->brd) ||
238
      !ipa_equal(i->opposite, j->opposite))
239
    return 1;
240
  if ((i->flags ^ j->flags) & ~(IF_UP | IF_ADMIN_DOWN | IF_UPDATED | IF_LINK_UP))
241
    return 1;				/* Interface type change isn't as well */
242
  return 0;
255
  unsigned c;
256

  
257
  if (((i->flags ^ j->flags) & ~(IF_UP | IF_ADMIN_DOWN | IF_UPDATED | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED))
258
      || i->index != j->index)
259
    return IF_CHANGE_TOO_MUCH;
260
  c = 0;
261
  if ((i->flags ^ j->flags) & IF_UP)
262
    c |= (i->flags & IF_UP) ? IF_CHANGE_DOWN : IF_CHANGE_UP;
263
  if (i->mtu != j->mtu)
264
    c |= IF_CHANGE_MTU;
265
  return c;
243 266
}
244 267

  
245 268
static inline void
246 269
if_copy(struct iface *to, struct iface *from)
247 270
{
248
  to->flags = from->flags;
271
  to->flags = from->flags | (to->flags & IF_TMP_DOWN);
249 272
  to->mtu = from->mtu;
250
  to->index = from->index;
251
  to->neigh = from->neigh;
252 273
}
253 274

  
254
static unsigned
255
if_changed(struct iface *i, struct iface *j)
275
static void
276
ifa_notify_change(unsigned c, struct ifa *a)
256 277
{
257
  unsigned f = 0;
278
  struct proto *p;
258 279

  
259
  if (i->mtu != j->mtu)
260
    f |= IF_CHANGE_MTU;
261
  if ((i->flags ^ j->flags) & ~IF_UPDATED)
262
    {
263
      f |= IF_CHANGE_FLAGS;
264
      if ((i->flags ^ j->flags) & IF_UP)
265
	if (i->flags & IF_UP)
266
	  f |= IF_CHANGE_DOWN;
267
	else
268
	  f |= IF_CHANGE_UP;
269
    }
270
  return f;
280
  debug("IFA change notification (%x) for %s:%I\n", c, a->iface->name, a->ip);
281
  WALK_LIST(p, proto_list)
282
    if (p->ifa_notify)
283
      p->ifa_notify(p, c, a);
271 284
}
272 285

  
273 286
static void
274
if_notify_change(unsigned c, struct iface *old, struct iface *new, struct iface *real)
287
if_notify_change(unsigned c, struct iface *i)
275 288
{
276 289
  struct proto *p;
290
  struct ifa *a;
277 291

  
278
  debug("Interface change notification (%x) for %s\n", c, new->name);
279
  if (old)
280
    if_dump(old);
281
  if (new)
282
    if_dump(new);
292
  if (i->flags & IF_JUST_CREATED)
293
    {
294
      i->flags &= ~IF_JUST_CREATED;
295
      c |= IF_CHANGE_CREATE | IF_CHANGE_MTU;
296
    }
297

  
298
  debug("Interface change notification (%x) for %s\n", c, i->name);
299
  if_dump(i);
283 300

  
284 301
  if (c & IF_CHANGE_UP)
285
    neigh_if_up(real);
302
    neigh_if_up(i);
303
  if (c & IF_CHANGE_DOWN)
304
    WALK_LIST(a, i->addrs)
305
      {
306
	a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
307
	ifa_notify_change(IF_CHANGE_DOWN, a);
308
      }
286 309

  
287 310
  WALK_LIST(p, proto_list)
288 311
    if (p->if_notify)
289
      p->if_notify(p, c, new, old);
312
      p->if_notify(p, c, i);
290 313

  
314
  if (c & IF_CHANGE_UP)
315
    WALK_LIST(a, i->addrs)
316
      {
317
	a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
318
	ifa_notify_change(IF_CHANGE_UP, a);
319
      }
291 320
  if (c & IF_CHANGE_DOWN)
292
    neigh_if_down(real);
321
    neigh_if_down(i);
293 322
}
294 323

  
295
void
324
static unsigned
325
if_recalc_flags(struct iface *i, unsigned flags)
326
{
327
  if ((flags & (IF_ADMIN_DOWN | IF_TMP_DOWN)) ||
328
      !(flags & IF_LINK_UP) ||
329
      !i->addr)
330
    flags &= ~IF_UP;
331
  else
332
    flags |= IF_UP;
333
  return flags;
334
}
335

  
336
static void
337
if_change_flags(struct iface *i, unsigned flags)
338
{
339
  unsigned of = i->flags;
340

  
341
  i->flags = if_recalc_flags(i, flags);
342
  if ((i->flags ^ of) & IF_UP)
343
    if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i);
344
}
345

  
346
struct iface *
296 347
if_update(struct iface *new)
297 348
{
298 349
  struct iface *i;
350
  struct ifa *a, *b;
299 351
  unsigned c;
300 352

  
301
  if ((new->flags & IF_LINK_UP) && !(new->flags & IF_ADMIN_DOWN) && ipa_nonzero(new->ip))
302
    new->flags |= IF_UP;
303
  else
304
    new->flags &= ~IF_UP;
305

  
306 353
  WALK_LIST(i, iface_list)
307 354
    if (!strcmp(new->name, i->name))
308 355
      {
309
	if (if_change_too_big_p(i, new)) /* Changed a lot, convert it to down/up */
356
	new->addr = i->addr;
357
	new->flags = if_recalc_flags(new, new->flags);
358
	c = if_what_changed(i, new);
359
	if (c & IF_CHANGE_TOO_MUCH)	/* Changed a lot, convert it to down/up */
310 360
	  {
311 361
	    DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
312
	    if (i->flags & IF_UP)
313
	      {
314
		struct iface j;
315
		memcpy(&j, i, sizeof(struct iface));
316
		i->flags &= ~IF_UP;
317
		if_notify_change(IF_CHANGE_DOWN | IF_CHANGE_FLAGS, &j, i, i);
318
	      }
362
	    if_change_flags(i, i->flags | IF_TMP_DOWN);
319 363
	    rem_node(&i->n);
364
	    WALK_LIST_DELSAFE(a, b, i->addrs)
365
	      ifa_delete(a);
320 366
	    goto newif;
321 367
	  }
322
	c = if_changed(i, new);
323
	if (c)
324
	  if_notify_change(c, i, new, i);
325
	if_copy(i, new);		/* Even if c==0 as we might need to update i->index et al. */
368
	else if (c)
369
	  {
370
	    if_copy(i, new);
371
	    if_notify_change(c, i);
372
	  }
326 373
	i->flags |= IF_UPDATED;
327
	return;
374
	return i;
328 375
      }
329

  
330 376
  i = mb_alloc(if_pool, sizeof(struct iface));
331 377
newif:
332 378
  memcpy(i, new, sizeof(*i));
333
  i->flags |= IF_UPDATED;
379
  init_list(&i->addrs);
380
  i->flags |= IF_UPDATED | IF_TMP_DOWN;		/* Tmp down as we don't have addresses yet */
334 381
  add_tail(&iface_list, &i->n);
335
  if_notify_change(IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0)
336
		   | IF_CHANGE_FLAGS | IF_CHANGE_MTU, NULL, i, i);
382
  return i;
337 383
}
338 384

  
339 385
void
340 386
if_start_update(void)
341 387
{
342 388
  struct iface *i;
389
  struct ifa *a;
343 390

  
344 391
  WALK_LIST(i, iface_list)
345
    i->flags &= ~IF_UPDATED;
392
    {
393
      i->flags &= ~IF_UPDATED;
394
      WALK_LIST(a, i->addrs)
395
	a->flags &= ~IF_UPDATED;
396
    }
397
}
398

  
399
void
400
if_end_partial_update(struct iface *i)
401
{
402
  if (i->flags & IF_TMP_DOWN)
403
    if_change_flags(i, i->flags & ~IF_TMP_DOWN);
346 404
}
347 405

  
348 406
void
349 407
if_end_update(void)
350 408
{
351 409
  struct iface *i, j;
410
  struct ifa *a, *b;
352 411

  
353 412
  if (!config->router_id)
354 413
    auto_router_id();
355 414

  
356 415
  WALK_LIST(i, iface_list)
357
    if (!(i->flags & IF_UPDATED))
358
      {
359
	memcpy(&j, i, sizeof(struct iface));
360
	i->flags = (i->flags & ~(IF_LINK_UP | IF_UP)) | IF_ADMIN_DOWN;
361
	if (i->flags != j.flags)
362
	  if_notify_change(IF_CHANGE_DOWN | IF_CHANGE_FLAGS, &j, i, i);
363
      }
416
    {
417
      if (!(i->flags & IF_UPDATED))
418
	if_change_flags(i, (i->flags & ~IF_LINK_UP) | IF_ADMIN_DOWN);
419
      else
420
	{
421
	  WALK_LIST_DELSAFE(a, b, i->addrs)
422
	    if (!(a->flags & IF_UPDATED))
423
	      ifa_delete(a);
424
	  if_end_partial_update(i);
425
	}
426
    }
364 427
}
365 428

  
366 429
void
367 430
if_feed_baby(struct proto *p)
368 431
{
369 432
  struct iface *i;
433
  struct ifa *a;
370 434

  
371
  if (!p->if_notify)
435
  if (!p->if_notify && !p->ifa_notify)
372 436
    return;
373 437
  debug("Announcing interfaces to new protocol %s\n", p->name);
374 438
  WALK_LIST(i, iface_list)
375
    p->if_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i, NULL);
439
    {
440
      if (p->if_notify)
441
	p->if_notify(p, IF_CHANGE_CREATE | ((i->flags & IF_UP) ? IF_CHANGE_UP : 0), i);
442
      if (p->ifa_notify && (i->flags & IF_UP))
443
	WALK_LIST(a, i->addrs)
444
	  p->ifa_notify(p, IF_CHANGE_CREATE | IF_CHANGE_UP, a);
445
    }
376 446
}
377 447

  
378 448
struct iface *
......
386 456
  return NULL;
387 457
}
388 458

  
459
struct iface *
460
if_find_by_name(char *name)
461
{
462
  struct iface *i;
463

  
464
  WALK_LIST(i, iface_list)
465
    if (!strcmp(i->name, name))
466
      return i;
467
  return NULL;
468
}
469

  
470
static int
471
ifa_recalc_primary(struct iface *i)
472
{
473
  struct ifa *a, *b = NULL;
474
  int res;
475

  
476
  WALK_LIST(a, i->addrs)
477
    {
478
      if (!(a->flags & IA_SECONDARY) && (!b || a->scope > b->scope))
479
	b = a;
480
      a->flags &= ~IA_PRIMARY;
481
    }
482
  res = (b != i->addr);
483
  i->addr = b;
484
  if (b)
485
    {
486
      b->flags |= IA_PRIMARY;
487
      rem_node(&b->n);
488
      add_head(&i->addrs, &b->n);
489
    }
490
  return res;
491
}
492

  
493
struct ifa *
494
ifa_update(struct ifa *a)
495
{
496
  struct iface *i = a->iface;
497
  struct ifa *b;
498

  
499
  WALK_LIST(b, i->addrs)
500
    if (ipa_equal(b->ip, a->ip))
501
      {
502
	if (ipa_equal(b->prefix, a->prefix) &&
503
	    b->pxlen == a->pxlen &&
504
	    ipa_equal(b->brd, a->brd) &&
505
	    ipa_equal(b->opposite, a->opposite) &&
506
	    b->scope == a->scope)
507
	  {
508
	    b->flags |= IF_UPDATED;
509
	    return b;
510
	  }
511
	ifa_delete(b);
512
	break;
513
      }
514
  b = mb_alloc(if_pool, sizeof(struct ifa));
515
  memcpy(b, a, sizeof(struct ifa));
516
  add_tail(&i->addrs, &b->n);
517
  b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
518
  if ((!i->addr || i->addr->scope < b->scope) && ifa_recalc_primary(i))
519
    if_change_flags(i, i->flags | IF_TMP_DOWN);
520
  if (b->flags & IF_UP)
521
    ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
522
  return b;
523
}
524

  
525
void
526
ifa_delete(struct ifa *a)
527
{
528
  struct iface *i = a->iface;
529
  struct ifa *b;
530

  
531
  WALK_LIST(b, i->addrs)
532
    if (ipa_equal(b->ip, a->ip))
533
      {
534
	rem_node(&b->n);
535
	if (b->flags & IF_UP)
536
	  {
537
	    b->flags &= ~IF_UP;
538
	    ifa_notify_change(IF_CHANGE_DOWN, b);
539
	  }
540
	if (b->flags & IA_PRIMARY)
541
	  {
542
	    if_change_flags(i, i->flags | IF_TMP_DOWN);
543
	    ifa_recalc_primary(i);
544
	  }
545
	mb_free(b);
546
      }
547
}
548

  
389 549
static void
390 550
auto_router_id(void)			/* FIXME: What if we run IPv6??? */
391 551
{
......
393 553

  
394 554
  j = NULL;
395 555
  WALK_LIST(i, iface_list)
396
    if ((i->flags & IF_UP) &&
397
	!(i->flags & (IF_UNNUMBERED | IF_IGNORE)) &&
398
	(!j || ipa_to_u32(i->ip) < ipa_to_u32(j->ip)))
556
    if ((i->flags & IF_LINK_UP) &&
557
	!(i->flags & (IF_UNNUMBERED | IF_IGNORE | IF_ADMIN_DOWN)) &&
558
	i->addr &&
559
	(!j || ipa_to_u32(i->addr->ip) < ipa_to_u32(j->addr->ip)))
399 560
      j = i;
400 561
  if (!j)
401 562
    die("Cannot determine router ID (no suitable network interface found), please configure it manually");
402
  debug("Guessed router ID %I (%s)\n", j->ip, j->name);
403
  config->router_id = ipa_to_u32(j->ip);
563
  debug("Guessed router ID %I (%s)\n", j->addr->ip, j->name);
564
  config->router_id = ipa_to_u32(j->addr->ip);
404 565
}
405 566

  
406 567
void

Also available in: Unified diff