Revision 42a0c054

View differences:

aclocal.m4
6 6
AC_CHECK_SIZEOF(short int, 0)
7 7
AC_CHECK_SIZEOF(int, 0)
8 8
AC_CHECK_SIZEOF(long int, 0)
9
for size in 1 2 4 ; do
9
AC_CHECK_SIZEOF(long long int, 0)
10
for size in 1 2 4 8; do
10 11
	bits=`expr $size "*" 8`
11 12
	AC_MSG_CHECKING([for $bits-bit type])
12 13
	if test $ac_cv_sizeof_int = $size ; then
......
17 18
		res="short int"
18 19
	elif test $ac_cv_sizeof_long_int = $size ; then
19 20
		res="long int"
21
	elif test $ac_cv_sizeof_long_long_int = $size ; then
22
		res="long long int"
20 23
	else
21 24
		AC_MSG_RESULT([not found])
22 25
		AC_MSG_ERROR([Cannot find $bits-bit integer type.])
filter/config.Y
75 75
  return lst;
76 76
}
77 77

  
78
#define EC_ALL 0xFFFFFFFF
79

  
80
static struct f_tree *
81
f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
82
{
83
  u64 fm, to;
84

  
85
  if (ipv4_used || (key >= 0x10000)) {
86
    check_u16(vf);
87
    if (vt == EC_ALL)
88
      vt = 0xFFFF;
89
    else
90
      check_u16(vt);
91
  }
92

  
93
  if (kind == EC_GENERIC) {
94
    fm = ec_generic(key, vf);
95
    to = ec_generic(key, vt);
96
  }
97
  else if (ipv4_used) {
98
    fm = ec_ip4(kind, key, vf);
99
    to = ec_ip4(kind, key, vt);
100
  }
101
  else if (key < 0x10000) {
102
    fm = ec_as2(kind, key, vf);
103
    to = ec_as2(kind, key, vt);
104
  }
105
  else {
106
    fm = ec_as4(kind, key, vf);
107
    to = ec_as4(kind, key, vt);
108
  }
109

  
110
  struct f_tree *t = f_new_tree();
111
  t->right = t;
112
  t->from.type = t->to.type = T_EC;
113
  t->from.val.ec = fm;
114
  t->to.val.ec = to;
115
  return t;
116
}
117

  
118
static inline struct f_inst *
119
f_generate_empty(struct f_inst *dyn)
120
{ 
121
  struct f_inst *e = f_new_inst();
122
  e->code = 'E';
123

  
124
  switch (dyn->aux & EAF_TYPE_MASK) {
125
    case EAF_TYPE_AS_PATH:
126
      e->aux = T_PATH;
127
      break;
128
    case EAF_TYPE_INT_SET:
129
      e->aux = T_CLIST;
130
      break;
131
    case EAF_TYPE_EC_SET:
132
      e->aux = T_ECLIST;
133
      break;
134
    default:
135
      cf_error("Can't empty that attribute");
136
  }
137

  
138
  dyn->code = P('e','S');
139
  dyn->a1.p = e;
140
  return dyn;
141
}
142

  
143

  
144
static inline struct f_inst *
145
f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
146
{
147
  struct f_inst *rv;
148

  
149
  if ((t1->code == 'c') && (t2->code == 'c')) {
150
    if ((t1->aux != T_INT) || (t2->aux != T_INT))
151
      cf_error( "Can't operate with value of non-integer type in pair constructor");
152

  
153
    check_u16(t1->a2.i);
154
    check_u16(t2->a2.i);
155

  
156
    rv = f_new_inst();
157
    rv->code = 'c';
158
    rv->aux = T_PAIR;
159
    rv->a2.i = pair(t1->a2.i, t2->a2.i);
160
  }
161
  else {
162
    rv = f_new_inst();
163
    rv->code = P('m', 'p');
164
    rv->a1.p = t1;
165
    rv->a2.p = t2;
166
  }
167

  
168
  return rv;
169
}
170

  
171
static inline struct f_inst *
172
f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
173
{
174
  struct f_inst *rv;
175
  int c1 = 0, c2 = 0, ipv4_used = 0;
176
  u32 key = 0, val2 = 0;
177

  
178
  if (tk->code == 'c') {
179
    c1 = 1;
180

  
181
    if (tk->aux == T_INT) {
182
      ipv4_used = 0; key = tk->a2.i;
183
    }
184
    else if (tk->aux == T_QUAD) {
185
      ipv4_used = 1; key = tk->a2.i;
186
    }
187
    else
188
      cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
189
  }
190

  
191
#ifndef IPV6
192
  /* IP->Quad implicit conversion */
193
  else if (tk->code == 'C') {
194
    c1 = 1;
195
    struct f_val *val = tk->a1.p;
196
    if (val->type == T_IP) {
197
      ipv4_used = 1; key = ipa_to_u32(val->val.px.ip);
198
    }
199
    else
200
      cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
201
  }
202
#endif
203

  
204
  if (tv->code == 'c') {
205
    if (tv->aux != T_INT)
206
      cf_error("Can't operate with value of non-integer type in EC constructor");
207
    c2 = 1;
208
    val2 = tv->a2.i;
209
  }
210

  
211
  if (c1 && c2) {
212
    u64 ec;
213
  
214
    if (kind == EC_GENERIC) {
215
      ec = ec_generic(key, val2);
216
    }
217
    else if (ipv4_used) {
218
      check_u16(val2);
219
      ec = ec_ip4(kind, key, val2);
220
    }
221
    else if (key < 0x10000) {
222
      ec = ec_as2(kind, key, val2);
223
    }
224
    else {
225
      check_u16(val2);
226
      ec = ec_as4(kind, key, val2);
227
    }
228

  
229
    NEW_F_VAL;
230
    rv = f_new_inst();
231
    rv->code = 'C';
232
    rv->a1.p = val;    
233
    val->type = T_EC;
234
    val->val.ec = ec;
235
  }
236
  else {
237
    rv = f_new_inst();
238
    rv->code = P('m','c');
239
    rv->aux = kind;
240
    rv->a1.p = tk;
241
    rv->a2.p = tv;
242
  }
243

  
244
  return rv;
245
};
246

  
247

  
248

  
78 249
CF_DECLS
79 250

  
80 251
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
81 252
	ACCEPT, REJECT, ERROR, QUITBIRD,
82
	INT, BOOL, IP, PREFIX, PAIR, QUAD, SET, STRING, BGPMASK, BGPPATH, CLIST,
253
	INT, BOOL, IP, PREFIX, PAIR, QUAD, EC,
254
	SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST,
83 255
	IF, THEN, ELSE, CASE,
84
	TRUE, FALSE,
256
	TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
85 257
	FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, PREFERENCE,
86 258
	LEN,
87 259
	DEFINED,
......
93 265
%nonassoc THEN
94 266
%nonassoc ELSE
95 267

  
96
%type <x> term block cmds cmds_int cmd function_body constant print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol dpair bgp_path_expr
268
%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr
97 269
%type <f> filter filter_body where_filter
98
%type <i> type break_command pair_expr
99
%type <i32> pair_atom
100
%type <e> pair_item set_item switch_item set_items switch_items switch_body
270
%type <i> type break_command pair_expr ec_kind
271
%type <i32> pair_atom ec_expr
272
%type <e> pair_item ec_item set_item switch_item set_items switch_items switch_body
101 273
%type <trie> fprefix_set
102 274
%type <v> set_atom switch_atom fprefix fprefix_s fipa
103 275
%type <s> decls declsn one_decl function_params 
......
128 300
 | PREFIX { $$ = T_PREFIX; }
129 301
 | PAIR { $$ = T_PAIR; }
130 302
 | QUAD { $$ = T_QUAD; }
303
 | EC { $$ = T_EC; }
131 304
 | STRING { $$ = T_STRING; }
132 305
 | BGPMASK { $$ = T_PATH_MASK; }
133 306
 | BGPPATH { $$ = T_PATH; }
134 307
 | CLIST { $$ = T_CLIST; }
308
 | ECLIST { $$ = T_ECLIST; }
135 309
 | type SET { 
136 310
	switch ($1) {
137 311
	  case T_INT:
138 312
	  case T_PAIR:
139 313
	  case T_QUAD:
314
	  case T_EC:
140 315
	  case T_IP:
141 316
	       $$ = T_SET;
142 317
	       break;
......
324 499
   }
325 500
 ;
326 501

  
502
ec_expr:
503
   term { $$ = f_eval_int($1); }
504

  
505
ec_kind:
506
   RT { $$ = EC_RT; }
507
 | RO { $$ = EC_RO; }
508
 | UNKNOWN NUM { $$ = $2; }
509
 | GENERIC { $$ = EC_GENERIC; }
510
 ;
511

  
512
ec_item:
513
   '(' ec_kind ',' ec_expr ',' ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
514
 | '(' ec_kind ',' ec_expr ',' ec_expr DDOT ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
515
 | '(' ec_kind ',' ec_expr ',' '*' ')' {  $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
516
 ;
517

  
327 518
set_item:
328 519
   pair_item
520
 | ec_item
329 521
 | set_atom { $$ = f_new_item($1, $1); }
330 522
 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
331 523
 ;
332 524

  
333 525
switch_item:
334 526
   pair_item
527
 | ec_item
335 528
 | switch_atom { $$ = f_new_item($1, $1); }
336 529
 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
337 530
 ;
......
411 604
 | 		      { $$ = NULL; }
412 605
 ;
413 606

  
414
dpair:
415
   '(' term ',' term ')' {
416
        if (($2->code == 'c') && ($4->code == 'c'))
417
          { 
418
            if (($2->aux != T_INT) || ($4->aux != T_INT))
419
              cf_error( "Can't operate with value of non-integer type in pair constructor" );
420
	    check_u16($2->a2.i); check_u16($4->a2.i);
421
            $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PAIR;  $$->a2.i = pair($2->a2.i, $4->a2.i);
422
          }
423
	else
424
	  { $$ = f_new_inst(); $$->code = P('m', 'p'); $$->a1.p = $2; $$->a2.p = $4; }
425
    }
426
 ;
427

  
428 607
constant:
429 608
   NUM    { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT;  $$->a2.i = $1; }
430 609
 | TRUE   { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1;  }
......
439 618
 | bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
440 619
 ;
441 620

  
621
constructor:
622
   '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); };
623
 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); };
624
 ;
625

  
442 626

  
443 627
/*
444 628
 *  Maybe there are no dynamic attributes defined by protocols.
......
490 674
       case SYM_VARIABLE | T_INT:
491 675
       case SYM_VARIABLE | T_PAIR:
492 676
       case SYM_VARIABLE | T_QUAD:
677
       case SYM_VARIABLE | T_EC:
493 678
       case SYM_VARIABLE | T_STRING:
494 679
       case SYM_VARIABLE | T_IP:
495 680
       case SYM_VARIABLE | T_PREFIX:
......
498 683
       case SYM_VARIABLE | T_PATH:
499 684
       case SYM_VARIABLE | T_PATH_MASK:
500 685
       case SYM_VARIABLE | T_CLIST:
686
       case SYM_VARIABLE | T_ECLIST:
501 687
	 $$->code = 'V';
502 688
	 $$->a1.p = $1->def;
503 689
	 $$->a2.p = $1->name;
......
539 725

  
540 726
 | symbol   { $$ = $1; }
541 727
 | constant { $$ = $1; }
542
 | dpair    { $$ = $1; }
728
 | constructor { $$ = $1; }
543 729

  
544 730
 | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
545 731

  
......
563 749

  
564 750
 | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
565 751
 | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
752
 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; }
566 753
 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; } 
567 754
 | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } 
568 755
 | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
......
702 889
   }
703 890

  
704 891

  
705
 | rtadot dynamic_attr '.' EMPTY ';' 
706
  { struct f_inst *i = f_new_inst(); i->code = 'E'; i->aux = T_CLIST; $$ = $2; $$->code = P('e','S'); $$->a1.p = i; }
892
 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
707 893
 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
708
 | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); } 
709
 | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); } 
710
 | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); } 
894
 | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
895
 | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
896
 | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
711 897
 ;
712 898

  
713 899
CF_END
filter/filter.c
51 51
#define CMP_ERROR 999
52 52

  
53 53
static struct adata *
54
adata_empty(struct linpool *pool)
54
adata_empty(struct linpool *pool, int l)
55 55
{
56
  struct adata *res = lp_alloc(pool, sizeof(struct adata));
57
  res->length = 0;
56
  struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
57
  res->length = l;
58 58
  return res;
59 59
}
60 60

  
......
126 126
  else return 1;
127 127
}
128 128

  
129
static inline int u64_cmp(u64 i1, u64 i2)
130
{
131
  if (i1 == i2) return 0;
132
  if (i1 < i2) return -1;
133
  else return 1;
134
}
135

  
129 136
/**
130 137
 * val_compare - compare two values
131 138
 * @v1: first value
......
167 174
  case T_PAIR:
168 175
  case T_QUAD:
169 176
    return uint_cmp(v1.val.i, v2.val.i);
177
  case T_EC:
178
    return u64_cmp(v1.val.ec, v2.val.ec);
170 179
  case T_IP:
171 180
    return ipa_compare(v1.val.px.ip, v2.val.px.ip);
172 181
  case T_PREFIX:
......
226 235
  if ((v1.type == T_IP) && (v2.type == T_CLIST))
227 236
    return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip));
228 237
#endif
238
  if ((v1.type == T_EC) && (v2.type == T_ECLIST))
239
    return ec_set_contains(v2.val.ad, v1.val.ec);
240

  
229 241
  if ((v1.type == T_STRING) && (v2.type == T_STRING))
230 242
    return patmatch(v2.val.s, v1.val.s);
231 243

  
......
258 270
  }
259 271
}
260 272

  
273
static inline int
274
eclist_set_type(struct f_tree *set)
275
{ return set->from.type == T_EC; }
276

  
261 277
static int
262 278
clist_match_set(struct adata *clist, struct f_tree *set)
263 279
{
......
270 286

  
271 287
  u32 *l = (u32 *) clist->data;
272 288
  u32 *end = l + clist->length/4;
289

  
273 290
  while (l < end) {
274 291
    v.val.i = *l++;
275 292
    if (find_tree(set, v))
......
278 295
  return 0;
279 296
}
280 297

  
298
static int
299
eclist_match_set(struct adata *list, struct f_tree *set)
300
{
301
  if (!list)
302
    return 0;
303

  
304
  if (!eclist_set_type(set))
305
    return CMP_ERROR;
306

  
307
  struct f_val v;
308
  u32 *l = int_set_get_data(list);
309
  int len = int_set_get_size(list);
310
  int i;
311

  
312
  v.type = T_EC;
313
  for (i = 0; i < len; i += 2) {
314
    v.val.ec = ec_get(l, i);
315
    if (find_tree(set, v))
316
      return 1;
317
  }
318

  
319
  return 0;
320
}
321

  
281 322
static struct adata *
282 323
clist_filter(struct linpool *pool, struct adata *clist, struct f_tree *set, int pos)
283 324
{
......
302 343
  if (nl == clist->length)
303 344
    return clist;
304 345

  
305
  struct adata *res = lp_alloc(pool, sizeof(struct adata) + nl);
306
  res->length = nl;
346
  struct adata *res = adata_empty(pool, nl);
347
  memcpy(res->data, tmp, nl);
348
  return res;
349
}
350

  
351
static struct adata *
352
eclist_filter(struct linpool *pool, struct adata *list, struct f_tree *set, int pos)
353
{
354
  if (!list)
355
    return NULL;
356

  
357
  struct f_val v;
358

  
359
  int len = int_set_get_size(list);
360
  u32 *l = int_set_get_data(list);
361
  u32 tmp[len];
362
  u32 *k = tmp;
363
  int i;
364

  
365
  v.type = T_EC;
366
  for (i = 0; i < len; i += 2) {
367
    v.val.ec = ec_get(l, i);
368
    if (pos == !!find_tree(set, v)) {	/* pos && find_tree || !pos && !find_tree */
369
      *k++ = l[i];
370
      *k++ = l[i+1];
371
    }
372
  }
373

  
374
  int nl = (k - tmp) * 4;
375
  if (nl == list->length)
376
    return list;
377

  
378
  struct adata *res = adata_empty(pool, nl);
307 379
  memcpy(res->data, tmp, nl);
308 380
  return res;
309 381
}
......
332 404
  if ((v1.type == T_CLIST) && (v2.type == T_SET))
333 405
    return clist_match_set(v1.val.ad, v2.val.t);
334 406

  
407
  if ((v1.type == T_ECLIST) && (v2.type == T_SET))
408
    return eclist_match_set(v1.val.ad, v2.val.t);
409

  
335 410
  if (v2.type == T_SET)
336 411
    switch (v1.type) {
337 412
    case T_ENUM:
......
339 414
    case T_PAIR:
340 415
    case T_QUAD:
341 416
    case T_IP:
417
    case T_EC:
342 418
      {
343 419
	struct f_tree *n;
344 420
	n = find_tree(v2.val.t, v1);
......
397 473
  case T_PREFIX: logn("%I/%d", v.val.px.ip, v.val.px.len); return;
398 474
  case T_PAIR: logn("(%d,%d)", v.val.i >> 16, v.val.i & 0xffff); return;
399 475
  case T_QUAD: logn("%R", v.val.i); return;
476
  case T_EC: ec_format(buf2, v.val.ec); logn("%s", buf2); return;
400 477
  case T_PREFIX_SET: trie_print(v.val.ti); return;
401 478
  case T_SET: tree_print(v.val.t); return;
402 479
  case T_ENUM: logn("(enum %x)%d", v.type, v.val.i); return;
403 480
  case T_PATH: as_path_format(v.val.ad, buf2, 1000); logn("(path %s)", buf2); return;
404 481
  case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); logn("(clist %s)", buf2); return;
482
  case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); logn("(eclist %s)", buf2); return;
405 483
  case T_PATH_MASK: pm_format(v.val.path_mask, buf2, 1000); logn("(pathmask%s)", buf2); return;
406 484
  default: logn( "[unknown type %x]", v.type ); return;
407 485
  }
......
541 619
    break;
542 620

  
543 621
  case P('m','p'):
544
    TWOARGS_C;
622
    TWOARGS;
545 623
    if ((v1.type != T_INT) || (v2.type != T_INT))
546 624
      runtime( "Can't operate with value of non-integer type in pair constructor" );
547 625
    u1 = v1.val.i;
......
552 630
    res.type = T_PAIR;
553 631
    break;
554 632

  
633
  case P('m','c'):
634
    {
635
      TWOARGS;
636

  
637
      int check, ipv4_used;
638
      u32 key, val;
639

  
640
      if (v1.type == T_INT) {
641
	ipv4_used = 0; key = v1.val.i;
642
      } 
643
      else if (v1.type == T_QUAD) {
644
	ipv4_used = 1; key = v1.val.i;
645
      }
646
#ifndef IPV6
647
      /* IP->Quad implicit conversion */
648
      else if (v1.type == T_IP) {
649
	ipv4_used = 1; key = ipa_to_u32(v1.val.px.ip);
650
      }
651
#endif
652
      else
653
	runtime("Can't operate with key of non-integer/IPv4 type in EC constructor");
654

  
655
      if (v2.type != T_INT)
656
	runtime("Can't operate with value of non-integer type in EC constructor");
657
      val = v2.val.i;
658

  
659
      res.type = T_EC;
660

  
661
      if (what->aux == EC_GENERIC) {
662
	check = 0; res.val.ec = ec_generic(key, val);
663
      }
664
      else if (ipv4_used) {
665
	check = 1; res.val.ec = ec_ip4(what->aux, key, val);
666
      }
667
      else if (key < 0x10000) {
668
	check = 0; res.val.ec = ec_as2(what->aux, key, val);
669
      }
670
      else {
671
	check = 1; res.val.ec = ec_as4(what->aux, key, val);
672
      }
673

  
674
      if (check && (val > 0xFFFF))
675
	runtime("Can't operate with value out of bounds in EC constructor");
676

  
677
      break;
678
    }
679

  
555 680
/* Relational operators */
556 681

  
557 682
#define COMPARE(x) \
......
723 848
	/* A special case: undefined int_set looks like empty int_set */
724 849
	if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) {
725 850
	  res.type = T_CLIST;
726
	  res.val.ad = adata_empty(f_pool);
851
	  res.val.ad = adata_empty(f_pool, 0);
852
	  break;
853
	}
854
	/* The same special case for ec_set */
855
	else if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
856
	  res.type = T_ECLIST;
857
	  res.val.ad = adata_empty(f_pool, 0);
727 858
	  break;
728 859
	}
860

  
729 861
	/* Undefined value */
730 862
	res.type = T_VOID;
731 863
	break;
......
757 889
	res.type = T_CLIST;
758 890
	res.val.ad = e->u.ptr;
759 891
	break;
892
      case EAF_TYPE_EC_SET:
893
	res.type = T_ECLIST;
894
	res.val.ad = e->u.ptr;
895
	break;
760 896
      case EAF_TYPE_UNDEF:
761 897
	res.type = T_VOID;
762 898
	break;
......
802 938
	break;
803 939
      case EAF_TYPE_INT_SET:
804 940
	if (v1.type != T_CLIST)
805
	  runtime( "Setting int set attribute to non-clist value" );
941
	  runtime( "Setting clist attribute to non-clist value" );
942
	l->attrs[0].u.ptr = v1.val.ad;
943
	break;
944
      case EAF_TYPE_EC_SET:
945
	if (v1.type != T_ECLIST)
946
	  runtime( "Setting eclist attribute to non-eclist value" );
806 947
	l->attrs[0].u.ptr = v1.val.ad;
807 948
	break;
808 949
      case EAF_TYPE_UNDEF:
......
926 1067

  
927 1068
  case 'E':	/* Create empty attribute */
928 1069
    res.type = what->aux;
929
    res.val.ad = adata_empty(f_pool);
1070
    res.val.ad = adata_empty(f_pool, 0);
930 1071
    break;
931 1072
  case P('A','p'):	/* Path prepend */
932 1073
    TWOARGS;
......
939 1080
    res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
940 1081
    break;
941 1082

  
942
  case P('C','a'):	/* Community list add or delete */
1083
  case P('C','a'):	/* (Extended) Community list add or delete */
943 1084
    TWOARGS;
944
    if (v1.type != T_CLIST)
945
      runtime("Can't add/delete to non-clist");
946

  
947
    struct f_val dummy;
948
    int arg_set = 0;
949
    i = 0;
1085
    if (v1.type == T_CLIST)
1086
    {
1087
      /* Community (or cluster) list */
1088
      struct f_val dummy;
1089
      int arg_set = 0;
1090
      i = 0;
950 1091

  
951
    if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
952
      i = v2.val.i;
1092
      if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
1093
	i = v2.val.i;
953 1094
#ifndef IPV6
954
    /* IP->Quad implicit conversion */
955
    else if (v2.type == T_IP)
956
      i = ipa_to_u32(v2.val.px.ip);
1095
      /* IP->Quad implicit conversion */
1096
      else if (v2.type == T_IP)
1097
	i = ipa_to_u32(v2.val.px.ip);
957 1098
#endif
958
    else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
959
      arg_set = 1;
960
    else
961
      runtime("Can't add/delete non-pair");
1099
      else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
1100
	arg_set = 1;
1101
      else
1102
	runtime("Can't add/delete non-pair");
1103

  
1104
      res.type = T_CLIST;
1105
      switch (what->aux)
1106
      {
1107
      case 'a':
1108
	if (arg_set)
1109
	  runtime("Can't add set");
1110
	res.val.ad = int_set_add(f_pool, v1.val.ad, i);
1111
	break;
1112
      
1113
      case 'd':
1114
	if (!arg_set)
1115
	  res.val.ad = int_set_del(f_pool, v1.val.ad, i);
1116
	else
1117
	  res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 0);
1118
	break;
962 1119

  
963
    res.type = T_CLIST;
964
    switch (what->aux)
1120
      case 'f':
1121
	if (!arg_set)
1122
	  runtime("Can't filter pair");
1123
	res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 1);
1124
	break;
1125

  
1126
      default:
1127
	bug("unknown Ca operation");
1128
      }
1129
    }
1130
    else if (v1.type == T_ECLIST)
965 1131
    {
966
    case 'a':
967
      if (arg_set)
968
	runtime("Can't add set");
969
      res.val.ad = int_set_add(f_pool, v1.val.ad, i);
970
      break;
1132
      /* Extended community list */
1133
      int arg_set = 0;
971 1134
      
972
    case 'd':
973
      if (!arg_set)
974
	res.val.ad = int_set_del(f_pool, v1.val.ad, i);
975
      else
976
	res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 0);
977
      break;
1135
      /* v2.val is either EC or EC-set */
1136
      if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
1137
	arg_set = 1;
1138
      else if (v2.type != T_EC)
1139
	runtime("Can't add/delete non-pair");
1140

  
1141
      res.type = T_ECLIST;
1142
      switch (what->aux)
1143
      {
1144
      case 'a':
1145
	if (arg_set)
1146
	  runtime("Can't add set");
1147
	res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec);
1148
	break;
1149
      
1150
      case 'd':
1151
	if (!arg_set)
1152
	  res.val.ad = ec_set_del(f_pool, v1.val.ad, v2.val.ec);
1153
	else
1154
	  res.val.ad = eclist_filter(f_pool, v1.val.ad, v2.val.t, 0);
1155
	break;
978 1156

  
979
    case 'f':
980
      if (!arg_set)
981
	runtime("Can't filter pair");
982
      res.val.ad = clist_filter(f_pool, v1.val.ad, v2.val.t, 1);
983
      break;
1157
      case 'f':
1158
	if (!arg_set)
1159
	  runtime("Can't filter ec");
1160
	res.val.ad = eclist_filter(f_pool, v1.val.ad, v2.val.t, 1);
1161
	break;
984 1162

  
985
    default:
986
      bug("unknown Ca operation");
1163
      default:
1164
	bug("unknown Ca operation");
1165
      }
987 1166
    }
1167
    else
1168
      runtime("Can't add/delete to non-(e)clist");
1169

  
988 1170
    break;
989 1171

  
990 1172
  default:
filter/filter.h
46 46
  int type;
47 47
  union {
48 48
    int i;
49
    u64 ec;
49 50
    /*    ip_addr ip; Folded into prefix */	
50 51
    struct f_prefix px;
51 52
    char *s;
......
152 153
#define T_PATH_MASK 0x23	/* mask for BGP path */
153 154
#define T_PATH 0x24		/* BGP path */
154 155
#define T_CLIST 0x25		/* Community list */
156
#define T_ECLIST 0x26		/* Extended community list */
157
#define T_EC 0x27		/* Extended community value, u64 */
155 158

  
156 159
#define T_RETURN 0x40
157 160
#define T_SET 0x80
filter/test.conf
11 11
define xyzzy = (120+10);
12 12
define '1a-a1' = (20+10);
13 13
define one = 1;
14
define ten = 10;
14 15

  
15 16
function onef(int a)
16 17
{
......
56 57
bgpmask pm2;
57 58
bgppath p2;
58 59
clist l;
60
eclist el;
59 61
{
60 62
	pm1 =  / 4 3 2 1 /;
61 63
	pm2 = [= 4 3 2 1 =];
......
118 120
	print "Community list (3,1) ", l;
119 121
	l = delete( l, [(*,(onef(5)))] );
120 122
	print "Community list empty ", l;
123

  
124
	el = -- empty --;
125
	el = add(el, (rt, 10, 20));
126
	el = add(el, (ro, 10.20.30.40, 100));
127
	el = add(el, (ro, 11.21.31.41.mask(16), 200));
128
	print "EC list (rt, 10, 20) (ro, 10.20.30.40, 100) (ro, 11.21.0.0, 200):";
129
	print el;
130
	el = delete(el, (rt, 10, 20));
131
	el = delete(el, (rt, 10, 30));
132
	el = add(el, (unknown 2, ten, 1));
133
	el = add(el, (unknown 5, ten, 1));
134
	el = add(el, (rt, ten, one+one));
135
	el = add(el, (rt, 10, 3));
136
	el = add(el, (rt, 10, 4));
137
	el = add(el, (rt, 10, 5));
138
	el = add(el, (generic, 0x2000a, 3*ten));
139
	el = delete(el, [(rt, 10, 2..ten)]);
140
	print "EC list (ro, 10.20.30.40, 100) (ro, 11.21.0.0, 200) (rt, 10, 1) (unknown 0x5, 10, 1) (rt, 10, 30):";
141
	print el;
142
	el = filter(el, [(rt, 10, *)]);
143
	print "EC list (rt, 10, 1) (rt, 10, 30): ", el;
144
	print "Testing EC list, true: ", (rt, 10, 1) ~ el, " ", el ~ [(rt, 10, ten..40)];
145
	print "Testing EC list, false: ", (rt, 10, 20) ~ el, " ", (ro, 10.20.30.40, 100) ~ el, " ", el ~ [(rt, 10, 35..40)], " ", el ~ [(ro, 10, *)];
121 146
}
122 147

  
123 148
function bla()
......
175 200
ip p;
176 201
pair pp;
177 202
quad qq;
203
ec cc;
178 204
int set is;
179 205
int set is1;
180 206
int set is2;
181 207
int set is3;
182 208
pair set ps;
209
ec set ecs;
183 210
prefix set pxs;
184 211
string s;
185 212
{
......
250 277
		", true: ", qq = 1.2.3.4, " ", qq ~ [1.2.3.4, 5.6.7.8],
251 278
		", false: ", qq = 4.3.2.1, " ", qq ~ [1.2.1.1, 1.2.3.5];
252 279

  
280
	cc = (rt, 12345, 200000);
281
	print "Testing EC: (rt, 12345, 200000) = ", cc;
282
	print "Testing EC: (ro, 100000, 20000) = ", (ro, 100000, 20000);
283
	print "Testing EC: (rt, 10.20.30.40, 20000) = ", (rt, 10.20.30.40, 20000);
284
	print "  true: ", cc = (rt, 12345, 200000), " ", cc < (rt, 12345, 200010),
285
		", false: ", cc = (rt, 12346, 200000), " ", cc = (ro, 12345, 200000), " ",  cc > (rt, 12345, 200010);
286

  
287
	ecs = [(rt, ten, (one+onef(0))*10), (ro, 100000, 100..200), (rt, 12345, *)];
288
	print "EC set: ", ecs;
289
	print "Testing EC set, true:  ",  (rt, 10, 20) ~ ecs, "  ", (ro, 100000, 100) ~ ecs, "  ", (ro, 100000, 200) ~ ecs,
290
		"  ", (rt, 12345, 0) ~ ecs, "  ", cc ~ ecs,  "  ", (rt, 12345, 4000000) ~ ecs;
291
	print "Testing EC set, false: ", (ro, 10, 20) ~ ecs, " ", (rt, 10, 21) ~ ecs, " ", (ro, 100000, 99) ~ ecs,
292
		" ", (ro, 12345, 10) ~ ecs, " ", (rt, 12346, 0) ~ ecs, " ", (ro, 0.1.134.160, 150) ~ ecs;
253 293

  
254 294
	s = "Hello";
255 295
	print "Testing string: ", s, " true: ", s ~ "Hell*", " false: ", s ~ "ell*";
nest/a-set.c
36 36
{
37 37
  u32 *z = (u32 *) set->data;
38 38
  byte *end = buf + size - 24;
39
  int from2 = MAX(from, 0);
39 40
  int to = set->length / 4;
40 41
  int i;
41 42

  
42
  for (i = MAX(from, 0); i < to; i++)
43
  for (i = from2; i < to; i++)
43 44
    {
44 45
      if (buf > end)
45 46
	{
......
50 51
	  return i;
51 52
	}
52 53

  
53
      if (i > from)
54
      if (i > from2)
54 55
	*buf++ = ' ';
55 56

  
56 57
      if (way)
......
63 64
}
64 65

  
65 66
int
67
ec_format(byte *buf, u64 ec)
68
{
69
  u32 type, key, val;
70
  char tbuf[16], *kind;
71

  
72
  type = ec >> 48;
73
  switch (type & 0xf0ff)
74
    {
75
    case EC_RT: kind = "rt"; break;
76
    case EC_RO: kind = "ro"; break;
77

  
78
    default:
79
      kind = tbuf;
80
      bsprintf(kind, "unknown 0x%x", type);
81
    }
82

  
83
  switch (ec >> 56)
84
    {
85
      /* RFC 4360 3.1.  Two-Octet AS Specific Extended Community */
86
    case 0x00:
87
    case 0x40:
88
      key = (ec >> 32) & 0xFFFF;
89
      val = ec;
90
      return bsprintf(buf, "(%s, %u, %u)", kind, key, val);
91

  
92
      /* RFC 4360 3.2.  IPv4 Address Specific Extended Community */
93
    case 0x01:
94
    case 0x41:
95
      key = ec >> 16;
96
      val = ec & 0xFFFF;
97
      return bsprintf(buf, "(%s, %R, %u)", kind, key, val);
98

  
99
      /* RFC 5668  4-Octet AS Specific BGP Extended Community */
100
    case 0x02:
101
    case 0x42:
102
      key = ec >> 16;
103
      val = ec & 0xFFFF;
104
      return bsprintf(buf, "(%s, %u, %u)", kind, key, val);
105

  
106
      /* Generic format for unknown kinds of extended communities */
107
    default:
108
      key = ec >> 32;
109
      val = ec;
110
      return bsprintf(buf, "(generic, 0x%x, 0x%x)", key, val);
111
    }
112

  
113
}
114

  
115
int
116
ec_set_format(struct adata *set, int from, byte *buf, unsigned int size)
117
{
118
  u32 *z = int_set_get_data(set);
119
  byte *end = buf + size - 24;
120
  int from2 = MAX(from, 0);
121
  int to = int_set_get_size(set);
122
  int i;
123

  
124
  for (i = from2; i < to; i += 2)
125
    {
126
      if (buf > end)
127
	{
128
	  if (from < 0)
129
	    strcpy(buf, " ...");
130
	  else
131
	    *buf = 0;
132
	  return i;
133
	}
134

  
135
      if (i > from2)
136
	*buf++ = ' ';
137

  
138
      buf += ec_format(buf, ec_get(z, i));
139
    }
140
  *buf = 0;
141
  return 0;
142
}
143

  
144
int
66 145
int_set_contains(struct adata *list, u32 val)
67 146
{
68 147
  if (!list)
69 148
    return 0;
70 149

  
71 150
  u32 *l = (u32 *) list->data;
72
  unsigned int i;
73
  for (i=0; i<list->length/4; i++)
151
  int len = int_set_get_size(list);
152
  int i;
153

  
154
  for (i = 0; i < len; i++)
74 155
    if (*l++ == val)
75 156
      return 1;
157

  
158
  return 0;
159
}
160

  
161
int
162
ec_set_contains(struct adata *list, u64 val)
163
{
164
  if (!list)
165
    return 0;
166

  
167
  u32 *l = int_set_get_data(list);
168
  int len = int_set_get_size(list);
169
  u32 eh = ec_hi(val);
170
  u32 el = ec_lo(val);
171
  int i;
172

  
173
  for (i=0; i < len; i += 2)
174
    if (l[i] == eh && l[i+1] == el)
175
      return 1;
176

  
76 177
  return 0;
77 178
}
78 179

  
......
86 187
    return list;
87 188

  
88 189
  len = list ? list->length : 0;
89
  res = lp_alloc(pool, len + sizeof(struct adata) + 4);
190
  res = lp_alloc(pool, sizeof(struct adata) + len + 4);
90 191
  res->length = len + 4;
91 192
  * (u32 *) res->data = val;
92 193
  if (list)
......
95 196
}
96 197

  
97 198
struct adata *
98
int_set_del(struct linpool *pool, struct adata *list, u32 val)
199
ec_set_add(struct linpool *pool, struct adata *list, u64 val)
99 200
{
100
  struct adata *res;
101
  u32 *l, *k;
102
  unsigned int i;
201
  if (ec_set_contains(list, val))
202
    return list;
203

  
204
  int olen = list ? list->length : 0;
205
  struct adata *res = lp_alloc(pool, sizeof(struct adata) + olen + 8);
206
  res->length = olen + 8;
207

  
208
  if (list)
209
    memcpy(res->data, list->data, list->length);
210

  
211
  u32 *l = (u32 *) (res->data + res->length - 8);
212
  l[0] = ec_hi(val);
213
  l[1] = ec_lo(val);
214

  
215
  return res;
216
}
217

  
103 218

  
219
struct adata *
220
int_set_del(struct linpool *pool, struct adata *list, u32 val)
221
{
104 222
  if (!int_set_contains(list, val))
105 223
    return list;
106 224

  
107
  res = lp_alloc(pool, list->length + sizeof(struct adata) - 4);
108
  res->length = list->length-4;
225
  struct adata *res;
226
  res = lp_alloc(pool, sizeof(struct adata) + list->length - 4);
227
  res->length = list->length - 4;
228

  
229
  u32 *l = int_set_get_data(list);
230
  u32 *k = int_set_get_data(res);
231
  int len = int_set_get_size(list);
232
  int i;
109 233

  
110
  l = (u32 *) list->data;
111
  k = (u32 *) res->data;
112
  for (i=0; i<list->length/4; i++)
234
  for (i = 0; i < len; i++)
113 235
    if (l[i] != val)
114 236
      *k++ = l[i];
115 237

  
116 238
  return res;
117 239
}
240

  
241
struct adata *
242
ec_set_del(struct linpool *pool, struct adata *list, u64 val)
243
{
244
  if (!ec_set_contains(list, val))
245
    return list;
246

  
247
  struct adata *res;
248
  res = lp_alloc(pool, sizeof(struct adata) + list->length - 8);
249
  res->length = list->length - 8;
250

  
251
  u32 *l = int_set_get_data(list);
252
  u32 *k = int_set_get_data(res);
253
  int len = int_set_get_size(list);
254
  u32 eh = ec_hi(val);
255
  u32 el = ec_lo(val);
256
  int i;
257

  
258
  for (i=0; i < len; i += 2)
259
    if (! (l[i] == eh && l[i+1] == el))
260
      {
261
	*k++ = l[i];
262
	*k++ = l[i+1];
263
      }
264

  
265
  return res;
266
}
nest/attrs.h
50 50

  
51 51
/* a-set.c */
52 52

  
53

  
54
/* Extended Community subtypes (kinds) */
55
#define EC_RT 0x0002
56
#define EC_RO 0x0003
57

  
58
#define EC_GENERIC 0xFFFF
59

  
60
/* Transitive bit (for first u32 half of EC) */
61
#define EC_TBIT 0x40000000
62

  
63

  
64
static inline int int_set_get_size(struct adata *list)
65
{ return list->length / 4; }
66

  
67
static inline u32 *int_set_get_data(struct adata *list)
68
{ return (u32 *) list->data; }
69

  
70
static inline u32 ec_hi(u64 ec) { return ec >> 32; }
71
static inline u32 ec_lo(u64 ec) { return ec; }
72
static inline u64 ec_get(const u32 *l, int i)
73
{ return (((u64) l[i]) << 32) | l[i+1]; }
74

  
75
/* RFC 4360 3.1.  Two-Octet AS Specific Extended Community */
76
static inline u64 ec_as2(u64 kind, u64 key, u64 val)
77
{ return ((kind | 0x0000) << 48) | (key << 32) | val; }
78

  
79
/* RFC 5668  4-Octet AS Specific BGP Extended Community */
80
static inline u64 ec_as4(u64 kind, u64 key, u64 val)
81
{ return ((kind | 0x0200) << 48) | (key << 16) | val; }
82

  
83
/* RFC 4360 3.2.  IPv4 Address Specific Extended Community */
84
static inline u64 ec_ip4(u64 kind, u64 key, u64 val)
85
{ return ((kind | 0x0100) << 48) | (key << 16) | val; }
86

  
87
static inline u64 ec_generic(u64 key, u64 val)
88
{ return (key << 32) | val; }
89

  
53 90
int int_set_format(struct adata *set, int way, int from, byte *buf, unsigned int size);
54
struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val);
91
int ec_format(byte *buf, u64 ec);
92
int ec_set_format(struct adata *set, int from, byte *buf, unsigned int size);
55 93
int int_set_contains(struct adata *list, u32 val);
94
int ec_set_contains(struct adata *list, u64 val);
95
struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val);
96
struct adata *ec_set_add(struct linpool *pool, struct adata *list, u64 val);
56 97
struct adata *int_set_del(struct linpool *pool, struct adata *list, u32 val);
98
struct adata *ec_set_del(struct linpool *pool, struct adata *list, u64 val);
57 99

  
58
static inline int int_set_get_size(struct adata *list)
59
{ return list->length / 4; }
60 100

  
61 101
#endif
nest/route.h
363 363
#define EAF_TYPE_ROUTER_ID 0x05		/* Router ID (IPv4 address) */
364 364
#define EAF_TYPE_AS_PATH 0x06		/* BGP AS path (encoding per RFC 1771:4.3) */
365 365
#define EAF_TYPE_INT_SET 0x0a		/* Set of u32's (e.g., a community list) */
366
#define EAF_TYPE_EC_SET 0x0e		/* Set of pairs of u32's - ext. community list */
366 367
#define EAF_TYPE_UNDEF 0x0f		/* `force undefined' entry */
367 368
#define EAF_EMBEDDED 0x01		/* Data stored in eattr.u.data (part of type spec) */
368 369
#define EAF_VAR_LENGTH 0x02		/* Attribute length is variable (part of type spec) */
nest/rt-attr.c
465 465
    }
466 466
}
467 467

  
468
static inline void
469
ea_show_ec_set(struct cli *c, struct adata *ad, byte *pos, byte *buf, byte *end)
470
{
471
  int i = ec_set_format(ad, 0, pos, end - pos);
472
  cli_printf(c, -1012, "%s", buf);
473
  while (i)
474
    {
475
      i = ec_set_format(ad, i, buf, end - buf - 1);
476
      cli_printf(c, -1012, "\t%s", buf);
477
    }
478
}
479

  
468 480
/**
469 481
 * ea_show - print an &eattr to CLI
470 482
 * @c: destination CLI
......
523 535
	case EAF_TYPE_INT_SET:
524 536
	  ea_show_int_set(c, ad, 1, pos, buf, end);
525 537
	  return;
538
	case EAF_TYPE_EC_SET:
539
	  ea_show_ec_set(c, ad, pos, buf, end);
540
	  return;
526 541
	case EAF_TYPE_UNDEF:
527 542
	default:
528 543
	  bsprintf(pos, "<type %02x>", e->type);
proto/bgp/attrs.c
247 247
  return ((len % 4) == 0) ? 0 : WITHDRAW;
248 248
}
249 249

  
250

  
251 250
static int
252 251
bgp_check_cluster_list(struct bgp_proto *p UNUSED, byte *a UNUSED, int len)
253 252
{
......
281 280
  return IGNORE;
282 281
}
283 282

  
283
static int
284
bgp_check_ext_community(struct bgp_proto *p UNUSED, byte *a UNUSED, int len)
285
{
286
  return ((len % 8) == 0) ? 0 : WITHDRAW;
287
}
288

  
289

  
284 290
static struct attr_desc bgp_attr_table[] = {
285 291
  { NULL, -1, 0, 0, 0,								/* Undefined */
286 292
    NULL, NULL },
......
311 317
    bgp_check_reach_nlri, NULL },
312 318
  { "mp_unreach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1,			/* BA_MP_UNREACH_NLRI */
313 319
    bgp_check_unreach_nlri, NULL },
314
  {  .name = NULL },								/* BA_EXTENDED_COMM */
320
  { "ext_community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_EC_SET, 1,	/* BA_EXT_COMMUNITY */
321
    bgp_check_ext_community, NULL },
315 322
  { "as4_path", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,		/* BA_AS4_PATH */
316 323
    NULL, NULL },
317 324
  { "as4_aggregator", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,	/* BA_AS4_PATH */
......
468 475
unsigned int
469 476
bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
470 477
{
471
  unsigned int i, code, flags;
478
  unsigned int i, code, type, flags;
472 479
  byte *start = w;
473 480
  int len, rv;
474 481

  
......
477 484
      eattr *a = &attrs->attrs[i];
478 485
      ASSERT(EA_PROTO(a->id) == EAP_BGP);
479 486
      code = EA_ID(a->id);
487

  
480 488
#ifdef IPV6
481 489
      /* When talking multiprotocol BGP, the NEXT_HOP attributes are used only temporarily. */
482 490
      if (code == BA_NEXT_HOP)
......
559 567

  
560 568
      /* Standard path continues here ... */
561 569

  
570
      type = a->type & EAF_TYPE_MASK;
562 571
      flags = a->flags & (BAF_OPTIONAL | BAF_TRANSITIVE | BAF_PARTIAL);
563 572
      len = bgp_get_attr_len(a);
564 573

  
565
      /* Skip empty int sets */ 
566
      if (((a->type & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) && (len == 0))
574
      /* Skip empty sets */ 
575
      if (((type == EAF_TYPE_INT_SET) || (type == EAF_TYPE_EC_SET)) && (len == 0))
567 576
	continue; 
568 577

  
569 578
      if (remains < len + 4)
......
572 581
      rv = bgp_encode_attr_hdr(w, flags, code, len);
573 582
      ADVANCE(w, remains, rv);
574 583

  
575
      switch (a->type & EAF_TYPE_MASK)
584
      switch (type)
576 585
	{
577 586
	case EAF_TYPE_INT:
578 587
	case EAF_TYPE_ROUTER_ID:
......
589 598
	    break;
590 599
	  }
591 600
	case EAF_TYPE_INT_SET:
601
	case EAF_TYPE_EC_SET:
592 602
	  {
593
	    u32 *z = (u32 *)a->u.ptr->data;
603
	    u32 *z = int_set_get_data(a->u.ptr);
594 604
	    int i;
595 605
	    for(i=0; i<len; i+=4)
596 606
	      put_u32(w+i, *z++);
......
624 634
  return (*x < *y) ? -1 : (*x > *y) ? 1 : 0;
625 635
}
626 636

  
627
static void
628
bgp_normalize_set(u32 *dest, u32 *src, unsigned cnt)
637
static inline void
638
bgp_normalize_int_set(u32 *dest, u32 *src, unsigned cnt)
629 639
{
630 640
  memcpy(dest, src, sizeof(u32) * cnt);
631 641
  qsort(dest, cnt, sizeof(u32), (int(*)(const void *, const void *)) bgp_compare_u32);
632 642
}
633 643

  
644
static int
645
bgp_compare_ec(const u32 *xp, const u32 *yp)
646
{
647
  u64 x = ec_get(xp, 0);
648
  u64 y = ec_get(yp, 0);
649
  return (x < y) ? -1 : (x > y) ? 1 : 0;
650
}
651

  
652
static inline void
653
bgp_normalize_ec_set(struct adata *ad, u32 *src, int internal)
654
{
655
  u32 *dst = int_set_get_data(ad);
656

  
657
  /* Remove non-transitive communities (EC_TBIT active) on external sessions */
658
  if (! internal)
659
    {
660
      int len = int_set_get_size(ad);
661
      u32 *t = dst;
662
      int i;
663

  
664
      for (i=0; i < len; i += 2)
665
	{
666
	  if (src[i] & EC_TBIT)
667
	    continue;
668
	  
669
	  *t++ = src[i];
670
	  *t++ = src[i+1];
671
	}
672

  
673
      ad->length = (t - dst) * 4;
674
    }
675
  else
676
    memcpy(dst, src, ad->length);
677

  
678
  qsort(dst, ad->length / 8, 8, (int(*)(const void *, const void *)) bgp_compare_ec);
679
}
680

  
634 681
static void
635 682
bgp_rehash_buckets(struct bgp_proto *p)
636 683
{
......
763 810
	  {
764 811
	    struct adata *z = alloca(sizeof(struct adata) + d->u.ptr->length);
765 812
	    z->length = d->u.ptr->length;
766
	    bgp_normalize_set((u32 *) z->data, (u32 *) d->u.ptr->data, z->length / 4);
813
	    bgp_normalize_int_set((u32 *) z->data, (u32 *) d->u.ptr->data, z->length / 4);
814
	    d->u.ptr = z;
815
	    break;
816
	  }
817
	case EAF_TYPE_EC_SET:
818
	  {
819
	    struct adata *z = alloca(sizeof(struct adata) + d->u.ptr->length);
820
	    z->length = d->u.ptr->length;
821
	    bgp_normalize_ec_set(z, (u32 *) d->u.ptr->data, p->is_internal);
767 822
	    d->u.ptr = z;
768 823
	    break;
769 824
	  }
......
1447 1502
	  ipa_ntoh(*(ip_addr *)ad->data);
1448 1503
	  break;
1449 1504
	case EAF_TYPE_INT_SET:
1505
	case EAF_TYPE_EC_SET:
1450 1506
	  {
1451 1507
	    u32 *z = (u32 *) ad->data;
1452 1508
	    for(i=0; i<ad->length/4; i++)
proto/bgp/bgp.h
236 236
#define BA_RCID_PATH		0x0d
237 237
#define BA_MP_REACH_NLRI	0x0e	/* [RFC2283] */
238 238
#define BA_MP_UNREACH_NLRI	0x0f
239
#define BA_EXTENDED_COMM	0x10	/* draft-ramachandra-bgp-ext-communities */
239
#define BA_EXT_COMMUNITY	0x10	/* [RFC4360] */
240 240
#define BA_AS4_PATH             0x11    /* [RFC4893] */
241 241
#define BA_AS4_AGGREGATOR       0x12
242 242

  
proto/bgp/config.Y
21 21
	PATH, METRIC, ERROR, START, DELAY, FORGET, WAIT, ENABLE,
22 22
	DISABLE, AFTER, BGP_PATH, BGP_LOCAL_PREF, BGP_MED, BGP_ORIGIN,
23 23
	BGP_NEXT_HOP, BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY,
24
	SOURCE, ADDRESS, PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4,
25
	ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE, PREFER, OLDER,
26
	MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH, INTERPRET,
27
	COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, TABLE,
28
	GATEWAY, DIRECT, RECURSIVE, MED)
24
	BGP_EXT_COMMUNITY, SOURCE, ADDRESS, PASSWORD, RR, RS, CLIENT,
25
	CLUSTER, ID, AS4, ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE,
26
	PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH,
27
	INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP,
28
	TABLE, GATEWAY, DIRECT, RECURSIVE, MED)
29 29

  
30 30
CF_GRAMMAR
31 31

  
......
120 120
	{ $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID)); })
121 121
CF_ADDTO(dynamic_attr, BGP_CLUSTER_LIST
122 122
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(EAP_BGP, BA_CLUSTER_LIST)); })
123
CF_ADDTO(dynamic_attr, BGP_EXT_COMMUNITY
124
	{ $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, T_ECLIST, EA_CODE(EAP_BGP, BA_EXT_COMMUNITY)); })
125

  
123 126

  
124 127

  
125 128
CF_ENUM(T_ENUM_BGP_ORIGIN, ORIGIN_, IGP, EGP, INCOMPLETE)
sysdep/autoconf.h.in
18 18
/* 32-bit integer type */
19 19
#define INTEGER_32 ?
20 20

  
21
/* 64-bit integer type */
22
#define INTEGER_64 ?
23

  
21 24
/* CPU endianity */
22 25
#undef CPU_LITTLE_ENDIAN
23 26
#undef CPU_BIG_ENDIAN
sysdep/config.h
30 30
typedef unsigned INTEGER_16 u16;
31 31
typedef INTEGER_32 s32;
32 32
typedef unsigned INTEGER_32 u32;
33
typedef INTEGER_64 s64;
34
typedef unsigned INTEGER_64 u64;
33 35
typedef u8 byte;
34 36
typedef u16 word;
35 37

  

Also available in: Unified diff