Revision 094d2bdb

View differences:

filter/filter.c
831 831
	res.val.i = * ((char *) rta + what->a2.i);
832 832
	break;
833 833
      case T_STRING:	/* Warning: this is a special case for proto attribute */
834
	res.val.s = rta->proto->name;
834
	res.val.s = rta->src->proto->name;
835 835
	break;
836 836
      case T_PREFIX:	/* Warning: this works only for prefix of network */
837 837
	{
lib/string.h
11 11

  
12 12
#include <stdarg.h>
13 13
#include <string.h>
14
#include <strings.h>
14 15

  
15 16
int bsprintf(char *str, const char *fmt, ...);
16 17
int bvsprintf(char *str, const char *fmt, va_list args);
nest/proto.c
219 219
  p->main_ahook = NULL;
220 220
}
221 221

  
222

  
222 223
/**
223 224
 * proto_config_new - create a new protocol configuration
224 225
 * @pr: protocol the configuration will belong to
......
791 792
  /* Connect protocol to routing table */
792 793
  if (initial && !p->proto->multitable)
793 794
    {
795
      p->main_source = rt_get_source(p, 0);
796
      rt_lock_source(p->main_source);
797

  
794 798
      p->main_ahook = proto_add_announce_hook(p, p->table, &p->stats);
795 799
      p->main_ahook->in_filter = p->cf->in_filter;
796 800
      p->main_ahook->out_filter = p->cf->out_filter;
797 801
      p->main_ahook->in_limit = p->cf->in_limit;
798 802
      p->main_ahook->out_limit = p->cf->out_limit;
803

  
799 804
      proto_reset_limit(p->main_ahook->in_limit);
800 805
      proto_reset_limit(p->main_ahook->out_limit);
801 806
    }
......
844 849
      return;
845 850
    }
846 851

  
852
  rt_prune_sources();
853

  
847 854
 again:
848 855
  WALK_LIST(p, flush_proto_list)
849 856
    if (p->flushing)
......
1040 1047
      if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
1041 1048
	proto_schedule_flush(p);
1042 1049

  
1050
      if (p->proto->multitable)
1051
	{
1052
	  rt_unlock_source(p->main_source);
1053
	  p->main_source = NULL;
1054
	}
1055

  
1043 1056
      neigh_prune(); // FIXME convert neighbors to resource?
1044 1057
      rfree(p->pool);
1045 1058
      p->pool = NULL;
nest/protocol.h
183 183
  int (*reload_routes)(struct proto *);
184 184

  
185 185
  /*
186
   *	Routing entry hooks (called only for rte's belonging to this protocol):
186
   *	Routing entry hooks (called only for routes belonging to this protocol):
187 187
   *
188 188
   *	   rte_recalculate Called at the beginning of the best route selection  
189 189
   *	   rte_better	Compare two rte's and decide which one is better (1=first, 0=second).
......
199 199
  void (*rte_remove)(struct network *, struct rte *);
200 200

  
201 201
  struct rtable *table;			/* Our primary routing table */
202
  struct rte_src *main_source;		/* Primary route source */
202 203
  struct announce_hook *main_ahook;	/* Primary announcement hook */
203 204
  struct announce_hook *ahooks;		/* Announcement hooks for this protocol */
204 205

  
nest/route.h
237 237
void rt_setup(pool *, rtable *, char *, struct rtable_config *);
238 238
static inline net *net_find(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_find(&tab->fib, &addr, len); }
239 239
static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_get(&tab->fib, &addr, len); }
240
rte *rte_find(net *net, struct proto *p);
240
rte *rte_find(net *net, struct rte_src *src);
241 241
rte *rte_get_temp(struct rta *);
242
void rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src);
243
static inline void rte_update(rtable *tab, net *net, struct proto *p, struct proto *src, rte *new) { rte_update2(p->main_ahook, net, new, src); }
242
void rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src);
243
static inline void rte_update(struct proto *p, net *net, rte *new) { rte_update2(p->main_ahook, net, new, p->main_source); }
244 244
void rte_discard(rtable *tab, rte *old);
245 245
void rte_dump(rte *);
246 246
void rte_free(rte *);
......
286 286
  unsigned char weight;
287 287
};
288 288

  
289
struct rte_src {
290
  struct rte_src *next;			/* Hash chain */
291
  struct proto *proto;			/* Protocol the source is based on */
292
  u32 private_id;			/* Private ID, assigned by the protocol */
293
  u32 global_id;			/* Globally unique ID of the source */
294
  unsigned uc;				/* Use count */
295
};
296

  
297

  
289 298
typedef struct rta {
290 299
  struct rta *next, **pprev;		/* Hash chain */
291
  struct proto *proto;			/* Protocol instance that originally created the route */
300
  struct rte_src *src;			/* Route source that created the route */
292 301
  unsigned uc;				/* Use count */
293 302
  byte source;				/* Route source (RTS_...) */
294 303
  byte scope;				/* Route scope (SCOPE_... -- see ip.h) */
......
403 412
#define EALF_BISECT 2			/* Use interval bisection for searching */
404 413
#define EALF_CACHED 4			/* Attributes belonging to cached rta */
405 414

  
415
struct rte_src *rt_find_source(struct proto *p, u32 id);
416
struct rte_src *rt_get_source(struct proto *p, u32 id);
417
static inline void rt_lock_source(struct rte_src *src) { src->uc++; }
418
static inline void rt_unlock_source(struct rte_src *src) { src->uc--; }
419
void rt_prune_sources(void);
420

  
421

  
406 422
eattr *ea_find(ea_list *, unsigned ea);
407 423
int ea_get_int(ea_list *, unsigned ea, int def);
408 424
void ea_dump(ea_list *);
......
419 435

  
420 436
void rta_init(void);
421 437
rta *rta_lookup(rta *);			/* Get rta equivalent to this one, uc++ */
438
static inline int rta_is_cached(rta *r) { return r->aflags & RTAF_CACHED; }
422 439
static inline rta *rta_clone(rta *r) { r->uc++; return r; }
423 440
void rta__free(rta *r);
424 441
static inline void rta_free(rta *r) { if (r && !--r->uc) rta__free(r); }
nest/rt-attr.c
58 58

  
59 59
static slab *rta_slab;
60 60
static slab *mpnh_slab;
61
static slab *rte_src_slab;
62

  
63
/* rte source ID bitmap */
64
static u32 *src_ids;
65
static u32 src_id_size, src_id_used, src_id_pos;
66
#define SRC_ID_SIZE_DEF 4
67

  
68
/* rte source hash */
69
static struct rte_src **src_table;
70
static u32 src_hash_order, src_hash_size, src_hash_count;
71
#define SRC_HASH_ORDER_DEF 6
72
#define SRC_HASH_ORDER_MAX 18
73
#define SRC_HASH_ORDER_MIN 10
61 74

  
62 75
struct protocol *attr_class_to_protocol[EAP_MAX];
63 76

  
77

  
78
static void
79
rte_src_init(void)
80
{
81
  rte_src_slab = sl_new(rta_pool, sizeof(struct rte_src));
82

  
83
  src_id_pos = 0;
84
  src_id_size = SRC_ID_SIZE_DEF;
85
  src_ids = mb_allocz(rta_pool, src_id_size * sizeof(u32));
86

  
87
 /* ID 0 is reserved */
88
  src_ids[0] = 1;
89
  src_id_used = 1;
90

  
91
  src_hash_count = 0;
92
  src_hash_order = SRC_HASH_ORDER_DEF;
93
  src_hash_size = 1 << src_hash_order;
94
  src_table = mb_allocz(rta_pool, src_hash_size * sizeof(struct rte_src *));
95
}
96

  
97
static inline int u32_cto(unsigned int x) { return ffs(~x) - 1; }
98

  
99
static inline u32
100
rte_src_alloc_id(void)
101
{
102
  int i, j;
103
  for (i = src_id_pos; i < src_id_size; i++)
104
    if (src_ids[i] != 0xffffffff)
105
      goto found;
106

  
107
  /* If we are at least 7/8 full, expand */
108
  if (src_id_used > (src_id_size * 28))
109
    {
110
      src_id_size *= 2;
111
      src_ids = mb_realloc(rta_pool, src_ids, src_id_size * sizeof(u32));
112
      bzero(src_ids + i, (src_id_size - i) * sizeof(u32));
113
      goto found;
114
    }
115

  
116
  for (i = 0; i < src_id_pos; i++)
117
    if (src_ids[i] != 0xffffffff)
118
      goto found;
119

  
120
  ASSERT(0);
121

  
122
 found:
123
  ASSERT(i < 0x8000000);
124

  
125
  src_id_pos = i;
126
  j = u32_cto(src_ids[i]);
127

  
128
  src_ids[i] |= (1 << j);
129
  src_id_used++;
130
  return 32 * i + j;
131
}
132

  
133
static inline void
134
rte_src_free_id(u32 id)
135
{
136
  int i = id / 32;
137
  int j = id % 32;
138

  
139
  ASSERT((i < src_id_size) && (src_ids[i] & (1 << j)));
140
  src_ids[i] &= ~(1 << j);
141
  src_id_used--;
142
}
143

  
144
static inline u32 rte_src_hash(struct proto *p, u32 x, u32 order)
145
{ return (x * 2902958171u) >> (32 - order); }
146

  
147
static void
148
rte_src_rehash(int step)
149
{
150
  struct rte_src **old_tab, *src, *src_next;
151
  u32 old_size, hash, i;
152

  
153
  old_tab = src_table;
154
  old_size = src_hash_size;
155

  
156
  src_hash_order += step;
157
  src_hash_size = 1 << src_hash_order;
158
  src_table = mb_allocz(rta_pool, src_hash_size * sizeof(struct rte_src *));
159
  
160
  for (i = 0; i < old_size; i++)
161
    for (src = old_tab[i]; src; src = src_next)
162
      {
163
	src_next = src->next;
164
	hash = rte_src_hash(src->proto, src->private_id, src_hash_order);
165
	src->next = src_table[hash];
166
	src_table[hash] = src;
167
      }
168

  
169
  mb_free(old_tab);
170
}
171

  
172
struct rte_src *
173
rt_find_source(struct proto *p, u32 id)
174
{
175
  struct rte_src *src;
176
  u32 hash = rte_src_hash(p, id, src_hash_order);
177

  
178
  for (src = src_table[hash]; src; src = src->next)
179
    if ((src->proto == p) && (src->private_id == id))
180
      return src;
181

  
182
  return NULL;
183
}
184

  
185
struct rte_src *
186
rt_get_source(struct proto *p, u32 id)
187
{
188
  struct rte_src *src;
189
  u32 hash = rte_src_hash(p, id, src_hash_order);
190

  
191
  for (src = src_table[hash]; src; src = src->next)
192
    if ((src->proto == p) && (src->private_id == id))
193
      return src;
194

  
195
  src = sl_alloc(rte_src_slab);
196
  src->proto = p;
197
  src->private_id = id;
198
  src->global_id = rte_src_alloc_id();
199
  src->uc = 0;
200

  
201
  src->next = src_table[hash];
202
  src_table[hash] = src;
203

  
204
  src_hash_count++;
205
  if ((src_hash_count > src_hash_size) && (src_hash_order < SRC_HASH_ORDER_MAX))
206
    rte_src_rehash(1);
207

  
208
  return src;
209
}
210

  
211
static inline void
212
rt_remove_source(struct rte_src **sp)
213
{
214
  struct rte_src *src = *sp;
215

  
216
  *sp = src->next;
217
  rte_src_free_id(src->global_id);
218
  sl_free(rte_src_slab, src);
219
  src_hash_count--;
220
}
221

  
222
void
223
rt_prune_sources(void)
224
{
225
  struct rte_src **sp;
226
  int i;
227
  
228
  for (i = 0; i < src_hash_size; i++)
229
    {
230
      sp = &src_table[i];
231
      while (*sp)
232
	{
233
	  if ((*sp)->uc == 0)
234
	    rt_remove_source(sp);
235
	  else
236
	    sp = &(*sp)->next;
237
	}
238
    }
239

  
240
  while ((src_hash_count < (src_hash_size / 4)) && (src_hash_order > SRC_HASH_ORDER_MIN))
241
    rte_src_rehash(-1);
242
}
243

  
244

  
245
/*
246
 *	Multipath Next Hop
247
 */
248

  
64 249
static inline unsigned int
65 250
mpnh_hash(struct mpnh *x)
66 251
{
......
682 867
static inline unsigned int
683 868
rta_hash(rta *a)
684 869
{
685
  return (a->proto->hash_key ^ ipa_hash(a->gw) ^
870
  return (((unsigned) a->src) ^ ipa_hash(a->gw) ^
686 871
	  mpnh_hash(a->nexthops) ^ ea_hash(a->eattrs)) & 0xffff;
687 872
}
688 873

  
689 874
static inline int
690 875
rta_same(rta *x, rta *y)
691 876
{
692
  return (x->proto == y->proto &&
877
  return (x->src == y->src &&
693 878
	  x->source == y->source &&
694 879
	  x->scope == y->scope &&
695 880
	  x->cast == y->cast &&
......
786 971
  r = rta_copy(o);
787 972
  r->hash_key = h;
788 973
  r->aflags = RTAF_CACHED;
974
  rt_lock_source(r->src);
789 975
  rt_lock_hostentry(r->hostentry);
790 976
  rta_insert(r);
791 977

  
......
805 991
    a->next->pprev = a->pprev;
806 992
  a->aflags = 0;		/* Poison the entry */
807 993
  rt_unlock_hostentry(a->hostentry);
994
  rt_unlock_source(a->src);
808 995
  mpnh_free(a->nexthops);
809 996
  ea_free(a->eattrs);
810 997
  sl_free(rta_slab, a);
......
827 1014
  static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
828 1015

  
829 1016
  debug("p=%s uc=%d %s %s%s%s h=%04x",
830
	a->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope), rtc[a->cast],
1017
	a->src->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope), rtc[a->cast],
831 1018
	rtd[a->dest], a->hash_key);
832 1019
  if (!(a->aflags & RTAF_CACHED))
833 1020
    debug(" !CACHED");
......
895 1082
  rta_slab = sl_new(rta_pool, sizeof(rta));
896 1083
  mpnh_slab = sl_new(rta_pool, sizeof(struct mpnh));
897 1084
  rta_alloc_hash();
1085
  rte_src_init();
898 1086
}
899 1087

  
900 1088
/*
nest/rt-dev.c
48 48
	  DBG("dev_if_notify: device shutdown: prefix not found\n");
49 49
	  return;
50 50
	}
51
      rte_update(p->table, n, p, p, NULL);
51
      rte_update(p, n, NULL);
52 52
    }
53 53
  else if (c & IF_CHANGE_UP)
54 54
    {
55
      rta *a, A;
55
      rta *a;
56 56
      net *n;
57 57
      rte *e;
58 58

  
59 59
      DBG("dev_if_notify: %s:%I going up\n", ad->iface->name, ad->ip);
60
      bzero(&A, sizeof(A));
61
      A.proto = p;
62
      A.source = RTS_DEVICE;
63
      A.scope = SCOPE_UNIVERSE;
64
      A.cast = RTC_UNICAST;
65
      A.dest = RTD_DEVICE;
66
      A.iface = ad->iface;
67
      A.eattrs = NULL;
68
      a = rta_lookup(&A);
60

  
61
      rta a0 = {
62
	.src = p->main_source,
63
	.source = RTS_DEVICE,
64
	.scope = SCOPE_UNIVERSE,
65
	.cast = RTC_UNICAST,
66
	.dest = RTD_DEVICE,
67
	.iface = ad->iface
68
      };
69

  
70
      a = rta_lookup(&a0);
69 71
      n = net_get(p->table, ad->prefix, ad->pxlen);
70 72
      e = rte_get_temp(a);
71 73
      e->net = n;
72 74
      e->pflags = 0;
73
      rte_update(p->table, n, p, p, e);
75
      rte_update(p, n, e);
74 76
    }
75 77
}
76 78

  
nest/rt-table.c
58 58

  
59 59
static inline void rt_schedule_gc(rtable *tab);
60 60

  
61
static inline struct ea_list *
62
make_tmp_attrs(struct rte *rt, struct linpool *pool)
63
{
64
  struct ea_list *(*mta)(struct rte *rt, struct linpool *pool);
65
  mta = rt->attrs->src->proto->make_tmp_attrs;
66
  return mta ? mta(rt, rte_update_pool) : NULL;
67
}
68

  
61 69
/* Like fib_route(), but skips empty net entries */
62 70
static net *
63 71
net_route(rtable *tab, ip_addr a, int len)
......
88 96
/**
89 97
 * rte_find - find a route
90 98
 * @net: network node
91
 * @p: protocol
99
 * @src: route source
92 100
 *
93 101
 * The rte_find() function returns a route for destination @net
94
 * which belongs has been defined by protocol @p.
102
 * which is from route source @src.
95 103
 */
96 104
rte *
97
rte_find(net *net, struct proto *p)
105
rte_find(net *net, struct rte_src *src)
98 106
{
99 107
  rte *e = net->routes;
100 108

  
101
  while (e && e->attrs->proto != p)
109
  while (e && e->attrs->src != src)
102 110
    e = e->next;
103 111
  return e;
104 112
}
......
119 127

  
120 128
  e->attrs = a;
121 129
  e->flags = 0;
122
  e->pref = a->proto->preference;
130
  e->pref = a->src->proto->preference;
123 131
  return e;
124 132
}
125 133

  
......
145 153
    return 1;
146 154
  if (new->pref < old->pref)
147 155
    return 0;
148
  if (new->attrs->proto->proto != old->attrs->proto->proto)
156
  if (new->attrs->src->proto->proto != old->attrs->src->proto->proto)
149 157
    {
150 158
      /*
151 159
       *  If the user has configured protocol preferences, so that two different protocols
152 160
       *  have the same preference, try to break the tie by comparing addresses. Not too
153 161
       *  useful, but keeps the ordering of routes unambiguous.
154 162
       */
155
      return new->attrs->proto->proto > old->attrs->proto->proto;
163
      return new->attrs->src->proto->proto > old->attrs->src->proto->proto;
156 164
    }
157
  if (better = new->attrs->proto->rte_better)
165
  if (better = new->attrs->src->proto->rte_better)
158 166
    return better(new, old);
159 167
  return 0;
160 168
}
......
198 206
  /* If called does not care for eattrs, we prepare one internally */
199 207
  if (!tmpa)
200 208
    {
201
      struct proto *src = rt->attrs->proto;
202
      tmpb = src->make_tmp_attrs ? src->make_tmp_attrs(rt, rte_update_pool) : NULL;
209
      tmpb = make_tmp_attrs(rt, rte_update_pool);
203 210
      tmpa = &tmpb;
204 211
    }
205 212

  
......
536 543
  if (type == RA_OPTIMAL)
537 544
    {
538 545
      if (new)
539
	new->attrs->proto->stats.pref_routes++;
546
	new->attrs->src->proto->stats.pref_routes++;
540 547
      if (old)
541
	old->attrs->proto->stats.pref_routes--;
548
	old->attrs->src->proto->stats.pref_routes--;
542 549

  
543 550
      if (tab->hostcache)
544 551
	rt_notify_hostcache(tab, net);
......
588 595
void
589 596
rte_free(rte *e)
590 597
{
591
  if (e->attrs->aflags & RTAF_CACHED)
598
  if (rta_is_cached(e->attrs))
592 599
    rta_free(e->attrs);
593 600
  sl_free(rte_slab, e);
594 601
}
......
608 615
    x->flags == y->flags &&
609 616
    x->pflags == y->pflags &&
610 617
    x->pref == y->pref &&
611
    (!x->attrs->proto->rte_same || x->attrs->proto->rte_same(x, y));
618
    (!x->attrs->src->proto->rte_same || x->attrs->src->proto->rte_same(x, y));
612 619
}
613 620

  
614 621
static void
615
rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, struct proto *src)
622
rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, struct rte_src *src)
616 623
{
617 624
  struct proto *p = ah->proto;
618 625
  struct rtable *table = ah->table;
......
625 632
  k = &net->routes;			/* Find and remove original route from the same protocol */
626 633
  while (old = *k)
627 634
    {
628
      if (old->attrs->proto == src)
635
      if (old->attrs->src == src)
629 636
	{
630 637
	  /* If there is the same route in the routing table but from
631 638
	   * a different sender, then there are two paths from the
......
656 663
#ifdef CONFIG_RIP
657 664
	      /* lastmod is used internally by RIP as the last time
658 665
		 when the route was received. */
659
	      if (src->proto == &proto_rip)
666
	      if (src->proto->proto == &proto_rip)
660 667
		old->lastmod = now;
661 668
#endif
662 669
	      return;
......
725 732
      /* If routes are not sorted, find the best route and move it on
726 733
	 the first position. There are several optimized cases. */
727 734

  
728
      if (src->rte_recalculate && src->rte_recalculate(table, net, new, old, old_best))
735
      if (src->proto->rte_recalculate && src->proto->rte_recalculate(table, net, new, old, old_best))
729 736
	goto do_recalculate;
730 737

  
731 738
      if (new && rte_better(new, old_best))
......
881 888
 */
882 889

  
883 890
void
884
rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src)
891
rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src)
885 892
{
886 893
  struct proto *p = ah->proto;
887 894
  struct proto_stats *stats = ah->stats;
......
906 913
	  rte_trace_in(D_FILTERS, p, new, "filtered out");
907 914
	  goto drop;
908 915
	}
909
      if (src->make_tmp_attrs)
910
	tmpa = src->make_tmp_attrs(new, rte_update_pool);
916

  
917
      tmpa = make_tmp_attrs(new, rte_update_pool);
911 918
      if (filter)
912 919
	{
913 920
	  ea_list *old_tmpa = tmpa;
......
918 925
	      rte_trace_in(D_FILTERS, p, new, "filtered out");
919 926
	      goto drop;
920 927
	    }
921
	  if (tmpa != old_tmpa && src->store_tmp_attrs)
922
	    src->store_tmp_attrs(new, tmpa);
928
	  if (tmpa != old_tmpa && src->proto->store_tmp_attrs)
929
	    src->proto->store_tmp_attrs(new, tmpa);
923 930
	}
924
      if (!(new->attrs->aflags & RTAF_CACHED)) /* Need to copy attributes */
931

  
932
      if (!rta_is_cached(new->attrs)) /* Need to copy attributes */
925 933
	new->attrs = rta_lookup(new->attrs);
926 934
      new->flags |= REF_COW;
927 935
    }
928 936
  else
929
    stats->imp_withdraws_received++;
937
    {
938
      stats->imp_withdraws_received++;
939

  
940
      if (!net || !src)
941
	{
942
	  stats->imp_withdraws_ignored++;
943
	  rte_update_unlock();
944
	  return;
945
	}
946
    }
930 947

  
931 948
  rte_recalculate(ah, net, new, tmpa, src);
932 949
  rte_update_unlock();
......
943 960
static inline void 
944 961
rte_announce_i(rtable *tab, unsigned type, net *n, rte *new, rte *old)
945 962
{
946
  struct proto *src;
947 963
  ea_list *tmpa;
948 964

  
949 965
  rte_update_lock();
950
  src = new->attrs->proto;
951
  tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(new, rte_update_pool) : NULL;
966
  tmpa = make_tmp_attrs(new, rte_update_pool);
952 967
  rte_announce(tab, type, n, new, old, NULL, tmpa);
953 968
  rte_update_unlock();
954 969
}
......
957 972
rte_discard(rtable *t, rte *old)	/* Non-filtered route deletion, used during garbage collection */
958 973
{
959 974
  rte_update_lock();
960
  rte_recalculate(old->sender, old->net, NULL, NULL, old->attrs->proto);
975
  rte_recalculate(old->sender, old->net, NULL, NULL, old->attrs->src);
961 976
  rte_update_unlock();
962 977
}
963 978

  
......
974 989
  debug("%-1I/%2d ", n->n.prefix, n->n.pxlen);
975 990
  debug("KF=%02x PF=%02x pref=%d lm=%d ", n->n.flags, e->pflags, e->pref, now-e->lastmod);
976 991
  rta_dump(e->attrs);
977
  if (e->attrs->proto->proto->dump_attrs)
978
    e->attrs->proto->proto->dump_attrs(e);
992
  if (e->attrs->src->proto->proto->dump_attrs)
993
    e->attrs->src->proto->proto->dump_attrs(e);
979 994
  debug("\n");
980 995
}
981 996

  
......
1096 1111
    rt_next_hop_update(tab);
1097 1112

  
1098 1113
  if (tab->gc_scheduled)
1099
    rt_prune_nets(tab);
1114
    {
1115
      rt_prune_nets(tab);
1116
      rt_prune_sources(); // FIXME this should be moved to independent event
1117
    }
1100 1118
}
1101 1119

  
1102 1120
void
......
1303 1321

  
1304 1322
	/* Call a pre-comparison hook */
1305 1323
	/* Not really an efficient way to compute this */
1306
	if (e->attrs->proto->rte_recalculate)
1307
	  e->attrs->proto->rte_recalculate(tab, n, new, e, NULL);
1324
	if (e->attrs->src->proto->rte_recalculate)
1325
	  e->attrs->src->proto->rte_recalculate(tab, n, new, e, NULL);
1308 1326

  
1309 1327
	if (e != old_best)
1310 1328
	  rte_free_quick(e);
......
1502 1520
static inline void
1503 1521
do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e)
1504 1522
{
1505
  struct proto *src = e->attrs->proto;
1506 1523
  ea_list *tmpa;
1507 1524

  
1508 1525
  rte_update_lock();
1509
  tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(e, rte_update_pool) : NULL;
1526
  tmpa = make_tmp_attrs(e, rte_update_pool);
1510 1527
  if (type == RA_ACCEPTED)
1511 1528
    rt_notify_accepted(h, n, e, NULL, NULL, tmpa, p->refeeding ? 2 : 1);
1512 1529
  else
......
1889 1906
}
1890 1907

  
1891 1908
static struct hostentry *
1892
rt_find_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
1909
rt_get_hostentry(rtable *tab, ip_addr a, ip_addr ll, rtable *dep)
1893 1910
{
1894 1911
  struct hostentry *he;
1895 1912

  
......
1910 1927
void
1911 1928
rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr *gw, ip_addr *ll)
1912 1929
{
1913
  rta_apply_hostentry(a, rt_find_hostentry(tab, *gw, *ll, dep));
1930
  rta_apply_hostentry(a, rt_get_hostentry(tab, *gw, *ll, dep));
1914 1931
}
1915 1932

  
1933

  
1916 1934
/*
1917 1935
 *  CLI commands
1918 1936
 */
......
1942 1960
  rta *a = e->attrs;
1943 1961
  int primary = (e->net->routes == e);
1944 1962
  int sync_error = (e->net->n.flags & KRF_SYNC_ERROR);
1963
  void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs);
1945 1964
  struct mpnh *nh;
1946 1965

  
1947 1966
  rt_format_via(e, via);
......
1950 1969
    bsprintf(from, " from %I", a->from);
1951 1970
  else
1952 1971
    from[0] = 0;
1953
  if (a->proto->proto->get_route_info || d->verbose)
1972

  
1973
  get_route_info = a->src->proto->proto->get_route_info;
1974
  if (get_route_info || d->verbose)
1954 1975
    {
1955 1976
      /* Need to normalize the extended attributes */
1956 1977
      ea_list *t = tmpa;
......
1959 1980
      ea_merge(t, tmpa);
1960 1981
      ea_sort(tmpa);
1961 1982
    }
1962
  if (a->proto->proto->get_route_info)
1963
    a->proto->proto->get_route_info(e, info, tmpa);
1983
  if (get_route_info)
1984
    get_route_info(e, info, tmpa);
1964 1985
  else
1965 1986
    bsprintf(info, " (%d)", e->pref);
1966
  cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, via, a->proto->name,
1987
  cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, via, a->src->proto->name,
1967 1988
	     tm, from, primary ? (sync_error ? " !" : " *") : "", info);
1968 1989
  for (nh = a->nexthops; nh; nh = nh->next)
1969 1990
    cli_printf(c, -1007, "\tvia %I on %s weight %d", nh->gw, nh->iface->name, nh->weight + 1);
......
1985 2006
  for(e=n->routes; e; e=e->next)
1986 2007
    {
1987 2008
      struct ea_list *tmpa;
1988
      struct proto *p0 = e->attrs->proto;
2009
      struct rte_src *src = e->attrs->src;
1989 2010
      struct proto *p1 = d->export_protocol;
1990 2011
      struct proto *p2 = d->show_protocol;
1991 2012
      d->rt_counter++;
1992 2013
      ee = e;
1993 2014
      rte_update_lock();		/* We use the update buffer for filtering */
1994
      tmpa = p0->make_tmp_attrs ? p0->make_tmp_attrs(e, rte_update_pool) : NULL;
2015
      tmpa = make_tmp_attrs(e, rte_update_pool);
1995 2016
      ok = (d->filter == FILTER_ACCEPT || f_run(d->filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
1996
      if (p2 && p2 != p0) ok = 0;
2017
      if (p2 && p2 != src->proto) ok = 0;
1997 2018
      if (ok && d->export_mode)
1998 2019
	{
1999 2020
	  int ic;
proto/bgp/attrs.c
621 621
  return -1;
622 622
}
623 623

  
624
/*
624 625
static void
625 626
bgp_init_prefix(struct fib_node *N)
626 627
{
627 628
  struct bgp_prefix *p = (struct bgp_prefix *) N;
628 629
  p->bucket_node.next = NULL;
629 630
}
631
*/
630 632

  
631 633
static int
632 634
bgp_compare_u32(const u32 *x, const u32 *y)
......
870 872
  mb_free(buck);
871 873
}
872 874

  
875

  
876
/* Prefix hash table */
877

  
878
static inline u32 prefix_hash(ip_addr prefix, int pxlen, u32 path_id, u32 order)
879
{
880
  u32 x = ipa_hash(prefix) + pxlen + path_id;
881
  return (x * 2902958171u) >> (32 - order);
882
}
883

  
884
static inline u32 px_hash_size(struct bgp_proto *p)
885
{ return 1 << p->px_hash_order; }
886

  
887
void
888
bgp_init_prefix_table(struct bgp_proto *p, u32 order)
889
{
890
  p->px_hash_count = 0;
891
  p->px_hash_order = order;
892
  p->prefix_table = mb_allocz(p->p.pool, px_hash_size(p) * sizeof(struct bgp_prefix *));
893
  p->prefix_slab = sl_new(p->p.pool, sizeof(struct bgp_prefix));
894
}
895

  
896
static void
897
bgp_rehash_prefix_table(struct bgp_proto *p, int step)
898
{
899
  struct bgp_prefix **old_tab, *px, *px_next;
900
  u32 old_size, hash, i;
901

  
902
  old_tab = p->prefix_table;
903
  old_size = px_hash_size(p);
904

  
905
  p->px_hash_order += step;
906
  p->prefix_table = mb_allocz(p->p.pool, px_hash_size(p) * sizeof(struct bgp_prefix *));
907
  
908
  for (i = 0; i < old_size; i++)
909
    for (px = old_tab[i]; px; px = px_next)
910
      {
911
	px_next = px->next;
912
	hash = prefix_hash(px->n.prefix, px->n.pxlen, px->path_id, p->px_hash_order);
913
	px->next = p->prefix_table[hash];
914
	p->prefix_table[hash] = px;
915
      }
916

  
917
  mb_free(old_tab);
918
}
919

  
920
static struct bgp_prefix *
921
bgp_get_prefix(struct bgp_proto *p, ip_addr prefix, int pxlen, u32 path_id)
922
{
923
  struct bgp_prefix *bp;
924
  u32 hash = prefix_hash(prefix, pxlen, path_id, p->px_hash_order);
925

  
926
  for (bp = p->prefix_table[hash]; bp; bp = bp->next)
927
    if (bp->n.pxlen == pxlen && ipa_equal(bp->n.prefix, prefix) && bp->path_id == path_id)
928
      return bp;
929

  
930
  bp = sl_alloc(p->prefix_slab);
931
  bp->n.prefix = prefix;
932
  bp->n.pxlen = pxlen;
933
  bp->path_id = path_id;
934
  bp->next = p->prefix_table[hash];
935
  p->prefix_table[hash] = bp;
936

  
937
  bp->bucket_node.next = NULL;
938

  
939
  p->px_hash_count++;
940
  if ((p->px_hash_count > px_hash_size(p)) && (p->px_hash_order < 18))
941
    bgp_rehash_prefix_table(p, 1);
942

  
943
  return bp;
944
}
945

  
946
void
947
bgp_free_prefix(struct bgp_proto *p, struct bgp_prefix *bp)
948
{
949
  struct bgp_prefix **bpp;
950
  u32 hash = prefix_hash(bp->n.prefix, bp->n.pxlen, bp->path_id, p->px_hash_order);
951

  
952
  for (bpp = &p->prefix_table[hash]; *bpp; *bpp = (*bpp)->next)
953
    if (*bpp == bp)
954
      break;
955

  
956
  *bpp = bp->next;
957
  sl_free(p->prefix_slab, bp);
958

  
959
  p->px_hash_count--;
960
  if ((p->px_hash_count < (px_hash_size(p) / 4)) && (p->px_hash_order > 10))
961
    bgp_rehash_prefix_table(p, -1);
962
}
963

  
964

  
873 965
void
874 966
bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs)
875 967
{
876 968
  struct bgp_proto *p = (struct bgp_proto *) P;
877 969
  struct bgp_bucket *buck;
878 970
  struct bgp_prefix *px;
971
  rte *key;
972
  u32 path_id;
879 973

  
880 974
  DBG("BGP: Got route %I/%d %s\n", n->n.prefix, n->n.pxlen, new ? "up" : "down");
881 975

  
882 976
  if (new)
883 977
    {
978
      key = new;
884 979
      buck = bgp_get_bucket(p, n, attrs, new->attrs->source != RTS_BGP);
885 980
      if (!buck)			/* Inconsistent attribute list */
886 981
	return;
887 982
    }
888 983
  else
889 984
    {
985
      key = old;
890 986
      if (!(buck = p->withdraw_bucket))
891 987
	{
892 988
	  buck = p->withdraw_bucket = mb_alloc(P->pool, sizeof(struct bgp_bucket));
893 989
	  init_list(&buck->prefixes);
894 990
	}
895 991
    }
896
  px = fib_get(&p->prefix_fib, &n->n.prefix, n->n.pxlen);
992
  path_id = p->add_path_tx ? key->attrs->src->global_id : 0;
993
  px = bgp_get_prefix(p, n->n.prefix, n->n.pxlen, path_id);
897 994
  if (px->bucket_node.next)
898 995
    {
899 996
      DBG("\tRemoving old entry.\n");
......
1021 1118
  if (rr)
1022 1119
    {
1023 1120
      /* Handling route reflection, RFC 4456 */
1024
      struct bgp_proto *src = (struct bgp_proto *) e->attrs->proto;
1121
      struct bgp_proto *src = (struct bgp_proto *) e->attrs->src->proto;
1025 1122

  
1026 1123
      a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID));
1027 1124
      if (!a)
......
1071 1168
{
1072 1169
  rte *e = *new;
1073 1170
  struct bgp_proto *p = (struct bgp_proto *) P;
1074
  struct bgp_proto *new_bgp = (e->attrs->proto->proto == &proto_bgp) ? (struct bgp_proto *) e->attrs->proto : NULL;
1171
  struct bgp_proto *new_bgp = (e->attrs->src->proto->proto == &proto_bgp) ?
1172
    (struct bgp_proto *) e->attrs->src->proto : NULL;
1075 1173

  
1076 1174
  if (p == new_bgp)			/* Poison reverse updates */
1077 1175
    return -1;
......
1110 1208
  if (e && as_path_get_first(e->u.ptr, &as))
1111 1209
    return as;
1112 1210
  else
1113
    return ((struct bgp_proto *) r->attrs->proto)->remote_as;
1211
    return ((struct bgp_proto *) r->attrs->src->proto)->remote_as;
1114 1212
}
1115 1213

  
1116 1214
static inline int
......
1123 1221
int
1124 1222
bgp_rte_better(rte *new, rte *old)
1125 1223
{
1126
  struct bgp_proto *new_bgp = (struct bgp_proto *) new->attrs->proto;
1127
  struct bgp_proto *old_bgp = (struct bgp_proto *) old->attrs->proto;
1224
  struct bgp_proto *new_bgp = (struct bgp_proto *) new->attrs->src->proto;
1225
  struct bgp_proto *old_bgp = (struct bgp_proto *) old->attrs->src->proto;
1128 1226
  eattr *x, *y;
1129 1227
  u32 n, o;
1130 1228

  
......
1258 1356
static inline int
1259 1357
use_deterministic_med(rte *r)
1260 1358
{
1261
  struct proto *P = r->attrs->proto;
1359
  struct proto *P = r->attrs->src->proto;
1262 1360
  return (P->proto == &proto_bgp) && ((struct bgp_proto *) P)->cf->deterministic_med;
1263 1361
}
1264 1362

  
......
1543 1641
  int withdraw = 0;
1544 1642

  
1545 1643
  bzero(a, sizeof(rta));
1546
  a->proto = &bgp->p;
1547 1644
  a->source = RTS_BGP;
1548 1645
  a->scope = SCOPE_UNIVERSE;
1549 1646
  a->cast = RTC_UNICAST;
......
1752 1849
}
1753 1850

  
1754 1851
void
1755
bgp_attr_init(struct bgp_proto *p)
1852
bgp_init_bucket_table(struct bgp_proto *p)
1756 1853
{
1757 1854
  p->hash_size = 256;
1758 1855
  p->hash_limit = p->hash_size * 4;
1759 1856
  p->bucket_hash = mb_allocz(p->p.pool, p->hash_size * sizeof(struct bgp_bucket *));
1760 1857
  init_list(&p->bucket_queue);
1761 1858
  p->withdraw_bucket = NULL;
1762
  fib_init(&p->prefix_fib, p->p.pool, sizeof(struct bgp_prefix), 0, bgp_init_prefix);
1859
  // fib_init(&p->prefix_fib, p->p.pool, sizeof(struct bgp_prefix), 0, bgp_init_prefix);
1763 1860
}
1764 1861

  
1765 1862
void
proto/bgp/bgp.c
362 362
  p->conn = conn;
363 363
  p->last_error_class = 0;
364 364
  p->last_error_code = 0;
365
  bgp_attr_init(conn->bgp);
365
  bgp_init_bucket_table(p);
366
  bgp_init_prefix_table(p, 8);
367

  
366 368
  bgp_conn_set_state(conn, BS_ESTABLISHED);
367 369
  proto_notify_state(&p->p, PS_UP);
368 370
}
......
410 412
bgp_send_open(struct bgp_conn *conn)
411 413
{
412 414
  conn->start_state = conn->bgp->start_state;
413
  conn->want_as4_support = conn->bgp->cf->enable_as4 && (conn->start_state != BSS_CONNECT_NOCAP);
414
  conn->peer_as4_support = 0;	// Default value, possibly changed by receiving capability.
415

  
416
  // Default values, possibly changed by receiving capabilities.
417
  conn->peer_refresh_support = 0;
418
  conn->peer_as4_support = 0;
419
  conn->peer_add_path = 0;
415 420
  conn->advertised_as = 0;
416 421

  
417 422
  DBG("BGP: Sending open\n");
......
920 925
static struct proto *
921 926
bgp_init(struct proto_config *C)
922 927
{
923
  struct bgp_config *c = (struct bgp_config *) C;
924 928
  struct proto *P = proto_new(C, sizeof(struct bgp_proto));
929
  struct bgp_config *c = (struct bgp_config *) C;
925 930
  struct bgp_proto *p = (struct bgp_proto *) P;
926 931

  
927 932
  P->accept_ra_types = c->secondary ? RA_ACCEPTED : RA_OPTIMAL;
928 933
  P->rt_notify = bgp_rt_notify;
929
  P->rte_better = bgp_rte_better;
930 934
  P->import_control = bgp_import_control;
931 935
  P->neigh_notify = bgp_neigh_notify;
932 936
  P->reload_routes = bgp_reload_routes;
933

  
934
  if (c->deterministic_med)
935
    P->rte_recalculate = bgp_rte_recalculate;
937
  P->rte_better = bgp_rte_better;
938
  P->rte_recalculate = c->deterministic_med ? bgp_rte_recalculate : NULL;
936 939

  
937 940
  p->cf = c;
938 941
  p->local_as = c->local_as;
......
1176 1179
  else if (P->proto_state == PS_UP)
1177 1180
    {
1178 1181
      cli_msg(-1006, "    Neighbor ID:      %R", p->remote_id);
1179
      cli_msg(-1006, "    Neighbor caps:   %s%s",
1182
      cli_msg(-1006, "    Neighbor caps:   %s%s%s%s",
1180 1183
	      c->peer_refresh_support ? " refresh" : "",
1181
	      c->peer_as4_support ? " AS4" : "");
1182
      cli_msg(-1006, "    Session:          %s%s%s%s%s",
1184
	      c->peer_as4_support ? " AS4" : "",
1185
	      (c->peer_add_path & ADD_PATH_RX) ? " add-path-rx" : "",
1186
	      (c->peer_add_path & ADD_PATH_TX) ? " add-path-tx" : "");
1187
      cli_msg(-1006, "    Session:          %s%s%s%s%s%s%s",
1183 1188
	      p->is_internal ? "internal" : "external",
1184 1189
	      p->cf->multihop ? " multihop" : "",
1185 1190
	      p->rr_client ? " route-reflector" : "",
1186 1191
	      p->rs_client ? " route-server" : "",
1187
	      p->as4_session ? " AS4" : "");
1192
	      p->as4_session ? " AS4" : "",
1193
	      p->add_path_rx ? " add-path-rx" : "",
1194
	      p->add_path_tx ? " add-path-tx" : "");
1188 1195
      cli_msg(-1006, "    Source address:   %I", p->source_addr);
1189 1196
      if (P->cf->in_limit)
1190 1197
	cli_msg(-1006, "    Route limit:      %d/%d",
proto/bgp/bgp.h
43 43
  int passive;				/* Do not initiate outgoing connection */
44 44
  int interpret_communities;		/* Hardwired handling of well-known communities */
45 45
  int secondary;			/* Accept also non-best routes (i.e. RA_ACCEPTED) */
46
  int add_path;				/* Use ADD-PATH extension [draft] */
46 47
  unsigned connect_retry_time;
47 48
  unsigned hold_time, initial_hold_time;
48 49
  unsigned keepalive_time;
......
62 63
#define GW_DIRECT 1
63 64
#define GW_RECURSIVE 2
64 65

  
66
#define ADD_PATH_RX 1
67
#define ADD_PATH_TX 2
68
#define ADD_PATH_FULL 3
69

  
70

  
65 71
struct bgp_conn {
66 72
  struct bgp_proto *bgp;
67 73
  struct birdsock *sk;
......
75 81
  byte *notify_data;
76 82
  u32 advertised_as;			/* Temporary value for AS number received */
77 83
  int start_state;			/* protocol start_state snapshot when connection established */
78
  int want_as4_support;			/* Connection tries to establish AS4 session */
79
  int peer_as4_support;			/* Peer supports 4B AS numbers [RFC4893] */
80
  int peer_refresh_support;		/* Peer supports route refresh [RFC2918] */
84
  u8 peer_refresh_support;		/* Peer supports route refresh [RFC2918] */
85
  u8 peer_as4_support;			/* Peer supports 4B AS numbers [RFC4893] */
86
  u8 peer_add_path;			/* Peer supports ADD-PATH [draft] */
81 87
  unsigned hold_time, keepalive_time;	/* Times calculated from my and neighbor's requirements */
82 88
};
83 89

  
......
86 92
  struct bgp_config *cf;		/* Shortcut to BGP configuration */
87 93
  u32 local_as, remote_as;
88 94
  int start_state;			/* Substates that partitions BS_START */
89
  int is_internal;			/* Internal BGP connection (local_as == remote_as) */
90
  int as4_session;			/* Session uses 4B AS numbers in AS_PATH (both sides support it) */
95
  u8 is_internal;			/* Internal BGP connection (local_as == remote_as) */
96
  u8 as4_session;			/* Session uses 4B AS numbers in AS_PATH (both sides support it) */
97
  u8 add_path_rx;			/* Session expects receive of ADD-PATH extended NLRI */
98
  u8 add_path_tx;			/* Session expects transmit of ADD-PATH extended NLRI */
91 99
  u32 local_id;				/* BGP identifier of this router */
92 100
  u32 remote_id;			/* BGP identifier of the neighbor */
93 101
  u32 rr_cluster_id;			/* Route reflector cluster ID */
......
104 112
  struct timer *startup_timer;		/* Timer used to delay protocol startup due to previous errors (startup_delay) */
105 113
  struct bgp_bucket **bucket_hash;	/* Hash table of attribute buckets */
106 114
  unsigned int hash_size, hash_count, hash_limit;
107
  struct fib prefix_fib;		/* Prefixes to be sent */
115
  // struct fib prefix_fib;		/* Prefixes to be sent */
116
  struct bgp_prefix **prefix_table;	/* Prefixes to be sent */
117
  slab *prefix_slab;			/* Slab holding prefix nodes */
118
  u32 px_hash_order, px_hash_count;
108 119
  list bucket_queue;			/* Queue of buckets to send */
109 120
  struct bgp_bucket *withdraw_bucket;	/* Withdrawn routes */
110 121
  unsigned startup_delay;		/* Time to delay protocol startup by due to errors */
......
120 131
};
121 132

  
122 133
struct bgp_prefix {
123
  struct fib_node n;			/* Node in prefix fib */
134
  struct {
135
    ip_addr prefix;
136
    int pxlen;
137
  } n;
138
  u32 path_id;
139
  struct bgp_prefix *next;
124 140
  node bucket_node;			/* Node in per-bucket list */
125 141
};
126 142

  
......
154 170
void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code);
155 171
void bgp_stop(struct bgp_proto *p, unsigned subcode);
156 172

  
173
struct rte_source *bgp_find_source(struct bgp_proto *p, u32 path_id);
174
struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
175

  
157 176

  
158 177

  
159 178
#ifdef LOCAL_DEBUG
......
189 208
int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best);
190 209
void bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs);
191 210
int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *);
192
void bgp_attr_init(struct bgp_proto *);
193
unsigned int bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains);
211
void bgp_init_bucket_table(struct bgp_proto *);
194 212
void bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck);
213
void bgp_init_prefix_table(struct bgp_proto *p, u32 order);
214
void bgp_free_prefix(struct bgp_proto *p, struct bgp_prefix *bp);
215
unsigned int bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains);
195 216
void bgp_get_route_info(struct rte *, byte *buf, struct ea_list *attrs);
196 217

  
197 218
inline static void bgp_attach_attr_ip(struct ea_list **to, struct linpool *pool, unsigned attr, ip_addr a)
proto/bgp/config.Y
26 26
	PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH,
27 27
	INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP,
28 28
	TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC,
29
	SECONDARY)
29
	SECONDARY, ADD, PATHS, RX, TX)
30 30

  
31 31
CF_GRAMMAR
32 32

  
......
107 107
 | bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
108 108
 | bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; }
109 109
 | bgp_proto SECONDARY bool ';' { BGP_CFG->secondary = $3; }
110
 | bgp_proto ADD PATHS RX ';' { BGP_CFG->add_path = ADD_PATH_RX; }
111
 | bgp_proto ADD PATHS TX ';' { BGP_CFG->add_path = ADD_PATH_TX; }
112
 | bgp_proto ADD PATHS bool ';' { BGP_CFG->add_path = $4 ? ADD_PATH_FULL : 0; }
110 113
 | bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; }
111 114
 | bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; }
112 115
 ;
proto/bgp/packets.c
159 159
}
160 160

  
161 161
static byte *
162
bgp_put_cap_add_path(struct bgp_conn *conn, byte *buf)
163
{
164
  *buf++ = 69;		/* Capability 69: Support for ADD-PATH */
165
  *buf++ = 4;		/* Capability data length */
166

  
167
  *buf++ = 0;		/* Appropriate AF */
168
  *buf++ = BGP_AF;
169
  *buf++ = 1;		/* SAFI 1 */
170

  
171
  *buf++ = conn->bgp->cf->add_path;
172

  
173
  return buf;
174
}
175

  
176
static byte *
162 177
bgp_create_open(struct bgp_conn *conn, byte *buf)
163 178
{
164 179
  struct bgp_proto *p = conn->bgp;
......
194 209
  if (p->cf->enable_refresh)
195 210
    cap = bgp_put_cap_rr(conn, cap);
196 211

  
197
  if (conn->want_as4_support)
212
  if (p->cf->enable_as4)
198 213
    cap = bgp_put_cap_as4(conn, cap);
199 214

  
215
  if (p->cf->add_path)
216
    cap = bgp_put_cap_add_path(conn, cap);
217

  
200 218
  cap_len = cap - buf - 12;
201 219
  if (cap_len > 0)
202 220
    {
......
223 241
    {
224 242
      struct bgp_prefix *px = SKIP_BACK(struct bgp_prefix, bucket_node, HEAD(buck->prefixes));
225 243
      DBG("\tDequeued route %I/%d\n", px->n.prefix, px->n.pxlen);
244

  
245
      if (p->add_path_tx)
246
	{
247
	  put_u32(w, px->path_id);
248
	  w += 4;
249
	}
250

  
226 251
      *w++ = px->n.pxlen;
227 252
      bytes = (px->n.pxlen + 7) / 8;
228 253
      a = px->n.prefix;
......
231 256
      w += bytes;
232 257
      remains -= bytes + 1;
233 258
      rem_node(&px->bucket_node);
234
      fib_delete(&p->prefix_fib, px);
259
      bgp_free_prefix(p, px);
260
      // fib_delete(&p->prefix_fib, px);
235 261
    }
236 262
  return w - start;
237 263
}
......
244 270
      struct bgp_prefix *px = SKIP_BACK(struct bgp_prefix, bucket_node, HEAD(buck->prefixes));
245 271
      log(L_ERR "%s: - route %I/%d skipped", p->p.name, px->n.prefix, px->n.pxlen);
246 272
      rem_node(&px->bucket_node);
247
      fib_delete(&p->prefix_fib, px);
273
      bgp_free_prefix(p, px);
274
      // fib_delete(&p->prefix_fib, px);
248 275
    }
249 276
}
250 277

  
......
626 653
bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
627 654
{
628 655
  // struct bgp_proto *p = conn->bgp;
629
  int cl;
656
  int i, cl;
630 657

  
631 658
  while (len > 0)
632 659
    {
......
643 670
	  conn->peer_refresh_support = 1;
644 671
	  break;
645 672

  
646
	case 65: /* AS4 capability, RFC 4893 */ 
673
	case 65: /* AS4 capability, RFC 4893 */
647 674
	  if (cl != 4)
648 675
	    goto err;
649 676
	  conn->peer_as4_support = 1;
650
	  if (conn->want_as4_support)
677
	  if (conn->bgp->cf->enable_as4)
651 678
	    conn->advertised_as = get_u32(opt + 2);
652 679
	  break;
653 680

  
681
	case 69: /* ADD-PATH capability, draft */
682
	  if (cl % 4)
683
	    goto err;
684
	  for (i = 0; i < cl; i += 4)
685
	    if (opt[2+i+0] == 0 && opt[2+i+1] == BGP_AF && opt[2+i+2] == 1) /* Match AFI/SAFI */
686
	      conn->peer_add_path = opt[2+i+3];
687
	  if (conn->peer_add_path > ADD_PATH_FULL)
688
	    goto err;
689

  
690
	  break;
691

  
654 692
	  /* We can safely ignore all other capabilities */
655 693
	}
656 694
      len -= 2 + cl;
......
789 827
  conn->hold_time = MIN(hold, p->cf->hold_time);
790 828
  conn->keepalive_time = p->cf->keepalive_time ? : conn->hold_time / 3;
791 829
  p->remote_id = id;
792
  p->as4_session = conn->want_as4_support && conn->peer_as4_support;
830
  p->as4_session = p->cf->enable_as4 && conn->peer_as4_support;
831
  p->add_path_rx = (p->cf->add_path & ADD_PATH_RX) && (conn->peer_add_path & ADD_PATH_TX);
832
  p->add_path_tx = (p->cf->add_path & ADD_PATH_TX) && (conn->peer_add_path & ADD_PATH_RX);
833

  
834
  if (p->add_path_tx)
835
    p->p.accept_ra_types = RA_ANY;
793 836

  
794 837
  DBG("BGP: Hold timer set to %d, keepalive to %d, AS to %d, ID to %x, AS4 session to %d\n", conn->hold_time, conn->keepalive_time, p->remote_as, p->remote_id, p->as4_session);
795 838

  
......
799 842
}
800 843

  
801 844
#define DECODE_PREFIX(pp, ll) do {		\
845
  if (p->add_path_rx)				\
846
  {						\
847
    if (ll < 5) { err=1; goto done; }		\
848
    path_id = get_u32(pp);			\
849
    pp += 4;					\
850
    ll -= 4;					\
851
  }						\
802 852
  int b = *pp++;				\
803 853
  int q;					\
804 854
  ll--;						\
......
813 863
  pxlen = b;					\
814 864
} while (0)
815 865

  
866

  
867
static inline void
868
bgp_rte_update(struct bgp_proto *p, ip_addr prefix, int pxlen,
869
	       u32 path_id, u32 *last_id, struct rte_src **src,
870
	       rta *a0, rta **a)
871
{
872
  if (path_id != *last_id)
873
    {
874
      *src = rt_get_source(&p->p, path_id);
875
      *last_id = path_id;
876

  
877
      if (*a)
878
	{
879
	  rta_free(*a);
880
	  *a = NULL;
881
	}
882
    }
883

  
884
  /* Prepare cached route attributes */
885
  if (!*a)
886
    {
887
      a0->src = *src;
888
      *a = rta_lookup(a0);
889
    }
890

  
891
  net *n = net_get(p->p.table, prefix, pxlen);
892
  rte *e = rte_get_temp(rta_clone(*a));
893
  e->net = n;
894
  e->pflags = 0;
895
  e->u.bgp.suppressed = 0;
896
  rte_update2(p->p.main_ahook, n, e, *src);
897
}
898

  
899
static inline void
900
bgp_rte_withdraw(struct bgp_proto *p, ip_addr prefix, int pxlen,
901
		 u32 path_id, u32 *last_id, struct rte_src **src)
902
{
903
  if (path_id != *last_id)
904
    {
905
      *src = rt_find_source(&p->p, path_id);
906
      *last_id = path_id;
907
    }
908

  
909
  net *n = net_find(p->p.table, prefix, pxlen);
910
  rte_update2( p->p.main_ahook, n, NULL, *src);
911
}
912

  
816 913
static inline int
817 914
bgp_set_next_hop(struct bgp_proto *p, rta *a)
818 915
{
......
871 968
		 byte *attrs, int attr_len)
872 969
{
873 970
  struct bgp_proto *p = conn->bgp;
874
  net *n;
875
  rta *a0, *a = NULL;
971
  struct rte_src *src = p->p.main_source;
972
  rta *a0, *a;
876 973
  ip_addr prefix;
877 974
  int pxlen, err = 0;
975
  u32 path_id = 0;
976
  u32 last_id = 0;
878 977

  
879 978
  /* Withdraw routes */
880 979
  while (withdrawn_len)
881 980
    {
882 981
      DECODE_PREFIX(withdrawn, withdrawn_len);
883 982
      DBG("Withdraw %I/%d\n", prefix, pxlen);
884
      if (n = net_find(p->p.table, prefix, pxlen))
885
	rte_update(p->p.table, n, &p->p, &p->p, NULL);
983

  
984
      bgp_rte_withdraw(p, prefix, pxlen, path_id, &last_id, &src);
886 985
    }
887 986

  
888 987
  if (!attr_len && !nlri_len)		/* shortcut */
......
893 992
  if (conn->state != BS_ESTABLISHED)	/* fatal error during decoding */
894 993
    return;
895 994

  
896
  if (a0 && nlri_len && bgp_set_next_hop(p, a0))
897
    a = rta_lookup(a0);
995
  if (a0 && ! bgp_set_next_hop(p, a0))
996
    a0 = NULL;
997

  
998
  a = NULL;
999
  last_id = 0;
1000
  src = p->p.main_source;
898 1001

  
899 1002
  while (nlri_len)
900 1003
    {
901 1004
      DECODE_PREFIX(nlri, nlri_len);
902 1005
      DBG("Add %I/%d\n", prefix, pxlen);
903 1006

  
904
      if (a)
905
	{
906
	  rte *e = rte_get_temp(rta_clone(a));
907
	  e->net = net_get(p->p.table, prefix, pxlen);
908
	  e->pflags = 0;
909
	  e->u.bgp.suppressed = 0;
910
	  rte_update(p->p.table, e->net, &p->p, &p->p, e);
911
	}
912
      else
913
	{
914
	  /* Forced withdraw as a result of soft error */
915
	  if (n = net_find(p->p.table, prefix, pxlen))
916
	    rte_update(p->p.table, n, &p->p, &p->p, NULL);
917
	}
1007
      if (a0)
1008
	bgp_rte_update(p, prefix, pxlen, path_id, &last_id, &src, a0, &a);
1009
      else /* Forced withdraw as a result of soft error */
1010
	bgp_rte_withdraw(p, prefix, pxlen, path_id, &last_id, &src);
918 1011
    }
919 1012

  
920 1013
 done:
......
970 1063
		 byte *attrs, int attr_len)
971 1064
{
972 1065
  struct bgp_proto *p = conn->bgp;
1066
  struct rte_src *src = p->p.main_source;
973 1067
  byte *start, *x;
974 1068
  int len, len0;
975 1069
  unsigned af, sub;
976
  net *n;
977
  rta *a0, *a = NULL;
1070
  rta *a0, *a;
978 1071
  ip_addr prefix;
979 1072
  int pxlen, err = 0;
1073
  u32 path_id = 0;
1074
  u32 last_id = 0;
980 1075

  
981 1076
  p->mp_reach_len = 0;
982 1077
  p->mp_unreach_len = 0;
......
991 1086
	{
992 1087
	  DECODE_PREFIX(x, len);
993 1088
	  DBG("Withdraw %I/%d\n", prefix, pxlen);
994
	  if (n = net_find(p->p.table, prefix, pxlen))
995
	    rte_update(p->p.table, n, &p->p, &p->p, NULL);
1089
	  bgp_rte_withdraw(p, prefix, pxlen, path_id, &last_id, &src);
996 1090
	}
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff