Revision f4a60a9b nest/rt-table.c

View differences:

nest/rt-table.c
55 55
static void rt_notify_hostcache(rtable *tab, net *net);
56 56
static void rt_update_hostcache(rtable *tab);
57 57
static void rt_next_hop_update(rtable *tab);
58
static inline int rt_prune_table(rtable *tab);
59
static inline void rt_schedule_gc(rtable *tab);
60
static inline void rt_schedule_prune(rtable *tab);
58
static inline void rt_prune_table(rtable *tab);
61 59

  
62 60

  
63 61
static inline struct ea_list *
......
230 228

  
231 229
  e->attrs = a;
232 230
  e->flags = 0;
233
  e->pref = a->src->proto->preference;
231
  e->pref = 0;
234 232
  return e;
235 233
}
236 234

  
......
349 347
}
350 348

  
351 349
static rte *
352
export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa, int silent)
350
export_filter(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, int silent)
353 351
{
354
  struct proto *p = ah->proto;
355
  struct filter *filter = ah->out_filter;
356
  struct proto_stats *stats = ah->stats;
352
  struct proto *p = c->proto;
353
  struct filter *filter = c->out_filter;
354
  struct proto_stats *stats = &c->stats;
357 355
  ea_list *tmpb = NULL;
358 356
  rte *rt;
359 357
  int v;
......
409 407
}
410 408

  
411 409
static void
412
do_rt_notify(struct announce_hook *ah, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
410
do_rt_notify(struct channel *c, net *net, rte *new, rte *old, ea_list *tmpa, int refeed)
413 411
{
414
  struct proto *p = ah->proto;
415
  struct proto_stats *stats = ah->stats;
412
  struct proto *p = c->proto;
413
  struct proto_stats *stats = &c->stats;
416 414

  
417 415

  
418 416
  /*
......
442 440
   * also non-new updates (contrary to import blocking).
443 441
   */
444 442

  
445
  struct proto_limit *l = ah->out_limit;
446
  if (l && new)
443
  struct channel_limit *l = &c->out_limit;
444
  if (l->action && new)
447 445
    {
448 446
      if ((!old || refeed) && (stats->exp_routes >= l->limit))
449
	proto_notify_limit(ah, l, PLD_OUT, stats->exp_routes);
447
	channel_notify_limit(c, l, PLD_OUT, stats->exp_routes);
450 448

  
451 449
      if (l->state == PLS_BLOCKED)
452 450
	{
......
483 481
	rte_trace_out(D_ROUTES, p, old, "removed");
484 482
    }
485 483
  if (!new)
486
    p->rt_notify(p, ah->table, net, NULL, old, NULL);
484
    p->rt_notify(p, c->table, net, NULL, old, NULL);
487 485
  else if (tmpa)
488 486
    {
489 487
      ea_list *t = tmpa;
490 488
      while (t->next)
491 489
	t = t->next;
492 490
      t->next = new->attrs->eattrs;
493
      p->rt_notify(p, ah->table, net, new, old, tmpa);
491
      p->rt_notify(p, c->table, net, new, old, tmpa);
494 492
      t->next = NULL;
495 493
    }
496 494
  else
497
    p->rt_notify(p, ah->table, net, new, old, new->attrs->eattrs);
495
    p->rt_notify(p, c->table, net, new, old, new->attrs->eattrs);
498 496
}
499 497

  
500 498
static void
501
rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int refeed)
499
rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, int refeed)
502 500
{
503
  struct proto *p = ah->proto;
504
  struct proto_stats *stats = ah->stats;
501
  struct proto *p = c->proto;
505 502

  
506 503
  rte *new = new0;
507 504
  rte *old = old0;
......
510 507
  ea_list *tmpa = NULL;
511 508

  
512 509
  if (new)
513
    stats->exp_updates_received++;
510
    c->stats.exp_updates_received++;
514 511
  else
515
    stats->exp_withdraws_received++;
512
    c->stats.exp_withdraws_received++;
516 513

  
517 514
  /*
518 515
   * This is a tricky part - we don't know whether route 'old' was
......
535 532
   */
536 533

  
537 534
  if (new)
538
    new = export_filter(ah, new, &new_free, &tmpa, 0);
535
    new = export_filter(c, new, &new_free, &tmpa, 0);
539 536

  
540 537
  if (old && !refeed)
541
    old = export_filter(ah, old, &old_free, NULL, 1);
538
    old = export_filter(c, old, &old_free, NULL, 1);
542 539

  
543 540
  if (!new && !old)
544 541
  {
......
555 552

  
556 553
#ifdef CONFIG_PIPE
557 554
    if ((p->proto == &proto_pipe) && !new0 && (p != old0->sender->proto))
558
      p->rt_notify(p, ah->table, net, NULL, old0, NULL);
555
      p->rt_notify(p, c->table, net, NULL, old0, NULL);
559 556
#endif
560 557

  
561 558
    return;
562 559
  }
563 560

  
564
  do_rt_notify(ah, net, new, old, tmpa, refeed);
561
  do_rt_notify(c, net, new, old, tmpa, refeed);
565 562

  
566 563
  /* Discard temporary rte's */
567 564
  if (new_free)
......
571 568
}
572 569

  
573 570
static void
574
rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *old_changed, rte *before_old, int feed)
571
rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_changed, rte *before_old, int feed)
575 572
{
576
  // struct proto *p = ah->proto;
577
  struct proto_stats *stats = ah->stats;
573
  // struct proto *p = c->proto;
578 574

  
579 575
  rte *r;
580 576
  rte *new_best = NULL;
......
592 588
     was not valid, caller must use NULL for both old_changed and before_old. */
593 589

  
594 590
  if (new_changed)
595
    stats->exp_updates_received++;
591
    c->stats.exp_updates_received++;
596 592
  else
597
    stats->exp_withdraws_received++;
593
    c->stats.exp_withdraws_received++;
598 594

  
599 595
  /* First, find the new_best route - first accepted by filters */
600 596
  for (r=net->routes; rte_is_valid(r); r=r->next)
601 597
    {
602
      if (new_best = export_filter(ah, r, &new_free, &tmpa, 0))
598
      if (new_best = export_filter(c, r, &new_free, &tmpa, 0))
603 599
	break;
604 600

  
605 601
      /* Note if we walked around the position of old_changed route */
......
650 646

  
651 647
  /* First case */
652 648
  if (old_meet)
653
    if (old_best = export_filter(ah, old_changed, &old_free, NULL, 1))
649
    if (old_best = export_filter(c, old_changed, &old_free, NULL, 1))
654 650
      goto found;
655 651

  
656 652
  /* Second case */
......
668 664
  /* Fourth case */
669 665
  for (r=r->next; rte_is_valid(r); r=r->next)
670 666
    {
671
      if (old_best = export_filter(ah, r, &old_free, NULL, 1))
667
      if (old_best = export_filter(c, r, &old_free, NULL, 1))
672 668
	goto found;
673 669

  
674 670
      if (r == before_old)
675
	if (old_best = export_filter(ah, old_changed, &old_free, NULL, 1))
671
	if (old_best = export_filter(c, old_changed, &old_free, NULL, 1))
676 672
	  goto found;
677 673
    }
678 674

  
679 675
  /* Implicitly, old_best is NULL and new_best is non-NULL */
680 676

  
681 677
 found:
682
  do_rt_notify(ah, net, new_best, old_best, tmpa, (feed == 2));
678
  do_rt_notify(c, net, new_best, old_best, tmpa, (feed == 2));
683 679

  
684 680
  /* Discard temporary rte's */
685 681
  if (new_free)
......
698 694
}
699 695

  
700 696
rte *
701
rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, ea_list **tmpa, int silent)
697
rt_export_merged(struct channel *c, net *net, rte **rt_free, ea_list **tmpa, int silent)
702 698
{
703
  // struct proto *p = ah->proto;
699
  // struct proto *p = c->proto;
704 700
  struct mpnh *nhs = NULL;
705 701
  rte *best0, *best, *rt0, *rt, *tmp;
706 702

  
......
710 706
  if (!rte_is_valid(best0))
711 707
    return NULL;
712 708

  
713
  best = export_filter(ah, best0, rt_free, tmpa, silent);
709
  best = export_filter(c, best0, rt_free, tmpa, silent);
714 710

  
715 711
  if (!best || !rte_is_reachable(best))
716 712
    return best;
......
720 716
    if (!rte_mergable(best0, rt0))
721 717
      continue;
722 718

  
723
    rt = export_filter(ah, rt0, &tmp, NULL, 1);
719
    rt = export_filter(c, rt0, &tmp, NULL, 1);
724 720

  
725 721
    if (!rt)
726 722
      continue;
727 723

  
728 724
    if (rte_is_reachable(rt))
729
      nhs = mpnh_merge_rta(nhs, rt->attrs, ah->proto->merge_limit);
725
      nhs = mpnh_merge_rta(nhs, rt->attrs, c->merge_limit);
730 726

  
731 727
    if (tmp)
732 728
      rte_free(tmp);
......
734 730

  
735 731
  if (nhs)
736 732
  {
737
    nhs = mpnh_merge_rta(nhs, best->attrs, ah->proto->merge_limit);
733
    nhs = mpnh_merge_rta(nhs, best->attrs, c->merge_limit);
738 734

  
739 735
    if (nhs->next)
740 736
    {
......
752 748

  
753 749

  
754 750
static void
755
rt_notify_merged(struct announce_hook *ah, net *net, rte *new_changed, rte *old_changed,
751
rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed,
756 752
		 rte *new_best, rte*old_best, int refeed)
757 753
{
758
  // struct proto *p = ah->proto;
754
  // struct proto *p = c->proto;
759 755

  
760 756
  rte *new_best_free = NULL;
761 757
  rte *old_best_free = NULL;
......
773 769
  if ((new_best == old_best) && !refeed)
774 770
  {
775 771
    new_changed = rte_mergable(new_best, new_changed) ?
776
      export_filter(ah, new_changed, &new_changed_free, NULL, 1) : NULL;
772
      export_filter(c, new_changed, &new_changed_free, NULL, 1) : NULL;
777 773

  
778 774
    old_changed = rte_mergable(old_best, old_changed) ?
779
      export_filter(ah, old_changed, &old_changed_free, NULL, 1) : NULL;
775
      export_filter(c, old_changed, &old_changed_free, NULL, 1) : NULL;
780 776

  
781 777
    if (!new_changed && !old_changed)
782 778
      return;
783 779
  }
784 780

  
785 781
  if (new_best)
786
    ah->stats->exp_updates_received++;
782
    c->stats.exp_updates_received++;
787 783
  else
788
    ah->stats->exp_withdraws_received++;
784
    c->stats.exp_withdraws_received++;
789 785

  
790 786
  /* Prepare new merged route */
791 787
  if (new_best)
792
    new_best = rt_export_merged(ah, net, &new_best_free, &tmpa, 0);
788
    new_best = rt_export_merged(c, net, &new_best_free, &tmpa, 0);
793 789

  
794 790
  /* Prepare old merged route (without proper merged next hops) */
795 791
  /* There are some issues with running filter on old route - see rt_notify_basic() */
796 792
  if (old_best && !refeed)
797
    old_best = export_filter(ah, old_best, &old_best_free, NULL, 1);
793
    old_best = export_filter(c, old_best, &old_best_free, NULL, 1);
798 794

  
799 795
  if (new_best || old_best)
800
    do_rt_notify(ah, net, new_best, old_best, tmpa, refeed);
796
    do_rt_notify(c, net, new_best, old_best, tmpa, refeed);
801 797

  
802 798
  /* Discard temporary rte's */
803 799
  if (new_best_free)
......
858 854
  if (!old && !new)
859 855
    return;
860 856

  
861
  if (type == RA_OPTIMAL)
862
    {
863
      if (new)
864
	new->attrs->src->proto->stats.pref_routes++;
865
      if (old)
866
	old->attrs->src->proto->stats.pref_routes--;
857
  if ((type == RA_OPTIMAL) && tab->hostcache)
858
    rt_notify_hostcache(tab, net);
867 859

  
868
      if (tab->hostcache)
869
	rt_notify_hostcache(tab, net);
870
    }
871

  
872
  struct announce_hook *a;
873
  WALK_LIST(a, tab->hooks)
860
  struct channel *c; node *n;
861
  WALK_LIST2(c, n, tab->channels, table_node)
874 862
    {
875
      ASSERT(a->proto->export_state != ES_DOWN);
876
      if (a->proto->accept_ra_types == type)
863
      if (c->export_state == ES_DOWN)
864
	continue;
865

  
866
      if (c->ra_mode == type)
877 867
	if (type == RA_ACCEPTED)
878
	  rt_notify_accepted(a, net, new, old, before_old, 0);
868
	  rt_notify_accepted(c, net, new, old, before_old, 0);
879 869
	else if (type == RA_MERGED)
880
	  rt_notify_merged(a, net, new, old, new_best, old_best, 0);
870
	  rt_notify_merged(c, net, new, old, new_best, old_best, 0);
881 871
	else
882
	  rt_notify_basic(a, net, new, old, 0);
872
	  rt_notify_basic(c, net, new, old, 0);
883 873
    }
884 874
}
885 875

  
......
943 933
static inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); }
944 934

  
945 935
static void
946
rte_recalculate(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
936
rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
947 937
{
948
  struct proto *p = ah->proto;
949
  struct rtable *table = ah->table;
950
  struct proto_stats *stats = ah->stats;
938
  struct proto *p = c->proto;
939
  struct rtable *table = c->table;
940
  struct proto_stats *stats = &c->stats;
951 941
  static struct tbf rl_pipe = TBF_DEFAULT_LOG_LIMITS;
952 942
  rte *before_old = NULL;
953 943
  rte *old_best = net->routes;
......
1011 1001
  int new_ok = rte_is_ok(new);
1012 1002
  int old_ok = rte_is_ok(old);
1013 1003

  
1014
  struct proto_limit *l = ah->rx_limit;
1015
  if (l && !old && new)
1004
  struct channel_limit *l = &c->rx_limit;
1005
  if (l->action && !old && new)
1016 1006
    {
1017 1007
      u32 all_routes = stats->imp_routes + stats->filt_routes;
1018 1008

  
1019 1009
      if (all_routes >= l->limit)
1020
	proto_notify_limit(ah, l, PLD_RX, all_routes);
1010
	channel_notify_limit(c, l, PLD_RX, all_routes);
1021 1011

  
1022 1012
      if (l->state == PLS_BLOCKED)
1023 1013
	{
......
1031 1021
	}
1032 1022
    }
1033 1023

  
1034
  l = ah->in_limit;
1035
  if (l && !old_ok && new_ok)
1024
  l = &c->in_limit;
1025
  if (l->action && !old_ok && new_ok)
1036 1026
    {
1037 1027
      if (stats->imp_routes >= l->limit)
1038
	proto_notify_limit(ah, l, PLD_IN, stats->imp_routes);
1028
	channel_notify_limit(c, l, PLD_IN, stats->imp_routes);
1039 1029

  
1040 1030
      if (l->state == PLS_BLOCKED)
1041 1031
	{
......
1049 1039
	  stats->imp_updates_ignored++;
1050 1040
	  rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
1051 1041

  
1052
	  if (ah->in_keep_filtered)
1042
	  if (c->in_keep_filtered)
1053 1043
	    new->flags |= REF_FILTERED;
1054 1044
	  else
1055 1045
	    { rte_free_quick(new); new = NULL; }
1056 1046

  
1057 1047
	  /* Note that old && !new could be possible when
1058
	     ah->in_keep_filtered changed in the recent past. */
1048
	     c->in_keep_filtered changed in the recent past. */
1059 1049

  
1060 1050
	  if (!old && !new)
1061 1051
	    return;
......
1188 1178
  if (!net->routes &&
1189 1179
      (table->gc_counter++ >= table->config->gc_max_ops) &&
1190 1180
      (table->gc_time + table->config->gc_min_time <= now))
1191
    rt_schedule_gc(table);
1181
    rt_schedule_prune(table);
1192 1182

  
1193 1183
  if (old_ok && p->rte_remove)
1194 1184
    p->rte_remove(net, old);
......
1237 1227
/**
1238 1228
 * rte_update - enter a new update to a routing table
1239 1229
 * @table: table to be updated
1240
 * @ah: pointer to table announce hook
1230
 * @c: channel doing the update
1241 1231
 * @net: network node
1242 1232
 * @p: protocol submitting the update
1243 1233
 * @src: protocol originating the update
......
1277 1267
 */
1278 1268

  
1279 1269
void
1280
rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
1270
rte_update2(struct channel *c, net *net, rte *new, struct rte_src *src)
1281 1271
{
1282
  struct proto *p = ah->proto;
1283
  struct proto_stats *stats = ah->stats;
1284
  struct filter *filter = ah->in_filter;
1272
  struct proto *p = c->proto;
1273
  struct proto_stats *stats = &c->stats;
1274
  struct filter *filter = c->in_filter;
1285 1275
  ea_list *tmpa = NULL;
1286 1276
  rte *dummy = NULL;
1287 1277

  
1278
  ASSERT(c->channel_state == CS_UP);
1279

  
1288 1280
  rte_update_lock();
1289 1281
  if (new)
1290 1282
    {
1291
      new->sender = ah;
1283
      new->sender = c;
1284

  
1285
      if (!new->pref)
1286
	new->pref = c->preference;
1292 1287

  
1293 1288
      stats->imp_updates_received++;
1294 1289
      if (!rte_validate(new))
......
1303 1298
	  stats->imp_updates_filtered++;
1304 1299
	  rte_trace_in(D_FILTERS, p, new, "filtered out");
1305 1300

  
1306
	  if (! ah->in_keep_filtered)
1301
	  if (! c->in_keep_filtered)
1307 1302
	    goto drop;
1308 1303

  
1309 1304
	  /* new is a private copy, i could modify it */
......
1321 1316
		  stats->imp_updates_filtered++;
1322 1317
		  rte_trace_in(D_FILTERS, p, new, "filtered out");
1323 1318

  
1324
		  if (! ah->in_keep_filtered)
1319
		  if (! c->in_keep_filtered)
1325 1320
		    goto drop;
1326 1321

  
1327 1322
		  new->flags |= REF_FILTERED;
......
1348 1343

  
1349 1344
 recalc:
1350 1345
  rte_hide_dummy_routes(net, &dummy);
1351
  rte_recalculate(ah, net, new, src);
1346
  rte_recalculate(c, net, new, src);
1352 1347
  rte_unhide_dummy_routes(net, &dummy);
1353 1348
  rte_update_unlock();
1354 1349
  return;
......
1409 1404
/**
1410 1405
 * rt_refresh_begin - start a refresh cycle
1411 1406
 * @t: related routing table
1412
 * @ah: related announce hook 
1407
 * @c related channel
1413 1408
 *
1414 1409
 * This function starts a refresh cycle for given routing table and announce
1415 1410
 * hook. The refresh cycle is a sequence where the protocol sends all its valid
1416 1411
 * routes to the routing table (by rte_update()). After that, all protocol
1417
 * routes (more precisely routes with @ah as @sender) not sent during the
1412
 * routes (more precisely routes with @c as @sender) not sent during the
1418 1413
 * refresh cycle but still in the table from the past are pruned. This is
1419 1414
 * implemented by marking all related routes as stale by REF_STALE flag in
1420 1415
 * rt_refresh_begin(), then marking all related stale routes with REF_DISCARD
1421 1416
 * flag in rt_refresh_end() and then removing such routes in the prune loop.
1422 1417
 */
1423 1418
void
1424
rt_refresh_begin(rtable *t, struct announce_hook *ah)
1419
rt_refresh_begin(rtable *t, struct channel *c)
1425 1420
{
1426 1421
  FIB_WALK(&t->fib, net, n)
1427 1422
    {
1428 1423
      rte *e;
1429 1424
      for (e = n->routes; e; e = e->next)
1430
	if (e->sender == ah)
1425
	if (e->sender == c)
1431 1426
	  e->flags |= REF_STALE;
1432 1427
    }
1433 1428
  FIB_WALK_END;
......
1436 1431
/**
1437 1432
 * rt_refresh_end - end a refresh cycle
1438 1433
 * @t: related routing table
1439
 * @ah: related announce hook 
1434
 * @c: related channel
1440 1435
 *
1441
 * This function starts a refresh cycle for given routing table and announce
1436
 * This function ends a refresh cycle for given routing table and announce
1442 1437
 * hook. See rt_refresh_begin() for description of refresh cycles.
1443 1438
 */
1444 1439
void
1445
rt_refresh_end(rtable *t, struct announce_hook *ah)
1440
rt_refresh_end(rtable *t, struct channel *c)
1446 1441
{
1447 1442
  int prune = 0;
1448 1443

  
......
1450 1445
    {
1451 1446
      rte *e;
1452 1447
      for (e = n->routes; e; e = e->next)
1453
	if ((e->sender == ah) && (e->flags & REF_STALE))
1448
	if ((e->sender == c) && (e->flags & REF_STALE))
1454 1449
	  {
1455 1450
	    e->flags |= REF_DISCARD;
1456 1451
	    prune = 1;
......
1501 1496
	rte_dump(e);
1502 1497
    }
1503 1498
  FIB_WALK_END;
1504

  
1505
  struct announce_hook *a;
1506
  WALK_LIST(a, t->hooks)
1507
    debug("\tAnnounces routes to protocol %s\n", a->proto->name);
1508 1499
  debug("\n");
1509 1500
}
1510 1501

  
......
1523 1514
}
1524 1515

  
1525 1516
static inline void
1526
rt_schedule_prune(rtable *tab)
1527
{
1528
  rt_mark_for_prune(tab);
1529
  ev_schedule(tab->rt_event);
1530
}
1531

  
1532
static inline void
1533
rt_schedule_gc(rtable *tab)
1534
{
1535
  if (tab->gc_scheduled)
1536
    return;
1537

  
1538
  tab->gc_scheduled = 1;
1539
  ev_schedule(tab->rt_event);
1540
}
1541

  
1542
static inline void
1543 1517
rt_schedule_hcu(rtable *tab)
1544 1518
{
1545 1519
  if (tab->hcu_scheduled)
......
1559 1533
  tab->nhu_state |= 1;
1560 1534
}
1561 1535

  
1562

  
1563
static void
1564
rt_prune_nets(rtable *tab)
1536
void
1537
rt_schedule_prune(rtable *tab)
1565 1538
{
1566
  struct fib_iterator fit;
1567
  int ncnt = 0, ndel = 0;
1568

  
1569
#ifdef DEBUGGING
1570
  fib_check(&tab->fib);
1571
#endif
1572

  
1573
  FIB_ITERATE_INIT(&fit, &tab->fib);
1574
again:
1575
  FIB_ITERATE_START(&tab->fib, &fit, net, n)
1576
    {
1577
      ncnt++;
1578
      if (!n->routes)		/* Orphaned FIB entry */
1579
	{
1580
	  FIB_ITERATE_PUT(&fit);
1581
	  fib_delete(&tab->fib, n);
1582
	  ndel++;
1583
	  goto again;
1584
	}
1585
    }
1586
  FIB_ITERATE_END;
1587
  DBG("Pruned %d of %d networks\n", ndel, ncnt);
1539
  if (tab->prune_state == 0)
1540
    ev_schedule(tab->rt_event);
1588 1541

  
1589
  tab->gc_counter = 0;
1590
  tab->gc_time = now;
1591
  tab->gc_scheduled = 0;
1542
  /* state change 0->1, 2->3 */
1543
  tab->prune_state |= 1;
1592 1544
}
1593 1545

  
1546

  
1594 1547
static void
1595 1548
rt_event(void *ptr)
1596 1549
{
......
1603 1556
    rt_next_hop_update(tab);
1604 1557

  
1605 1558
  if (tab->prune_state)
1606
    if (!rt_prune_table(tab))
1607
      {
1608
	/* Table prune unfinished */
1609
	ev_schedule(tab->rt_event);
1610
	return;
1611
      }
1612

  
1613
  if (tab->gc_scheduled)
1614
    {
1615
      rt_prune_nets(tab);
1616
      rt_prune_sources(); // FIXME this should be moved to independent event
1617
    }
1559
    rt_prune_table(tab);
1618 1560
}
1619 1561

  
1620 1562
void
......
1625 1567
  t->config = cf;
1626 1568
  t->addr_type = cf ? cf->addr_type : NET_IP4;
1627 1569
  fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
1628
  init_list(&t->hooks);
1570
  init_list(&t->channels);
1571

  
1629 1572
  if (cf)
1630 1573
    {
1631 1574
      t->rt_event = ev_new(p);
......
1652 1595
}
1653 1596

  
1654 1597

  
1655
static int
1656
rt_prune_step(rtable *tab, int *limit)
1598
/**
1599
 * rt_prune_table - prune a routing table
1600
 *
1601
 * The prune loop scans routing tables and removes routes belonging to flushing
1602
 * protocols, discarded routes and also stale network entries. It is called from
1603
 * rt_event(). The event is rescheduled if the current iteration do not finish
1604
 * the table. The pruning is directed by the prune state (@prune_state),
1605
 * specifying whether the prune cycle is scheduled or running, and there
1606
 * is also a persistent pruning iterator (@prune_fit).
1607
 *
1608
 * The prune loop is used also for channel flushing. For this purpose, the
1609
 * channels to flush are marked before the iteration and notified after the
1610
 * iteration.
1611
 */
1612
static void
1613
rt_prune_table(rtable *tab)
1657 1614
{
1658 1615
  struct fib_iterator *fit = &tab->prune_fit;
1616
  int limit = 512;
1617

  
1618
  struct channel *c;
1619
  node *n, *x;
1659 1620

  
1660 1621
  DBG("Pruning route table %s\n", tab->name);
1661 1622
#ifdef DEBUGGING
1662 1623
  fib_check(&tab->fib);
1663 1624
#endif
1664 1625

  
1665
  if (tab->prune_state == RPS_NONE)
1666
    return 1;
1626
  if (tab->prune_state == 0)
1627
    return;
1667 1628

  
1668
  if (tab->prune_state == RPS_SCHEDULED)
1669
    {
1670
      FIB_ITERATE_INIT(fit, &tab->fib);
1671
      tab->prune_state = RPS_RUNNING;
1672
    }
1629
  if (tab->prune_state == 1)
1630
  {
1631
    /* Mark channels to flush */
1632
    WALK_LIST2(c, n, tab->channels, table_node)
1633
      if (c->channel_state == CS_FLUSHING)
1634
	c->flush_active = 1;
1635

  
1636
    FIB_ITERATE_INIT(fit, &tab->fib);
1637
    tab->prune_state = 2;
1638
  }
1673 1639

  
1674 1640
again:
1675 1641
  FIB_ITERATE_START(&tab->fib, fit, net, n)
......
1678 1644

  
1679 1645
    rescan:
1680 1646
      for (e=n->routes; e; e=e->next)
1681
	if (e->sender->proto->flushing || (e->flags & REF_DISCARD))
1647
	if (e->sender->flush_active || (e->flags & REF_DISCARD))
1682 1648
	  {
1683
	    if (*limit <= 0)
1649
	    if (limit <= 0)
1684 1650
	      {
1685 1651
		FIB_ITERATE_PUT(fit);
1686
		return 0;
1652
		ev_schedule(tab->rt_event);
1653
		return;
1687 1654
	      }
1688 1655

  
1689 1656
	    rte_discard(tab, e);
1690
	    (*limit)--;
1657
	    limit--;
1691 1658

  
1692 1659
	    goto rescan;
1693 1660
	  }
1661

  
1694 1662
      if (!n->routes)		/* Orphaned FIB entry */
1695 1663
	{
1696 1664
	  FIB_ITERATE_PUT(fit);
......
1704 1672
  fib_check(&tab->fib);
1705 1673
#endif
1706 1674

  
1707
  tab->prune_state = RPS_NONE;
1708
  return 1;
1709
}
1675
  tab->gc_counter = 0;
1676
  tab->gc_time = now;
1710 1677

  
1711
/**
1712
 * rt_prune_table - prune a routing table
1713
 *
1714
 * This function scans the routing table @tab and removes routes belonging to
1715
 * flushing protocols, discarded routes and also stale network entries, in a
1716
 * similar fashion like rt_prune_loop(). Returns 1 when all such routes are
1717
 * pruned. Contrary to rt_prune_loop(), this function is not a part of the
1718
 * protocol flushing loop, but it is called from rt_event() for just one routing
1719
 * table.
1720
 *
1721
 * Note that rt_prune_table() and rt_prune_loop() share (for each table) the
1722
 * prune state (@prune_state) and also the pruning iterator (@prune_fit).
1723
 */
1724
static inline int
1725
rt_prune_table(rtable *tab)
1726
{
1727
  int limit = 512;
1728
  return rt_prune_step(tab, &limit);
1729
}
1678
  /* state change 2->0, 3->1 */
1679
  tab->prune_state &= 1;
1730 1680

  
1731
/**
1732
 * rt_prune_loop - prune routing tables
1733
 *
1734
 * The prune loop scans routing tables and removes routes belonging to flushing
1735
 * protocols, discarded routes and also stale network entries. Returns 1 when
1736
 * all such routes are pruned. It is a part of the protocol flushing loop.
1737
 */
1738
int
1739
rt_prune_loop(void)
1740
{
1741
  int limit = 512;
1742
  rtable *t;
1681
  if (tab->prune_state > 0)
1682
    ev_schedule(tab->rt_event);
1743 1683

  
1744
  WALK_LIST(t, routing_tables)
1745
    if (! rt_prune_step(t, &limit))
1746
      return 0;
1684
  /* FIXME: This should be handled in a better way */
1685
  rt_prune_sources();
1747 1686

  
1748
  return 1;
1687
  /* Close flushed channels */
1688
  WALK_LIST2_DELSAFE(c, n, x, tab->channels, table_node)
1689
    if (c->flush_active)
1690
      {
1691
	c->flush_active = 0;
1692
	channel_set_state(c, CS_DOWN);
1693
      }
1694

  
1695
  return;
1749 1696
}
1750 1697

  
1751 1698
void
1752 1699
rt_preconfig(struct config *c)
1753 1700
{
1754
  struct symbol *s = cf_get_symbol("master");
1755

  
1756 1701
  init_list(&c->tables);
1757
  c->master_rtc = rt_new_table(s, NET_IP4);
1702

  
1703
  rt_new_table(cf_get_symbol("master4"), NET_IP4);
1704
  rt_new_table(cf_get_symbol("master6"), NET_IP6);
1758 1705
}
1759 1706

  
1760 1707

  
1761
/* 
1708
/*
1762 1709
 * Some functions for handing internal next hop updates
1763 1710
 * triggered by rt_schedule_nhu().
1764 1711
 */
......
1914 1861
rt_new_table(struct symbol *s, uint addr_type)
1915 1862
{
1916 1863
  /* Hack that allows to 'redefine' the master table */
1917
  if ((s->class == SYM_TABLE) && (s->def == new_config->master_rtc))
1864
  if ((s->class == SYM_TABLE) &&
1865
      (s->def == new_config->def_tables[addr_type]) &&
1866
      ((addr_type == NET_IP4) || (addr_type == NET_IP6)))
1918 1867
    return s->def;
1919 1868

  
1920 1869
  struct rtable_config *c = cfg_allocz(sizeof(struct rtable_config));
......
1922 1871
  cf_define_symbol(s, SYM_TABLE, c);
1923 1872
  c->name = s->name;
1924 1873
  c->addr_type = addr_type;
1925
  add_tail(&new_config->tables, &c->n);
1926 1874
  c->gc_max_ops = 1000;
1927 1875
  c->gc_min_time = 5;
1876

  
1877
  add_tail(&new_config->tables, &c->n);
1878

  
1879
  /* First table of each type is kept as default */
1880
  if (! new_config->def_tables[addr_type])
1881
    new_config->def_tables[addr_type] = c;
1882

  
1928 1883
  return c;
1929 1884
}
1930 1885

  
......
2029 1984
}
2030 1985

  
2031 1986
static inline void
2032
do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e)
1987
do_feed_channel(struct channel *c, net *n, rte *e)
2033 1988
{
2034 1989
  rte_update_lock();
2035
  if (type == RA_ACCEPTED)
2036
    rt_notify_accepted(h, n, e, NULL, NULL, p->refeeding ? 2 : 1);
2037
  else if (type == RA_MERGED)
2038
    rt_notify_merged(h, n, NULL, NULL, e, p->refeeding ? e : NULL, p->refeeding);
2039
  else
2040
    rt_notify_basic(h, n, e, p->refeeding ? e : NULL, p->refeeding);
1990
  if (c->ra_mode == RA_ACCEPTED)
1991
    rt_notify_accepted(c, n, e, NULL, NULL, c->refeeding ? 2 : 1);
1992
  else if (c->ra_mode == RA_MERGED)
1993
    rt_notify_merged(c, n, NULL, NULL, e, c->refeeding ? e : NULL, c->refeeding);
1994
  else /* RA_BASIC */
1995
    rt_notify_basic(c, n, e, c->refeeding ? e : NULL, c->refeeding);
2041 1996
  rte_update_unlock();
2042 1997
}
2043 1998

  
2044 1999
/**
2045
 * rt_feed_baby - advertise routes to a new protocol
2046
 * @p: protocol to be fed
2000
 * rt_feed_channel - advertise all routes to a channel
2001
 * @c: channel to be fed
2047 2002
 *
2048
 * This function performs one pass of advertisement of routes to a newly
2049
 * initialized protocol. It's called by the protocol code as long as it
2050
 * has something to do. (We avoid transferring all the routes in single
2051
 * pass in order not to monopolize CPU time.)
2003
 * This function performs one pass of advertisement of routes to a channel that
2004
 * is in the ES_FEEDING state. It is called by the protocol code as long as it
2005
 * has something to do. (We avoid transferring all the routes in single pass in
2006
 * order not to monopolize CPU time.)
2052 2007
 */
2053 2008
int
2054
rt_feed_baby(struct proto *p)
2009
rt_feed_channel(struct channel *c)
2055 2010
{
2056
  struct announce_hook *h;
2057
  struct fib_iterator *fit;
2011
  struct fib_iterator *fit = &c->feed_fit;
2058 2012
  int max_feed = 256;
2059 2013

  
2060
  if (!p->feed_ahook)			/* Need to initialize first */
2014
  ASSERT(c->export_state == ES_FEEDING);
2015

  
2016
  if (!c->feed_active)
2061 2017
    {
2062
      if (!p->ahooks)
2063
	return 1;
2064
      DBG("Announcing routes to new protocol %s\n", p->name);
2065
      p->feed_ahook = p->ahooks;
2066
      fit = p->feed_iterator = mb_alloc(p->pool, sizeof(struct fib_iterator));
2067
      goto next_hook;
2018
      FIB_ITERATE_INIT(fit, &c->table->fib);
2019
      c->feed_active = 1;
2068 2020
    }
2069
  fit = p->feed_iterator;
2070 2021

  
2071
again:
2072
  h = p->feed_ahook;
2073
  FIB_ITERATE_START(&h->table->fib, fit, net, n)
2022
  FIB_ITERATE_START(&c->table->fib, fit, net, n)
2074 2023
    {
2075 2024
      rte *e = n->routes;
2076 2025
      if (max_feed <= 0)
......
2079 2028
	  return 0;
2080 2029
	}
2081 2030

  
2082
      /* XXXX perhaps we should change feed for RA_ACCEPTED to not use 'new' */
2031
      /* FIXME: perhaps we should change feed for RA_ACCEPTED to not use 'new' */
2083 2032

  
2084
      if ((p->accept_ra_types == RA_OPTIMAL) ||
2085
	  (p->accept_ra_types == RA_ACCEPTED) ||
2086
	  (p->accept_ra_types == RA_MERGED))
2033
      if ((c->ra_mode == RA_OPTIMAL) ||
2034
	  (c->ra_mode == RA_ACCEPTED) ||
2035
	  (c->ra_mode == RA_MERGED))
2087 2036
	if (rte_is_valid(e))
2088 2037
	  {
2089
	    if (p->export_state != ES_FEEDING)
2090
	      return 1;  /* In the meantime, the protocol fell down. */
2038
	    /* In the meantime, the protocol may fell down */
2039
	    if (c->export_state != ES_FEEDING)
2040
	      goto done;
2091 2041

  
2092
	    do_feed_baby(p, p->accept_ra_types, h, n, e);
2042
	    do_feed_channel(c, n, e);
2093 2043
	    max_feed--;
2094 2044
	  }
2095 2045

  
2096
      if (p->accept_ra_types == RA_ANY)
2046
      if (c->ra_mode == RA_ANY)
2097 2047
	for(e = n->routes; e; e = e->next)
2098 2048
	  {
2099
	    if (p->export_state != ES_FEEDING)
2100
	      return 1;  /* In the meantime, the protocol fell down. */
2049
	    /* In the meantime, the protocol may fell down */
2050
	    if (c->export_state != ES_FEEDING)
2051
	      goto done;
2101 2052

  
2102 2053
	    if (!rte_is_valid(e))
2103 2054
	      continue;
2104 2055

  
2105
	    do_feed_baby(p, RA_ANY, h, n, e);
2056
	    do_feed_channel(c, n, e);
2106 2057
	    max_feed--;
2107 2058
	  }
2108 2059
    }
2109 2060
  FIB_ITERATE_END;
2110
  p->feed_ahook = h->next;
2111
  if (!p->feed_ahook)
2112
    {
2113
      mb_free(p->feed_iterator);
2114
      p->feed_iterator = NULL;
2115
      return 1;
2116
    }
2117 2061

  
2118
next_hook:
2119
  h = p->feed_ahook;
2120
  FIB_ITERATE_INIT(fit, &h->table->fib);
2121
  goto again;
2062
done:
2063
  c->feed_active = 0;
2064
  return 1;
2122 2065
}
2123 2066

  
2124 2067
/**
2125 2068
 * rt_feed_baby_abort - abort protocol feeding
2126
 * @p: protocol
2069
 * @c: channel
2127 2070
 *
2128
 * This function is called by the protocol code when the protocol
2129
 * stops or ceases to exist before the last iteration of rt_feed_baby()
2130
 * has finished.
2071
 * This function is called by the protocol code when the protocol stops or
2072
 * ceases to exist during the feeding.
2131 2073
 */
2132 2074
void
2133
rt_feed_baby_abort(struct proto *p)
2075
rt_feed_channel_abort(struct channel *c)
2134 2076
{
2135
  if (p->feed_ahook)
2077
  if (c->feed_active)
2136 2078
    {
2137
      /* Unlink the iterator and exit */
2138
      fit_get(&p->feed_ahook->table->fib, p->feed_iterator);
2139
      p->feed_ahook = NULL;
2079
      /* Unlink the iterator */
2080
      fit_get(&c->table->fib, &c->feed_fit);
2081
      c->feed_active = 0;
2140 2082
    }
2141 2083
}
2142 2084

  
2143

  
2144 2085
static inline unsigned
2145 2086
ptr_hash(void *ptr)
2146 2087
{
......
2517 2458
  rte *e, *ee;
2518 2459
  byte ia[NET_MAX_TEXT_LENGTH+1];
2519 2460
  struct ea_list *tmpa;
2520
  struct announce_hook *a = NULL;
2461
  struct channel *ec = d->export_channel;
2521 2462
  int first = 1;
2522 2463
  int pass = 0;
2523 2464

  
2524 2465
  bsprintf(ia, "%N", n->n.addr);
2525 2466

  
2526
  if (d->export_mode)
2527
    {
2528
      if (! d->export_protocol->rt_notify)
2529
	return;
2530

  
2531
      a = proto_find_announce_hook(d->export_protocol, d->table);
2532
      if (!a)
2533
	return;
2534
    }
2535 2467

  
2536 2468
  for (e = n->routes; e; e = e->next)
2537 2469
    {
......
2550 2482
      tmpa = make_tmp_attrs(e, rte_update_pool);
2551 2483

  
2552 2484
      /* Special case for merged export */
2553
      if ((d->export_mode == RSEM_EXPORT) && (d->export_protocol->accept_ra_types == RA_MERGED))
2485
      if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED))
2554 2486
        {
2555 2487
	  rte *rt_free;
2556
	  e = rt_export_merged(a, n, &rt_free, &tmpa, 1);
2488
	  e = rt_export_merged(ec, n, &rt_free, &tmpa, 1);
2557 2489
	  pass = 1;
2558 2490

  
2559 2491
	  if (!e)
......
2564 2496
	  struct proto *ep = d->export_protocol;
2565 2497
	  int ic = ep->import_control ? ep->import_control(ep, &e, &tmpa, rte_update_pool) : 0;
2566 2498

  
2567
	  if (ep->accept_ra_types == RA_OPTIMAL || ep->accept_ra_types == RA_MERGED)
2499
	  if (ec->ra_mode == RA_OPTIMAL || ec->ra_mode == RA_MERGED)
2568 2500
	    pass = 1;
2569 2501

  
2570 2502
	  if (ic < 0)
......
2578 2510
	       * command may change the export filter and do not update routes.
2579 2511
	       */
2580 2512
	      int do_export = (ic > 0) ||
2581
		(f_run(a->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
2513
		(f_run(ec->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
2582 2514

  
2583 2515
	      if (do_export != (d->export_mode == RSEM_EXPORT))
2584 2516
		goto skip;
2585 2517

  
2586
	      if ((d->export_mode == RSEM_EXPORT) && (ep->accept_ra_types == RA_ACCEPTED))
2518
	      if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_ACCEPTED))
2587 2519
		pass = 1;
2588 2520
	    }
2589 2521
	}
......
2612 2544
    }
2613 2545
}
2614 2546

  
2547
static struct channel *
2548
rt_show_export_channel(struct rt_show_data *d)
2549
{
2550
  if (! d->export_protocol->rt_notify)
2551
    return NULL;
2552

  
2553
  return proto_find_channel_by_table(d->export_protocol, d->table);
2554
}
2555

  
2615 2556
static void
2616 2557
rt_show_cont(struct cli *c)
2617 2558
{
......
2624 2565
  struct fib *fib = &d->table->fib;
2625 2566
  struct fib_iterator *it = &d->fit;
2626 2567

  
2627
  FIB_ITERATE_START(fib, it, net, n)
2568
  if (d->export_mode)
2628 2569
    {
2629
      if (d->running_on_config && d->running_on_config != config)
2630
	{
2631
	  cli_printf(c, 8004, "Stopped due to reconfiguration");
2632
	  goto done;
2633
	}
2634
      if (d->export_protocol && (d->export_protocol->export_state == ES_DOWN))
2635
	{
2636
	  cli_printf(c, 8005, "Protocol is down");
2570
      /* Ensure we have current export channel */
2571
      d->export_channel = rt_show_export_channel(d);
2572
      if (!d->export_channel || (d->export_channel->export_state == ES_DOWN))
2573
        {
2574
	  cli_printf(c, 8005, "Channel is down");
2637 2575
	  goto done;
2638 2576
	}
2577
    }
2578

  
2579
  FIB_ITERATE_START(fib, it, net, n)
2580
    {
2639 2581
      if (!max--)
2640 2582
	{
2641 2583
	  FIB_ITERATE_PUT(it);
......
2661 2603
  fit_get(&d->table->fib, &d->fit);
2662 2604
}
2663 2605

  
2606
static inline rtable *
2607
rt_show_get_table(struct proto *p)
2608
{
2609
  /* FIXME: Use a better way to handle multi-channel protocols */
2610

  
2611
  if (p->main_channel)
2612
    return p->main_channel->table;
2613

  
2614
  if (!EMPTY_LIST(p->channels))
2615
    return ((struct channel *) HEAD(p->channels))->table;
2616

  
2617
  return NULL;
2618
}
2619

  
2664 2620
void
2665 2621
rt_show(struct rt_show_data *d)
2666 2622
{
2667 2623
  net *n;
2668 2624

  
2669 2625
  /* Default is either a master table or a table related to a respective protocol */
2670
  if (!d->table && d->export_protocol) d->table = d->export_protocol->table;
2671
  if (!d->table && d->show_protocol) d->table = d->show_protocol->table;
2672
  if (!d->table) d->table = config->master_rtc->table;
2626
  if (!d->table && d->export_protocol) d->table = rt_show_get_table(d->export_protocol);
2627
  if (!d->table && d->show_protocol) d->table = rt_show_get_table(d->show_protocol);
2628
  if (!d->table) d->table = config->def_tables[NET_IP4]->table; /* FIXME: iterate through all tables ? */
2673 2629

  
2674 2630
  /* Filtered routes are neither exported nor have sensible ordering */
2675 2631
  if (d->filtered && (d->export_mode || d->primary_only))
......
2684 2640
    }
2685 2641
  else
2686 2642
    {
2643
      if (d->export_mode)
2644
        {
2645
	  /* Find channel associated with the export protocol */
2646
	  d->export_channel = rt_show_export_channel(d);
2647
	  if (!d->export_channel || (d->export_channel->export_state == ES_DOWN))
2648
	    {
2649
	      cli_msg(8005, "Channel is down");
2650
	      return;
2651
	    }
2652
	}
2653

  
2687 2654
      if (d->show_for)
2688 2655
	n = net_route(d->table, d->addr);
2689 2656
      else

Also available in: Unified diff