Revision 11cb6202 proto/bgp/attrs.c

View differences:

proto/bgp/attrs.c
55 55
}
56 56

  
57 57
static int
58
bgp_check_path(struct bgp_proto *p UNUSED, byte *a, int len)
58
bgp_check_path(byte *a, int len, int bs, int errcode)
59 59
{
60 60
  while (len)
61 61
    {
62 62
      DBG("Path segment %02x %02x\n", a[0], a[1]);
63 63
      if (len < 2 ||
64
	  a[0] != AS_PATH_SET && a[0] != AS_PATH_SEQUENCE ||
65
	  2*a[1] + 2 > len)
66
	return 11;
67
      len -= 2*a[1] + 2;
68
      a += 2*a[1] + 2;
64
	  (a[0] != AS_PATH_SET && a[0] != AS_PATH_SEQUENCE) ||
65
	  bs * a[1] + 2 > len)
66
	return errcode;
67
      len -= bs * a[1] + 2;
68
      a += bs * a[1] + 2;
69 69
    }
70 70
  return 0;
71 71
}
72 72

  
73 73
static int
74
bgp_check_as_path(struct bgp_proto *p, byte *a, int len)
75
{
76
  return bgp_check_path(a, len, (bgp_as4_support && p->as4_support) ? 4 : 2, 11);
77
}
78

  
79
static int
80
bgp_check_as4_path(struct bgp_proto *p, byte *a, int len)
81
{
82
  if (bgp_as4_support && (! p->as4_support))
83
    return bgp_check_path(a, len, 4, 9);
84
  else 
85
    return 0;
86
}
87

  
88

  
89
static int
74 90
bgp_check_next_hop(struct bgp_proto *p UNUSED, byte *a, int len)
75 91
{
76 92
#ifdef IPV6
......
88 104
}
89 105

  
90 106
static int
107
bgp_check_aggregator(struct bgp_proto *p UNUSED, UNUSED byte *a, int len)
108
{
109
  int exp_len = (bgp_as4_support && p->as4_support) ? 8 : 6;
110
  
111
  return (len == exp_len) ? 0 : 5;
112
}
113

  
114
static int
91 115
bgp_check_reach_nlri(struct bgp_proto *p UNUSED, byte *a UNUSED, int len UNUSED)
92 116
{
93 117
#ifdef IPV6
......
113 137
  { "origin", 1, BAF_TRANSITIVE, EAF_TYPE_INT, 1,				/* BA_ORIGIN */
114 138
    bgp_check_origin, bgp_format_origin },
115 139
  { "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH, 1,				/* BA_AS_PATH */
116
    bgp_check_path, NULL },
140
    bgp_check_as_path, NULL },
117 141
  { "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS, 1,			/* BA_NEXT_HOP */
118 142
    bgp_check_next_hop, NULL },
119 143
  { "med", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0,					/* BA_MULTI_EXIT_DISC */
......
122 146
    NULL, NULL },
123 147
  { "atomic_aggr", 0, BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,			/* BA_ATOMIC_AGGR */
124 148
    NULL, NULL },
125
  { "aggregator", 6, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,		/* BA_AGGREGATOR */
126
    NULL, NULL },
149
  { "aggregator", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,	/* BA_AGGREGATOR */
150
    bgp_check_aggregator, NULL },
127 151
  { "community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_INT_SET, 1,	/* BA_COMMUNITY */
128 152
    NULL, NULL },
129 153
  { NULL, },									/* BA_ORIGINATOR_ID */
......
135 159
    bgp_check_reach_nlri, NULL },
136 160
  { "mp_unreach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1,			/* BA_MP_UNREACH_NLRI */
137 161
    bgp_check_unreach_nlri, NULL },
162
  { NULL, },									/* BA_EXTENDED_COMM */
163
  { "as4_path", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,		/* BA_AS4_PATH */
164
    bgp_check_as4_path, NULL },
165
  { "as4_aggregator", 8, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,	/* BA_AS4_PATH */
166
    NULL, NULL }
138 167
};
139 168

  
169
/* BA_AS4_PATH is type EAF_TYPE_OPAQUE and not type EAF_TYPE_AS_PATH because
170
 * EAF_TYPE_AS_PATH is supposed to have different format (2 or 4 B for each ASN)
171
 * depending on bgp_as4_support variable.
172
 */
173

  
140 174
#define ATTR_KNOWN(code) ((code) < ARRAY_SIZE(bgp_attr_table) && bgp_attr_table[code].name)
141 175

  
142 176
static byte *
......
170 204
  return bgp_set_attr(a->attrs, pool, attr, val);
171 205
}
172 206

  
207
static int
208
bgp_encode_attr_hdr(byte *dst, unsigned int flags, unsigned code, int len)
209
{
210
  int wlen;
211

  
212
  DBG("\tAttribute %02x (%d bytes, flags %02x)\n", code, len, flags);
213

  
214
  if (len < 256)
215
    {
216
      *dst++ = flags;
217
      *dst++ = code;
218
      *dst++ = len;
219
      wlen = 3;
220
    }
221
  else
222
    {
223
      *dst++ = flags | BAF_EXT_LEN;
224
      *dst++ = code;
225
      put_u16(dst, len);
226
      wlen = 4;
227
    }
228

  
229
  return wlen;
230
}
231

  
232
static void
233
aggregator_convert_to_old(struct adata *aggr, byte *dst, int *new_used)
234
{
235
  byte *src = aggr->data;
236
  *new_used = 0;
237

  
238
  u32 as = get_u32(src);
239
  if (as > 0xFFFF) 
240
    {
241
      as = AS_TRANS;
242
      *new_used = 1;
243
    }
244
  put_u16(dst, as);
245

  
246
  /* Copy IPv4 address */
247
  memcpy(dst + 2, src + 4, 4);
248
}
249

  
250
static void
251
aggregator_convert_to_new(struct adata *aggr, byte *dst)
252
{
253
  byte *src = aggr->data;
254

  
255
  u32 as   = get_u16(src);
256
  put_u32(dst, as);
257

  
258
  /* Copy IPv4 address */
259
  memcpy(dst + 4, src + 2, 4);
260
}
261

  
262
static int
263
bgp_get_attr_len(eattr *a)
264
{
265
  int len;
266
  if (ATTR_KNOWN(EA_ID(a->id)))
267
    {
268
      int code = EA_ID(a->id);
269
      struct attr_desc *desc = &bgp_attr_table[code];
270
      len = desc->expected_length;
271
      if (len < 0)
272
	{
273
	  ASSERT(!(a->type & EAF_EMBEDDED));
274
	  len = a->u.ptr->length;
275
	}
276
    }
277
  else
278
    {
279
      ASSERT((a->type & EAF_TYPE_MASK) == EAF_TYPE_OPAQUE);
280
      len = a->u.ptr->length;
281
    }
282
  
283
  return len;
284
}
285

  
286
#define ADVANCE(w, r, l) do { r -= l; w += l; } while (0)
287

  
173 288
/**
174 289
 * bgp_encode_attrs - encode BGP attributes
290
 * @p: BGP instance
175 291
 * @w: buffer
176 292
 * @attrs: a list of extended attributes
177 293
 * @remains: remaining space in the buffer
......
182 298
 * Result: Length of the attribute block generated.
183 299
 */
184 300
unsigned int
185
bgp_encode_attrs(byte *w, ea_list *attrs, int remains)
301
bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
186 302
{
187 303
  unsigned int i, code, flags;
188 304
  byte *start = w;
189
  int len;
305
  int len, rv;
190 306

  
191 307
  for(i=0; i<attrs->count; i++)
192 308
    {
......
198 314
      if (code == BA_NEXT_HOP)
199 315
	continue;
200 316
#endif
201
      flags = a->flags & (BAF_OPTIONAL | BAF_TRANSITIVE | BAF_PARTIAL);
202
      if (ATTR_KNOWN(code))
203
	{
204
	  struct attr_desc *desc = &bgp_attr_table[code];
205
	  len = desc->expected_length;
206
	  if (len < 0)
207
	    {
208
	      ASSERT(!(a->type & EAF_EMBEDDED));
209
	      len = a->u.ptr->length;
210
	    }
211
	}
212
      else
317

  
318
      /* When AS4-aware BGP speaker is talking to non-AS4-aware BGP speaker,
319
       * we have to convert our 4B AS_PATH to 2B AS_PATH and send our AS_PATH 
320
       * as optional AS4_PATH attribute.
321
       */
322
      if ((code == BA_AS_PATH) && bgp_as4_support && (! p->as4_support))
213 323
	{
214
	  ASSERT((a->type & EAF_TYPE_MASK) == EAF_TYPE_OPAQUE);
215 324
	  len = a->u.ptr->length;
325

  
326
	  if (remains < (len + 4))
327
	    goto err_no_buffer;
328

  
329
	  /* Using temporary buffer because don't know a length of created attr
330
	   * and therefore a length of a header. Perhaps i should better always
331
	   * use BAF_EXT_LEN. */
332
	  
333
	  byte buf[len];
334
	  int new_used;
335
	  int nl = as_path_convert_to_old(a->u.ptr, buf, &new_used);
336

  
337
	  rv = bgp_encode_attr_hdr(w, BAF_TRANSITIVE, BA_AS_PATH, nl);
338
	  ADVANCE(w, remains, rv);
339
	  memcpy(w, buf, nl);
340
	  ADVANCE(w, remains, nl);
341

  
342
	  if (! new_used)
343
	    continue;
344

  
345
	  if (remains < (len + 4))
346
	    goto err_no_buffer;
347

  
348
	  /* We should discard AS_CONFED_SEQUENCE or AS_CONFED_SET path segments 
349
	   * here but we don't support confederations and such paths we already
350
	   * discarded in bgp_check_as_path().
351
	   */
352

  
353
	  rv = bgp_encode_attr_hdr(w, BAF_OPTIONAL | BAF_TRANSITIVE, BA_AS4_PATH, len);
354
	  ADVANCE(w, remains, rv);
355
	  memcpy(w, a->u.ptr->data, len);
356
	  ADVANCE(w, remains, len);
357

  
358
	  continue;
216 359
	}
217
      DBG("\tAttribute %02x (type %02x, %d bytes, flags %02x)\n", code, a->type, len, flags);
218
      if (remains < len + 4)
219
	{
220
	  log(L_ERR "BGP: attribute list too long, ignoring the remaining attributes");
221
	  break;
222
	}
223
      if (len < 256)
224
	{
225
	  *w++ = flags;
226
	  *w++ = code;
227
	  *w++ = len;
228
	  remains -= 3;
229
	}
230
      else
360

  
361
      /* The same issue with AGGREGATOR attribute */
362
      if ((code == BA_AGGREGATOR) && bgp_as4_support && (! p->as4_support))
231 363
	{
232
	  *w++ = flags | BAF_EXT_LEN;
233
	  *w++ = code;
234
	  put_u16(w, len);
235
	  w += 2;
236
	  remains -= 4;
364
	  int new_used;
365

  
366
	  len = 6;
367
	  if (remains < (len + 3))
368
	    goto err_no_buffer;
369

  
370
	  rv = bgp_encode_attr_hdr(w, BAF_OPTIONAL | BAF_TRANSITIVE, BA_AGGREGATOR, len);
371
	  ADVANCE(w, remains, rv);
372
	  aggregator_convert_to_old(a->u.ptr, w, &new_used);
373
	  ADVANCE(w, remains, len);
374

  
375
	  if (! new_used)
376
	    continue;
377

  
378
	  len = 8;
379
	  if (remains < (len + 3))
380
	    goto err_no_buffer;
381

  
382
	  rv = bgp_encode_attr_hdr(w, BAF_OPTIONAL | BAF_TRANSITIVE, BA_AS4_AGGREGATOR, len);
383
	  ADVANCE(w, remains, rv);
384
	  memcpy(w, a->u.ptr->data, len);
385
	  ADVANCE(w, remains, len);
386

  
387
	  continue;
237 388
	}
389

  
390
      /* Standard path continues here ... */
391

  
392
      flags = a->flags & (BAF_OPTIONAL | BAF_TRANSITIVE | BAF_PARTIAL);
393
      len = bgp_get_attr_len(a);
394

  
395
      if (remains < len + 4)
396
	goto err_no_buffer;
397

  
398
      rv = bgp_encode_attr_hdr(w, flags, code, len);
399
      ADVANCE(w, remains, rv);
400

  
238 401
      switch (a->type & EAF_TYPE_MASK)
239 402
	{
240 403
	case EAF_TYPE_INT:
......
266 429
	default:
267 430
	  bug("bgp_encode_attrs: unknown attribute type %02x", a->type);
268 431
	}
269
      remains -= len;
270
      w += len;
432
      ADVANCE(w, remains, len);
271 433
    }
272 434
  return w - start;
435

  
436
 err_no_buffer:
437
  log(L_ERR "BGP: attribute list too long, ignoring the remaining attributes");
438
  return w - start;
273 439
}
274 440

  
275 441
static void
......
566 732
    bgp_set_attr(ea->attrs+1, pool, BA_AS_PATH, 0);
567 733
  else
568 734
    {
569
      z = bgp_set_attr(ea->attrs+1, pool, BA_AS_PATH, 4);
735
      z = bgp_set_attr(ea->attrs+1, pool, BA_AS_PATH, bgp_as4_support ? 6 : 4);
570 736
      z[0] = AS_PATH_SEQUENCE;
571 737
      z[1] = 1;				/* 1 AS */
572
      put_u16(z+2, p->local_as);
738

  
739
      if (bgp_as4_support)
740
	put_u32(z+2, p->local_as);
741
      else
742
	put_u16(z+2, p->local_as);
573 743
    }
574 744

  
575 745
  z = bgp_set_attr(ea->attrs+2, pool, BA_NEXT_HOP, sizeof(ip_addr));
......
670 840
    {
671 841
      x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
672 842
      y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
673
      n = x ? as_path_getlen(x->u.ptr) : 100000;
674
      o = y ? as_path_getlen(y->u.ptr) : 100000;
843
      n = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN;
844
      o = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN;
675 845
      if (n < o)
676 846
	return 1;
677 847
      if (n > o)
......
712 882
static int
713 883
bgp_path_loopy(struct bgp_proto *p, eattr *a)
714 884
{
715
  byte *path = a->u.ptr->data;
716
  int len = a->u.ptr->length;
717
  int i, n;
885
  return as_path_is_member(a->u.ptr, p->local_as);
886
}
887

  
888

  
889
static struct adata *
890
bgp_aggregator_convert_to_new(struct adata *old, struct linpool *pool)
891
{
892
  struct adata *newa = lp_alloc(pool, sizeof(struct adata) + 8);
893
  newa->length = 8;
894
  aggregator_convert_to_new(old, newa->data);
895
  return newa;
896
}
897

  
898

  
899
/* Take last req_as ASNs from path old2 (in 2B format), convert to 4B format
900
 * and append path old4 (in 4B format).
901
 */
902
static struct adata *
903
bgp_merge_as_paths(struct adata *old2, struct adata *old4, int req_as, struct linpool *pool)
904
{
905
  byte buf[old2->length * 2];
906

  
907
  int ol = as_path_convert_to_new(old2, buf, req_as);
908
  int nl = ol + (old4 ? old4->length : 0);
718 909

  
719
  while (len > 0)
910
  struct adata *newa = lp_alloc(pool, sizeof(struct adata) + nl);
911
  newa->length = nl;
912
  memcpy(newa->data, buf, ol);
913
  if (old4) memcpy(newa->data + ol, old4->data, old4->length);
914

  
915
  return newa;
916
}
917

  
918

  
919
/* Reconstruct 4B AS_PATH and AGGREGATOR according to RFC4893 4.2.3 */
920
static void
921
bgp_reconstruct_4b_atts(struct bgp_proto *p, rta *a, struct linpool *pool)
922
{
923
  eattr *p2 =ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
924
  eattr *p4 =ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_AS4_PATH));
925
  eattr *a2 =ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_AGGREGATOR));
926
  eattr *a4 =ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_AS4_AGGREGATOR));
927

  
928
  if (a2)
720 929
    {
721
      n = path[1];
722
      len -= 2 + 2*n;
723
      path += 2;
724
      for(i=0; i<n; i++)
930
      u32 a2_as = get_u16(a2->u.ptr->data);
931

  
932
      if (a4)
725 933
	{
726
	  if (get_u16(path) == p->local_as)
727
	    return 1;
728
	  path += 2;
934
	  if (a2_as != AS_TRANS)
935
	    {
936
	      /* Routes were aggregated by old router and therefore AS4_PATH
937
	       * and AS4_AGGREGATOR is invalid
938
	       *
939
	       * Convert AS_PATH and AGGREGATOR to 4B format and finish.
940
	       */
941

  
942
	      a2->u.ptr = bgp_aggregator_convert_to_new(a2->u.ptr, pool);
943
	      p2->u.ptr = bgp_merge_as_paths(p2->u.ptr, NULL, AS_PATH_MAXLEN, pool);
944

  
945
	      return;
946
	    }
947
	  else
948
	    {
949
	      /* Common case, use AS4_AGGREGATOR attribute */
950
	      a2->u.ptr = a4->u.ptr;
951
	    }
952
	}
953
      else
954
	{
955
	  /* Common case, use old AGGREGATOR attribute */
956
	  a2->u.ptr = bgp_aggregator_convert_to_new(a2->u.ptr, pool);
957

  
958
	  if (a2_as == AS_TRANS)
959
	    log(L_WARN "BGP: AGGREGATOR attribute contain AS_TRANS, but AS4_AGGREGATOR is missing");
729 960
	}
730 961
    }
731
  return 0;
962
  else
963
    if (a4)
964
      log(L_WARN "BGP: AS4_AGGREGATOR attribute received, but AGGREGATOR attribute is missing");
965

  
966
  int p2_len = as_path_getlen(p2->u.ptr);
967
  int p4_len = p4 ? as_path_getlen(p4->u.ptr) : AS_PATH_MAXLEN;
968

  
969
  if (p2_len < p4_len)
970
    p2->u.ptr = bgp_merge_as_paths(p2->u.ptr, NULL, AS_PATH_MAXLEN, pool);
971
  else
972
    p2->u.ptr = bgp_merge_as_paths(p2->u.ptr, p4->u.ptr, p2_len - p4_len, pool);
973

  
974
}
975

  
976
static void
977
bgp_remove_as4_attrs(struct bgp_proto *p, rta *a)
978
{
979
  unsigned id1 = EA_CODE(EAP_BGP, BA_AS4_PATH);
980
  unsigned id2 = EA_CODE(EAP_BGP, BA_AS4_AGGREGATOR);
981
  ea_list **el = &(a->eattrs);
982

  
983
  /* We know that ea_lists constructed in bgp_decode_attrs have one attribute per ea_list struct */
984
  while (*el != NULL)
985
    {
986
      unsigned fid = (*el)->attrs[0].id;
987

  
988
      if ((fid == id1) || (fid == id2))
989
	{
990
	  *el = (*el)->next;
991
	  if (p->as4_support)
992
	    log(L_WARN "BGP: Unexpected AS4_* attributes received");
993
	}
994
      else
995
	el = &((*el)->next);
996
    }
732 997
}
733 998

  
734 999
/**
......
883 1148
	    }
884 1149
	}
885 1150
    }
1151
  
1152
  /* When receiving attributes from non-AS4-aware BGP speaker,
1153
   * we have to reconstruct 4B AS_PATH and AGGREGATOR attributes
1154
   */
1155
  if (bgp_as4_support && (! bgp->as4_support))
1156
    bgp_reconstruct_4b_atts(bgp, a, pool);
1157

  
1158
  if (bgp_as4_support)
1159
    bgp_remove_as4_attrs(bgp, a);
886 1160

  
887 1161
  /* If the AS path attribute contains our AS, reject the routes */
888 1162
  e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
......
945 1219
{
946 1220
  eattr *p = ea_find(attrs, EA_CODE(EAP_BGP, BA_AS_PATH));
947 1221
  eattr *o = ea_find(attrs, EA_CODE(EAP_BGP, BA_ORIGIN));
948
  int origas;
1222
  u32 origas;
949 1223

  
950 1224
  buf += bsprintf(buf, " (%d) [", e->pref);
951
  if (p && (origas = as_path_get_first(p->u.ptr)) >= 0)
952
    buf += bsprintf(buf, "AS%d", origas);
1225
  if (p && as_path_get_first(p->u.ptr, &origas))
1226
    buf += bsprintf(buf, "AS%u", origas);
953 1227
  if (o)
954 1228
    buf += bsprintf(buf, "%c", "ie?"[o->u.data]);
955 1229
  strcpy(buf, "]");

Also available in: Unified diff