Revision 62e64905

View differences:

conf/cf-lex.l
124 124
}
125 125

  
126 126
[02]:{DIGIT}+:{DIGIT}+ {
127
  unsigned long int l, len1, len2;
127 128
  char *e;
128
  unsigned long int l;
129 129

  
130 130
  if (yytext[0] == '0')
131
  {
131 132
    cf_lval.i64 = 0;
133
    len1 = 16;
134
    len2 = 32;
135
  }
132 136
  else
133
    cf_lval.i64 = 0x2000000000000ULL;
137
  {
138
    cf_lval.i64 = 2ULL << 48;
139
    len1 = 32;
140
    len2 = 16;
141
  }
134 142

  
135 143
  errno = 0;
136 144
  l = strtoul(yytext+2, &e, 10);
137
  if (e && (*e != ':') || errno == ERANGE || (yytext[0] == '0') && (l >= (1<<16)))
145
  if (e && (*e != ':') || (errno == ERANGE) || (l >> len1))
138 146
    cf_error("ASN out of range");
139
  cf_lval.i64 |= (((u64) l) << 32);
147
  cf_lval.i64 |= ((u64) l) << len2;
148

  
140 149
  errno = 0;
141 150
  l = strtoul(e+1, &e, 10);
142
  if (e && *e || errno == ERANGE || (yytext[0] == '2') && (l >= (1<<16)))
143
    cf_error("Assigned number out of range");
151
  if (e && *e || (errno == ERANGE) || (l >> len2))
152
    cf_error("Number out of range");
144 153
  cf_lval.i64 |= l;
154

  
145 155
  return VPN_RD;
146 156
}
147 157

  
148 158
1:{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+:{DIGIT}+ {
149 159
  unsigned long int l;
150
  char *e = strchr(yytext+2, ':');
151
  *e++ = '\0';
152 160
  ip4_addr ip4;
161
  char *e;
162

  
163
  cf_lval.i64 = 1ULL << 48;
164

  
165
  e = strchr(yytext+2, ':');
166
  *e++ = '\0';
153 167
  if (!ip4_pton(yytext+2, &ip4))
154 168
    cf_error("Invalid IPv4 address %s in Route Distinguisher", yytext+2);
169
  cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16;
170

  
155 171
  errno = 0;
156 172
  l = strtoul(e, &e, 10);
157
  if (e && *e || errno == ERANGE || (l >= (1<<16)))
158
    cf_error("Assigned number out of range");
159
  cf_lval.i64 = (1ULL<<48) | (((u64)ip4_to_u32(ip4)) << 16) | ((u64)l);
173
  if (e && *e || (errno == ERANGE) || (l >> 16))
174
    cf_error("Number out of range");
175
  cf_lval.i64 |= l;
176

  
160 177
  return VPN_RD;
161 178
}
162 179

  
conf/confbase.Y
203 203
net_vpn4_: VPN_RD net_ip4_
204 204
{
205 205
  $$ = cfg_alloc(sizeof(net_addr_vpn4));
206
  net_fill_vpn4($$, ((net_addr_ip4 *)&$2)->prefix, $2.pxlen, $1);
206
  net_fill_vpn4($$, net4_prefix(&$2), net4_pxlen(&$2), $1);
207 207
}
208 208

  
209 209
net_vpn6_: VPN_RD net_ip6_
210 210
{
211 211
  $$ = cfg_alloc(sizeof(net_addr_vpn6));
212
  net_fill_vpn6($$, ((net_addr_ip6 *)&$2)->prefix, $2.pxlen, $1);
212
  net_fill_vpn6($$, net6_prefix(&$2), net6_pxlen(&$2), $1);
213 213
}
214 214

  
215 215
net_roa4_: net_ip4_ MAX NUM AS NUM
......
229 229
};
230 230

  
231 231
net_ip_: net_ip4_ | net_ip6_ ;
232
net_roa_: net_roa4_ | net_roa6_ ;
233 232
net_vpn_: net_vpn4_ | net_vpn6_ ;
233
net_roa_: net_roa4_ | net_roa6_ ;
234 234

  
235 235
net_:
236 236
   net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
......
297 297
    label_stack_start
298 298
  | label_stack '/' NUM {
299 299
    if ($1[0] >= MPLS_MAX_LABEL_STACK)
300
      cf_error("Too many labels in stack.");
301
    $1[++$1[0]] = $3;
300
      cf_error("Too many labels in stack");
301
    $1[0]++;
302
    $1[*$1] = $3;
302 303
    $$ = $1;
303 304
  }
304 305
;
doc/bird.sgml
4140 4140
specific destination for them and you don't want to send them out through the
4141 4141
default route to prevent routing loops).
4142 4142

  
4143
<p>There are five types of static routes: `classical' routes telling to forward
4143
<p>There are four types of static routes: `classical' routes telling to forward
4144 4144
packets to a neighboring router (single path or multipath, possibly weighted),
4145
device routes specifying forwarding to hosts on a
4146
directly connected network, recursive routes computing their nexthops by doing
4147
route table lookups for a given IP, and special routes (sink, blackhole etc.)
4148
which specify a special action to be done instead of forwarding the packet.
4145
device routes specifying forwarding to hosts on a directly connected network,
4146
recursive routes computing their nexthops by doing route table lookups for a
4147
given IP, and special routes (sink, blackhole etc.)  which specify a special
4148
action to be done instead of forwarding the packet.
4149 4149

  
4150 4150
<p>When the particular destination is not available (the interface is down or
4151 4151
the next hop of the route is not a neighbor at the moment), Static just
filter/filter.h
174 174
#define SA_PROTO	 4
175 175
#define SA_SOURCE	 5
176 176
#define SA_SCOPE	 6
177
#define SA_DEST    	 8
178
#define SA_IFNAME  	 9
179
#define SA_IFINDEX    	10
177
#define SA_DEST    	 7
178
#define SA_IFNAME  	 8
179
#define SA_IFINDEX    	 9
180 180

  
181 181

  
182 182
struct f_tree {
lib/alloca.h
15 15
#include <stdlib.h>
16 16
#endif
17 17

  
18
#define allocz(len) ({ void *_x = alloca(len); memset(_x, 0, len); _x; })
19

  
18 20
#endif
lib/net.c
69 69
  case NET_VPN4:
70 70
    switch (n->vpn4.rd >> 48)
71 71
    {
72
      case 0: return bsnprintf(buf, buflen, "0:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 32), (u32) n->vpn4.rd, n->vpn4.prefix, n->vpn4.pxlen);
73
      case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I4/%d", ip4_from_u32(n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen);
74
      case 2: return bsnprintf(buf, buflen, "2:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen);
72
    case 0: return bsnprintf(buf, buflen, "0:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 32), (u32) n->vpn4.rd, n->vpn4.prefix, n->vpn4.pxlen);
73
    case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I4/%d", ip4_from_u32(n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen);
74
    case 2: return bsnprintf(buf, buflen, "2:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen);
75
    default: return bsnprintf(buf, buflen, "X:%08x:%08x %I4/%d", (u32) (n->vpn4.rd >> 32), (u32) n->vpn4.rd, n->vpn4.prefix, n->vpn4.pxlen);
75 76
    }
76
    return bsnprintf(buf, buflen, "X: %016x %I4/%d", (n->vpn4.rd), n->vpn4.prefix, n->vpn4.pxlen);
77

  
78
    /* XXX: RD format is specified for VPN4; not found any for VPN6, reusing the same as for VPN4. */
79 77
  case NET_VPN6:
78
    /* XXX: RD format is specified for VPN4; not found any for VPN6, reusing the same as for VPN4 */
80 79
    switch (n->vpn6.rd >> 48)
81 80
    {
82
      case 0: return bsnprintf(buf, buflen, "0:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen);
83
      case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I6/%d", ip4_from_u32(n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen);
84
      case 2: return bsnprintf(buf, buflen, "2:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen);
81
    case 0: return bsnprintf(buf, buflen, "0:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen);
82
    case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I6/%d", ip4_from_u32(n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen);
83
    case 2: return bsnprintf(buf, buflen, "2:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen);
84
    default: return bsnprintf(buf, buflen, "X:%08x:%08x %I6/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen);
85 85
    }
86
    return bsnprintf(buf, buflen, "X: %016x %I6/%d", (n->vpn6.rd), n->vpn6.prefix, n->vpn6.pxlen);
87 86
  case NET_ROA4:
88 87
    return bsnprintf(buf, buflen, "%I4/%u-%u AS%u",  n->roa4.prefix, n->roa4.pxlen, n->roa4.max_pxlen, n->roa4.asn);
89 88
  case NET_ROA6:
lib/net.h
306 306
static inline int net_equal_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b)
307 307
{ return net_equal((const net_addr *) a, (const net_addr *) b); }
308 308

  
309
static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
310
{ return !memcmp(a, b, sizeof(net_addr_mpls)); }
311

  
309 312

  
310 313
static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b)
311 314
{ return ip4_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
......
313 316
static inline int net_equal_prefix_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b)
314 317
{ return ip6_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
315 318

  
316
static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
317
{ return !memcmp(a, b, sizeof(net_addr_mpls)); }
318 319

  
319 320
static inline int net_zero_ip4(const net_addr_ip4 *a)
320 321
{ return !a->pxlen && ip4_zero(a->prefix); }
......
404 405
static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src)
405 406
{ memcpy(dst, src, sizeof(net_addr_mpls)); }
406 407

  
408

  
409
/* XXXX */
410
static inline u32 u64_hash(u64 a)
411
{ return u32_hash(a); }
412

  
407 413
static inline u32 net_hash_ip4(const net_addr_ip4 *n)
408 414
{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
409 415

  
410 416
static inline u32 net_hash_ip6(const net_addr_ip6 *n)
411 417
{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
412 418

  
413
/* XXXX */
414
static inline u32 u64_hash(u64 a)
415
{ return u32_hash(a); }
416

  
417 419
static inline u32 net_hash_vpn4(const net_addr_vpn4 *n)
418 420
{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26) ^ u64_hash(n->rd); }
419 421

  
......
452 454

  
453 455
static inline int net_validate_mpls(const net_addr_mpls *n)
454 456
{
455
  return n->label < (1<<20);
457
  return n->label < (1 << 20);
456 458
}
457 459

  
458 460
int net_validate(const net_addr *N);
nest/route.h
390 390
#define RTC_MULTICAST 2
391 391
#define RTC_ANYCAST 3			/* IPv6 Anycast */
392 392

  
393
#define RTD_UNICAST 0			/* Next hop is neighbor router */
393
#define RTD_NONE 0			/* Undefined next hop */
394
#define RTD_UNICAST 1			/* Next hop is neighbor router */
394 395
#define RTD_BLACKHOLE 2			/* Silently drop packets */
395 396
#define RTD_UNREACHABLE 3		/* Reject as unreachable */
396 397
#define RTD_PROHIBIT 4			/* Administratively prohibited */
397
#define RTD_NONE 6			/* Invalid RTD */
398 398

  
399 399
					/* Flags for net->n.flags, used by kernel syncer */
400 400
#define KRF_INSTALLED 0x80		/* This route should be installed in the kernel */
......
408 408

  
409 409
/* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */
410 410
static inline int rte_is_reachable(rte *r)
411
{ uint d = r->attrs->dest; return (d == RTD_UNICAST); }
411
{ return r->attrs->dest == RTD_UNICAST; }
412 412

  
413 413

  
414 414
/*
......
523 523
struct nexthop *nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, linpool *lp);
524 524
static inline void nexthop_link(struct rta *a, struct nexthop *from)
525 525
{ memcpy(&a->nh, from, nexthop_size(from)); }
526
void nexthop_insert(struct nexthop *n, struct nexthop *y);
526
void nexthop_insert(struct nexthop **n, struct nexthop *y);
527 527
int nexthop_is_sorted(struct nexthop *x);
528 528

  
529 529
void rta_init(void);
nest/rt-attr.c
150 150
  for (; x; x = x->next)
151 151
  {
152 152
    h ^= ipa_hash(x->gw) ^ (h << 5) ^ (h >> 9);
153
    for (int i=0; i<x->labels; i++)
153

  
154
    for (int i = 0; i < x->labels; i++)
154 155
      h ^= x->label[i] ^ (h << 6) ^ (h >> 7);
155 156
  }
156 157

  
......
164 165
  {
165 166
    if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) || (x->weight != y->weight) || (x->labels != y->labels))
166 167
      return 0;
167
    for (int i=0; i<x->labels; i++)
168

  
169
    for (int i = 0; i < x->labels; i++)
168 170
      if (x->label[i] != y->label[i])
169 171
	return 0;
170 172
  }
171 173

  
172
  return 1;
174
  return x == y;
173 175
}
174 176

  
175 177
static int
......
195 197
  if (r)
196 198
    return r;
197 199

  
198
  for (int i=0; i<y->labels; i++)
200
  for (int i = 0; i < y->labels; i++)
199 201
  {
200 202
    r = ((int) y->label[i]) - ((int) x->label[i]);
201 203
    if (r)
......
271 273
}
272 274

  
273 275
void
274
nexthop_insert(struct nexthop *n, struct nexthop *x)
276
nexthop_insert(struct nexthop **n, struct nexthop *x)
275 277
{
276
  struct nexthop tmp;
277
  memcpy(&tmp, n, sizeof(struct nexthop));
278
  if (nexthop_compare_node(n, x) > 0) /* Insert to the included nexthop */
279
  {
280
    memcpy(n, x, sizeof(struct nexthop));
281
    memcpy(x, &tmp, sizeof(struct nexthop));
282
    n->next = x;
283
    return;
284
  }
285

  
286
  for (struct nexthop **nn = &(n->next); *nn; nn = &((*nn)->next))
278
  for (; *n; n = &((*n)->next))
287 279
  {
288
    int cmp = nexthop_compare_node(*nn, x);
280
    int cmp = nexthop_compare_node(*n, x);
289 281

  
290 282
    if (cmp < 0)
291 283
      continue;
292
    
293
    if (cmp > 0)
294
    {
295
      x->next = *nn;
296
      *nn = x;
297
    }
298
    
299
    return;
284
    else if (cmp > 0)
285
      break;
286
    else
287
      return;
300 288
  }
301 289

  
290
  x->next = *n;
291
  *n = x;
302 292
}
303 293

  
304 294
int
......
314 304
static inline slab *
315 305
nexthop_slab(struct nexthop *nh)
316 306
{
317
  return nexthop_slab_[nh->labels > 2 ? 3 : nh->labels];
307
  return nexthop_slab_[MIN(nh->labels, 3)];
318 308
}
319 309

  
320 310
static struct nexthop *
nest/rt-dev.c
79 79
	.source = RTS_DEVICE,
80 80
	.scope = SCOPE_UNIVERSE,
81 81
	.dest = RTD_UNICAST,
82
	.nh = {
83
	  .iface = ad->iface
84
	}
82
	.nh.iface = ad->iface,
85 83
      };
86 84

  
87 85
      a = rta_lookup(&a0);
nest/rt-table.c
1768 1768
rta_apply_hostentry(rta *a, struct hostentry *he)
1769 1769
{
1770 1770
  a->hostentry = he;
1771
  
1772 1771
  a->dest = he->dest;
1773 1772
  a->igp_metric = he->igp_metric;
1774 1773

  
......
1810 1809
static inline rte *
1811 1810
rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
1812 1811
{
1813
  rta *ap = alloca(RTA_MAX_SIZE);
1814
  memcpy(ap, old->attrs, rta_size(old->attrs));
1815
  rta_apply_hostentry(ap, old->attrs->hostentry);
1816
  ap->aflags = 0;
1812
  rta *a = alloca(RTA_MAX_SIZE);
1813
  memcpy(a, old->attrs, rta_size(old->attrs));
1814
  rta_apply_hostentry(a, old->attrs->hostentry);
1815
  a->aflags = 0;
1817 1816

  
1818 1817
  rte *e = sl_alloc(rte_slab);
1819 1818
  memcpy(e, old, sizeof(rte));
1820
  e->attrs = rta_lookup(ap);
1819
  e->attrs = rta_lookup(a);
1821 1820

  
1822 1821
  return e;
1823 1822
}
......
2373 2372
	}
2374 2373

  
2375 2374
      if ((a->dest == RTD_UNICAST) && ipa_zero(a->nh.gw) && !a->next)
2376
	{ /* We have singlepath device route */
2375
	{
2376
	  /* We have singlepath device route */
2377 2377
	  if (if_local_addr(he->addr, a->nh.iface))
2378 2378
	    {
2379 2379
	      /* The host address is a local address, this is not valid */
......
2389 2389
      else
2390 2390
	{
2391 2391
	  /* The host is reachable through some route entry */
2392
	  he->nh = (&a->nh);
2392
	  he->nh = &(a->nh);
2393 2393
	  he->dest = a->dest;
2394 2394
	}
2395 2395

  
proto/bgp/attrs.c
1461 1461
static inline int
1462 1462
rte_resolvable(rte *rt)
1463 1463
{
1464
  int rd = rt->attrs->dest;
1465
  return (rd == RTD_UNICAST);
1464
  return rt->attrs->dest == RTD_UNICAST;
1466 1465
}
1467 1466

  
1468 1467
int
proto/bgp/packets.c
700 700
      WITHDRAW(BAD_NEXT_HOP);
701 701

  
702 702
    a->dest = RTD_UNICAST;
703
    a->nh.gw = nbr->addr;
704
    a->nh.iface = nbr->iface;
705
    a->nh.next = NULL;
703
    a->nh = (struct nexthop){ .gw = nbr->addr, .iface = nbr->iface };
706 704
    a->hostentry = NULL;
707 705
    a->igp_metric = 0;
708 706
  }
......
749 747
  if (s->channel->cf->next_hop_self)
750 748
    return 0;
751 749

  
752
  /* We need valid global gateway */
753
  if ((ra->dest != RTD_UNICAST) || (ra->nh.next) || ipa_zero(ra->nh.gw) || ipa_is_link_local(ra->nh.gw))
750
  /* We need one valid global gateway */
751
  if ((ra->dest != RTD_UNICAST) || ra->nh.next || ipa_zero(ra->nh.gw) || ipa_is_link_local(ra->nh.gw))
754 752
    return 0;
755 753

  
756 754
  /* Use it when exported to internal peers */
......
1434 1432

  
1435 1433
  if (ea)
1436 1434
  {
1437
    a = alloca(sizeof(struct rta));
1438
    memset(a, 0, sizeof(struct rta));
1435
    a = allocz(sizeof(struct rta));
1439 1436

  
1440 1437
    a->source = RTS_BGP;
1441 1438
    a->scope = SCOPE_UNIVERSE;
1442
    a->dest = RTD_UNREACHABLE;
1443 1439
    a->from = s->proto->cf->remote_ip;
1444 1440
    a->eattrs = ea;
1445 1441

  
proto/ospf/rt.c
36 36
static inline struct nexthop *
37 37
new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight)
38 38
{
39
  struct nexthop *nh = lp_alloc(p->nhpool, sizeof(struct nexthop));
40
  nh->labels = 0;
39
  struct nexthop *nh = lp_allocz(p->nhpool, sizeof(struct nexthop));
41 40
  nh->gw = gw;
42 41
  nh->iface = iface;
43
  nh->next = NULL;
44 42
  nh->weight = weight;
45 43
  return nh;
46 44
}
......
1907 1905
    (nf->n.metric1 != nf->old_metric1) || (nf->n.metric2 != nf->old_metric2) ||
1908 1906
    (nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid) ||
1909 1907
    (nr->source != or->source) || (nr->dest != or->dest) ||
1910
    (nr->nh.iface != or->nh.iface) || !ipa_equal(nr->nh.gw, or->nh.gw) ||
1911 1908
    !nexthop_same(&(nr->nh), &(or->nh));
1912 1909
}
1913 1910

  
......
1952 1949
	.src = p->p.main_source,
1953 1950
	.source = nf->n.type,
1954 1951
	.scope = SCOPE_UNIVERSE,
1952
	.dest = RTD_UNICAST,
1953
	.nh = *(nf->n.nhs),
1955 1954
      };
1956 1955

  
1957
      nexthop_link(&a0, nf->n.nhs);
1958
      a0.dest = RTD_UNICAST;
1959

  
1960 1956
      if (reload || ort_changed(nf, &a0))
1961 1957
      {
1962 1958
	rta *a = rta_lookup(&a0);
proto/pipe/pipe.c
43 43

  
44 44
#include "pipe.h"
45 45

  
46
#include <alloca.h>
47

  
48 46
static void
49 47
pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old, ea_list *attrs)
50 48
{
proto/rip/rip.c
147 147
      .src = p->p.main_source,
148 148
      .source = RTS_RIP,
149 149
      .scope = SCOPE_UNIVERSE,
150
      .dest = RTD_UNICAST,
150 151
    };
151 152

  
152 153
    u8 rt_metric = rt->metric;
153 154
    u16 rt_tag = rt->tag;
154
    struct rip_rte *rt2 = rt->next;
155 155

  
156
    /* Find second valid rte */
157
    while (rt2 && !rip_valid_rte(rt2))
158
      rt2 = rt2->next;
159

  
160
    a0.dest = RTD_UNICAST;
161
    if (p->ecmp && rt2)
156
    if (p->ecmp)
162 157
    {
163 158
      /* ECMP route */
159
      struct nexthop *nhs = NULL;
164 160
      int num = 0;
165 161

  
166 162
      for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next)
......
168 164
	if (!rip_valid_rte(rt))
169 165
	    continue;
170 166

  
171
	struct nexthop *nh = (a0.nh.next ? &(a0.nh) : alloca(sizeof(struct nexthop)));
167
	struct nexthop *nh = allocz(sizeof(struct nexthop));
172 168

  
173 169
	nh->gw = rt->next_hop;
174 170
	nh->iface = rt->from->nbr->iface;
175 171
	nh->weight = rt->from->ifa->cf->ecmp_weight;
176 172

  
177
	if (a0.nh.next)
178
	  nexthop_insert(&(a0.nh), nh);
179

  
173
	nexthop_insert(&nhs, nh);
180 174
	num++;
181 175

  
182 176
	if (rt->tag != rt_tag)
183 177
	  rt_tag = 0;
184 178
      }
179

  
180
      a0.nh = *nhs;
185 181
    }
186 182
    else
187 183
    {
188 184
      /* Unipath route */
189
      a0.nh.next = NULL;
185
      a0.from = rt->from->nbr->addr;
190 186
      a0.nh.gw = rt->next_hop;
191 187
      a0.nh.iface = rt->from->nbr->iface;
192
      a0.from = rt->from->nbr->addr;
193 188
    }
194 189

  
195 190
    rta *a = rta_lookup(&a0);
proto/rpki/rpki.c
124 124
    .src = p->p.main_source,
125 125
    .source = RTS_RPKI,
126 126
    .scope = SCOPE_UNIVERSE,
127
    .dest = RTD_BLACKHOLE,
127
    .dest = RTD_NONE,
128 128
  };
129 129

  
130 130
  rta *a = rta_lookup(&a0);
proto/static/config.Y
13 13
CF_DEFINES
14 14

  
15 15
#define STATIC_CFG ((struct static_config *) this_proto)
16
static struct static_route *this_srt, *last_srt;
16
static struct static_route *this_srt, *this_snh;
17 17
static struct f_inst **this_srt_last_cmd;
18 18

  
19
static struct static_route *
20
static_nexthop_new(void)
21
{
22
  struct static_route *nh;
23

  
24
  if (!this_snh)
25
  {
26
    /* First next hop */
27
    nh = this_srt;
28
    rem_node(&this_srt->n);
29
  }
30
  else
31
  {
32
    /* Additional next hop */
33
    nh = cfg_allocz(sizeof(struct static_route));
34
    nh->net = this_srt->net;
35
    this_snh->mp_next = nh;
36
  }
37

  
38
  nh->dest = RTD_UNICAST;
39
  nh->mp_head = this_srt;
40
  return nh;
41
};
42

  
19 43
static void
20 44
static_route_finish(void)
21 45
{ }
......
45 69
 | static_proto stat_route stat_route_opt_list ';' { static_route_finish(); }
46 70
 ;
47 71

  
48
stat_nexthop_via: VIA
49
{
50
  if (last_srt)
51
  {
52
    last_srt = (last_srt->mp_next = cfg_allocz(sizeof(struct static_route)));
53
    last_srt->net = this_srt->net;
54
  }
55
  else
56
  {
57
    last_srt = this_srt;
58
    rem_node(&this_srt->n);
59
  }
60

  
61
  last_srt->mp_head = this_srt;
62
  last_srt->dest = RTD_UNICAST;
63
};
64

  
65
stat_nexthop_ident:
66
    stat_nexthop_via ipa ipa_scope {
67
      last_srt->via = $2;
68
      last_srt->iface = $3;
69
      add_tail(&STATIC_CFG->neigh_routes, &last_srt->n);
72
stat_nexthop:
73
    VIA ipa ipa_scope {
74
      this_snh = static_nexthop_new();
75
      this_snh->via = $2;
76
      this_snh->iface = $3;
77
      add_tail(&STATIC_CFG->neigh_routes, &this_snh->n);
70 78
    }
71
  | stat_nexthop_via TEXT {
72
      last_srt->via = IPA_NONE;
73
      last_srt->if_name = $2;
74
      add_tail(&STATIC_CFG->iface_routes, &last_srt->n);
79
  | VIA TEXT {
80
      this_snh = static_nexthop_new();
81
      this_snh->via = IPA_NONE;
82
      this_snh->if_name = $2;
83
      add_tail(&STATIC_CFG->iface_routes, &this_snh->n);
75 84
    }
76
  | stat_nexthop_ident MPLS label_stack {
77
    last_srt->label_count = $3[0];
78
    last_srt->label_stack = &($3[1]);
85
  | stat_nexthop MPLS label_stack {
86
    this_snh->label_count = $3[0];
87
    this_snh->label_stack = &($3[1]);
79 88
  }
80
  | stat_nexthop_ident WEIGHT expr {
81
    last_srt->weight = $3 - 1;
89
  | stat_nexthop WEIGHT expr {
90
    this_snh->weight = $3 - 1;
82 91
    if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256");
83 92
  }
84
  | stat_nexthop_ident BFD bool { last_srt->use_bfd = $3; cf_check_bfd($3); }
93
  | stat_nexthop BFD bool {
94
    this_snh->use_bfd = $3; cf_check_bfd($3);
95
  }
85 96
;
86 97

  
87
stat_nexthop:
88
    stat_nexthop_ident
89
  | stat_nexthop stat_nexthop_ident
98
stat_nexthops:
99
    stat_nexthop
100
  | stat_nexthops stat_nexthop
90 101
;
91 102

  
92 103
stat_route0: ROUTE net_any {
......
95 106
     this_srt->net = $2;
96 107
     this_srt_last_cmd = &(this_srt->cmds);
97 108
     this_srt->mp_next = NULL;
98
     last_srt = NULL;
109
     this_snh = NULL;
99 110
  }
100 111
 ;
101 112

  
102 113
stat_route:
103
   stat_route0 stat_nexthop
114
   stat_route0 stat_nexthops
104 115
 | stat_route0 RECURSIVE ipa {
105 116
      this_srt->dest = RTDX_RECURSIVE;
106 117
      this_srt->via = $3;
proto/static/static.c
60 60
static void
61 61
static_install(struct proto *p, struct static_route *r)
62 62
{
63
  rta *ap = alloca(RTA_MAX_SIZE);
63
  rta *ap = allocz(RTA_MAX_SIZE);
64 64
  rte *e;
65 65

  
66 66
  if (!(r->state & STS_WANT) && (r->state & (STS_INSTALLED | STS_FORCE)) && r->dest != RTD_UNICAST)
67 67
    goto drop;
68 68

  
69 69
  DBG("Installing static route %N, rtd=%d\n", r->net, r->dest);
70
  bzero(ap, RTA_MAX_SIZE);
71 70
  ap->src = p->main_source;
72
  ap->source = ((r->dest == RTD_UNICAST) && ipa_zero(r->via)) ? RTS_STATIC_DEVICE : RTS_STATIC;
71
  ap->source = RTS_STATIC;
73 72
  ap->scope = SCOPE_UNIVERSE;
74 73
  ap->dest = r->dest;
75 74

  
76 75
  if (r->dest == RTD_UNICAST)
77 76
    {
77
      struct nexthop *nhs = NULL;
78 78
      struct static_route *r2;
79
      int num = 0, update = 0;
79
      int update = 0;
80 80

  
81
      r = r->mp_head;
81 82
      for (r2 = r; r2; r2 = r2->mp_next)
82 83
      {
83

  
84 84
	if ((r2->state & STS_FORCE) ||
85 85
	    (!!(r2->state & STS_INSTALLED) != !!(r2->state & STS_WANT)))
86 86
	  update++;
87 87

  
88 88
	if (r2->state & STS_WANT)
89
	  {
90
	    struct nexthop *nh = (ap->nh.next) ? alloca(NEXTHOP_MAX_SIZE) : &(ap->nh);
91
	    if (ipa_zero(r2->via)) // Device nexthop
92
	      {
93
		nh->gw = IPA_NONE;
94
		nh->iface = r2->iface;
95
	      }
96
	    else // Router nexthop
97
	      {
98
		nh->gw = r2->via;
99
		nh->iface = r2->neigh->iface;
100
	      }
101
	    nh->weight = r2->weight;
102
	    nh->labels = r2->label_count;
103
	    for (int i=0; i<nh->labels; i++)
104
	      nh->label[i] = r2->label_stack[i];
105

  
106
	    if (ap->nh.next)
107
	      nexthop_insert(&(ap->nh), nh);
108
	    r2->state |= STS_INSTALLED;
109
	    num++;
110
	  }
89
	{
90
	  struct nexthop *nh = allocz(NEXTHOP_MAX_SIZE);
91

  
92
	  nh->gw = r2->via;
93
	  nh->iface = r2->neigh ? r2->neigh->iface : r2->iface;
94
	  nh->weight = r2->weight;
95
	  nh->labels = r2->label_count;
96
	  memcpy(nh->label, r2->label_stack, r2->label_count * sizeof(u32));
97

  
98
	  r2->state |= STS_INSTALLED;
99
	  nexthop_insert(&nhs, nh);
100
	}
111 101
	else
112 102
	  r2->state = 0;
113 103
      }
......
115 105
      if (!update) // Nothing changed
116 106
	return;
117 107

  
118
      r = r->mp_head;
119

  
120
      if (!num) // No nexthop to install
108
      if (!nhs) // No nexthop to install
121 109
      {
122 110
drop:
123 111
	rte_update(p, r->net, NULL);
124 112
	return;
125 113
      }
114

  
115
      ap->dest = RTD_UNICAST;
116
      nexthop_link(ap, nhs);
126 117
    }
127 118
  else
128 119
    r->state |= STS_INSTALLED;
129
  
120

  
130 121
  if (r->dest == RTDX_RECURSIVE)
131 122
    {
132 123
      ap->nh.labels_append = ap->nh.labels = r->label_count;
sysdep/bsd/krt-sock.c
193 193
  struct ks_msg msg;
194 194
  char *body = (char *)msg.buf;
195 195
  sockaddr gate, mask, dst;
196
  ip_addr gw;
197 196

  
198 197
  DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw);
199 198

  
......
223 222
    msg.rtm.rtm_flags |= RTF_BLACKHOLE;
224 223
#endif
225 224

  
226
  /* This is really very nasty, but I'm not able
227
   * to add "(reject|blackhole)" route without
228
   * gateway set
225
  /*
226
   * This is really very nasty, but I'm not able to add reject/blackhole route
227
   * without gateway address.
229 228
   */
230
  if(!i)
229
  if (!i)
231 230
  {
232
    i = HEAD(iface_list);
233

  
234 231
    WALK_LIST(j, iface_list)
235 232
    {
236 233
      if (j->flags & IF_LOOPBACK)
......
239 236
        break;
240 237
      }
241 238
    }
242
  }
243 239

  
244
  gw = a->nh.gw;
245

  
246
  /* Embed interface ID to link-local address */
247
  if (ipa_is_link_local(gw))
248
    _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
240
    if (!i)
241
    {
242
      log(L_ERR "KRT: Cannot find loopback iface");
243
      return -1;
244
    }
245
  }
249 246

  
250 247
  int af = AF_UNSPEC;
251 248

  
......
261 258
      return -1;
262 259
  }
263 260

  
264

  
265 261
  sockaddr_fill(&dst,  af, net_prefix(net->n.addr), NULL, 0);
266 262
  sockaddr_fill(&mask, af, net_pxmask(net->n.addr), NULL, 0);
267
  sockaddr_fill(&gate, af, gw, NULL, 0);
268 263

  
269 264
  switch (a->dest)
270 265
  {
271
    case RTD_UNICAST:
272
      if (ipa_zero(gw))
273
      {
274
	if(i)
275
	{
276
#ifdef RTF_CLONING
277
	  if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS)	/* PTP */
278
	    msg.rtm.rtm_flags |= RTF_CLONING;
279
#endif
266
  case RTD_UNICAST:
267
    if (ipa_nonzero(a->nh.gw))
268
    {
269
      ip_addr gw = a->nh.gw;
280 270

  
281
	  if(!i->addr) {
282
	    log(L_ERR "KRT: interface %s has no IP addess", i->name);
283
	    return -1;
284
	  }
285

  
286
	  sockaddr_fill(&gate, ipa_is_ip4(i->addr->ip) ? AF_INET : AF_INET6, i->addr->ip, NULL, 0);
287
	  msg.rtm.rtm_addrs |= RTA_GATEWAY;
288
	}
289
      } else {
290
	msg.rtm.rtm_flags |= RTF_GATEWAY;
291
	msg.rtm.rtm_addrs |= RTA_GATEWAY;
292
      }
271
      /* Embed interface ID to link-local address */
272
      if (ipa_is_link_local(gw))
273
	_I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
274

  
275
      sockaddr_fill(&gate, af, gw, NULL, 0);
276
      msg.rtm.rtm_flags |= RTF_GATEWAY;
277
      msg.rtm.rtm_addrs |= RTA_GATEWAY;
293 278
      break;
279
    }
294 280

  
295 281
#ifdef RTF_REJECT
296
    case RTD_UNREACHABLE:
282
  case RTD_UNREACHABLE:
297 283
#endif
298 284
#ifdef RTF_BLACKHOLE
299
    case RTD_BLACKHOLE:
285
  case RTD_BLACKHOLE:
300 286
#endif
301
    default:
302
      bug("krt-sock: unknown flags, but not filtered");
287
  {
288
    /* Fallback for all other valid cases */
289
    if (!i->addr)
290
    {
291
      log(L_ERR "KRT: interface %s has no IP addess", i->name);
292
      return -1;
293
    }
294

  
295
#ifdef RTF_CLONING
296
    if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS)	/* PTP */
297
      msg.rtm.rtm_flags |= RTF_CLONING;
298
#endif
299

  
300
    sockaddr_fill(&gate, ipa_is_ip4(i->addr->ip) ? AF_INET : AF_INET6, i->addr->ip, NULL, 0);
301
    msg.rtm.rtm_addrs |= RTA_GATEWAY;
302
  }
303

  
304
  default:
305
    bug("krt-sock: unknown flags, but not filtered");
303 306
  }
304 307

  
305 308
  msg.rtm.rtm_index = i->index;
......
497 500
    }
498 501

  
499 502
  a.dest = RTD_UNICAST;
500
  a.nh.next = NULL;
501 503
  if (flags & RTF_GATEWAY)
502 504
  {
503 505
    neighbor *ng;
......
520 522
	return;
521 523
      }
522 524
  }
523
  else
524
    a.nh.gw = IPA_NONE;
525 525

  
526 526
 done:
527 527
  e = rte_get_temp(&a);
sysdep/linux/netlink.c
320 320
  [IFA_ADDRESS]	  = { 1, 1, sizeof(ip4_addr) },
321 321
  [IFA_LOCAL]	  = { 1, 1, sizeof(ip4_addr) },
322 322
  [IFA_BROADCAST] = { 1, 1, sizeof(ip4_addr) },
323
  [IFA_FLAGS]     = { 1, 1, sizeof(u32) },
323 324
};
324 325

  
325 326
static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = {
......
543 544

  
544 545
  h->nlmsg_len += sizeof(*via);
545 546

  
546
  if (ipa_is_ip4(ipa)) {
547
    ip4_addr ip4 = ipa_to_ip4(ipa);
548
    ip4 = ip4_hton(ip4);
547
  if (ipa_is_ip4(ipa))
548
  {
549 549
    via->rtvia_family = AF_INET;
550
    memcpy(via->rtvia_addr, &ip4, sizeof(ip4));
551
    h->nlmsg_len += sizeof(ip4);
552
  } else {
553
    ip6_addr ip6 = ipa_to_ip6(ipa);
554
    ip6 = ip6_hton(ip6);
550
    put_ip4(via->rtvia_addr, ipa_to_ip4(ipa));
551
    h->nlmsg_len += sizeof(ip4_addr);
552
  }
553
  else
554
  {
555 555
    via->rtvia_family = AF_INET6;
556
    memcpy(via->rtvia_addr, &ip6, sizeof(ip6));
557
    h->nlmsg_len += sizeof(ip6);
556
    put_ip6(via->rtvia_addr, ipa_to_ip6(ipa));
557
    h->nlmsg_len += sizeof(ip6_addr);
558 558
  }
559 559

  
560 560
  nl_close_attr(h, nest);
......
669 669
	}
670 670
      else
671 671
	rv->gw = IPA_NONE;
672

  
672 673
      if (a[RTA_ENCAP_TYPE])
673 674
	{
674 675
	  if (rta_get_u16(a[RTA_ENCAP_TYPE]) != LWTUNNEL_ENCAP_MPLS) {
......
1092 1093
  rta *a = e->attrs;
1093 1094

  
1094 1095
  switch (a->dest)
1095
    {
1096
  {
1096 1097
    case RTD_UNICAST:
1097
      for (struct nexthop *nh = &(a->nh); nh; nh = nh->next)
1098
	if (nh->iface)
1099
	  return 1;
1100
      return 0;
1101 1098
    case RTD_BLACKHOLE:
1102 1099
    case RTD_UNREACHABLE:
1103 1100
    case RTD_PROHIBIT:
1104
      break;
1101
      return 1;
1102

  
1105 1103
    default:
1106 1104
      return 0;
1107
    }
1108
  return 1;
1105
  }
1109 1106
}
1110 1107

  
1111 1108
static inline int
......
1210 1207

  
1211 1208

  
1212 1209
dest:
1213
  /* a->iface != NULL checked in krt_capable() for router and device routes */
1214 1210
  switch (dest)
1215 1211
    {
1216 1212
    case RTD_UNICAST:
......
1502 1498
  switch (i->rtm_type)
1503 1499
    {
1504 1500
    case RTN_UNICAST:
1501
      ra->dest = RTD_UNICAST;
1505 1502

  
1506 1503
      if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET))
1507 1504
	{
......
1512 1509
	      return;
1513 1510
	    }
1514 1511

  
1515
	  nexthop_link(ra, nh);
1512
	  ra->nh = *nh;
1516 1513
	  break;
1517 1514
	}
1518 1515

  
......
1698 1695
  else
1699 1696
  {
1700 1697
    /* Merge next hops with the stored route */
1701
    rta *a = s->attrs;
1698
    rta *oa = s->attrs;
1702 1699

  
1703
    nexthop_insert(&a->nh, &ra->nh);
1700
    struct nexthop *nhs = &oa->nh;
1701
    nexthop_insert(&nhs, &ra->nh);
1702

  
1703
    /* Perhaps new nexthop is inserted at the first position */
1704
    if (nhs == &ra->nh)
1705
    {
1706
      /* Swap rtas */
1707
      s->attrs = ra;
1708

  
1709
      /* Keep old eattrs */
1710
      ra->eattrs = oa->eattrs;
1711
    }
1704 1712
  }
1705 1713
}
1706 1714

  
sysdep/unix/krt.c
984 984
static int
985 985
krt_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
986 986
{
987
  struct krt_proto *p = (struct krt_proto *) P;
987
  // struct krt_proto *p = (struct krt_proto *) P;
988 988
  rte *e = *new;
989 989

  
990 990
  if (e->attrs->src->proto == P)
......
1005 1005
    return -1;
1006 1006
  }
1007 1007

  
1008
  if (!KRT_CF->devroutes && (e->attrs->source != RTS_STATIC_DEVICE))
1009
  {
1010
    struct nexthop *nh = &(e->attrs->nh);
1011
    for (; nh; nh = nh->next)
1012
      if (ipa_nonzero(nh->gw))
1013
	break;
1014

  
1015
    if (!nh) /* Gone through all the nexthops and no explicit GW found */
1016
      return -1;
1017
  }
1018

  
1019 1008
  if (!krt_capable(e))
1020 1009
    return -1;
1021 1010

  

Also available in: Unified diff