Commit ec430a7f authored by Ondrej Zajicek (work)'s avatar Ondrej Zajicek (work)
Browse files

Nest: Implement BGP path mask loop operator

Implement regex-like '+' operator in BGP path masks to match previous
path mask item multiple times. This is useful as ASNs may appear
multiple times in paths due to path prepending for traffic engineering
purposes.
parent 5fc84071
Loading
Loading
Loading
Loading
+10 −5
Original line number Diff line number Diff line
@@ -1471,11 +1471,16 @@ in the foot).
	<cf/*/ matches any (even empty) sequence of arbitrary AS numbers and
	<cf/?/ matches one arbitrary AS number. For example, if <cf>bgp_path</cf>
 	is 4 3 2 1, then: <tt>bgp_path &tilde; [= * 4 3 * =]</tt> is true,
	but <tt>bgp_path &tilde; [= * 4 5 * =]</tt> is false. BGP mask
	expressions can also contain integer expressions enclosed in parenthesis
	and integer variables, for example <tt>[= * 4 (1+2) a =]</tt>. You can
	also use ranges (e.g. <tt>[= * 3..5 2 100..200 * =]</tt>) and sets
	(e.g. <tt>[= 1 2 [3, 5, 7] * =]</tt>).
	but <tt>bgp_path &tilde; [= * 4 5 * =]</tt> is false. There is also
	<cf/+/ operator which matches one or multiple instances of previous
	expression, e.g. <tt>[= 1 2+ 3 =]</tt> matches both path 1 2 3 and path
	1 2 2 2 3, but not 1 3 nor 1 2 4 3. Note that while <cf/*/ and <cf/?/
	are wildcard-style operators, <cf/+/ is regex-style operator.

	BGP mask expressions can also contain integer expressions enclosed in
	parenthesis and integer variables, for example <tt>[= * 4 (1+2) a =]</tt>.
	You can also use ranges (e.g. <tt>[= * 3..5 2 100..200 * =]</tt>)
	and sets (e.g. <tt>[= 1 2 [3, 5, 7] * =]</tt>).

	<tag><label id="type-clist">clist</tag>
	Clist is similar to a set, except that unlike other sets, it can be
+1 −0
Original line number Diff line number Diff line
@@ -662,6 +662,7 @@ bgp_path_tail:
 }
 | '*' bgp_path_tail		{ $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; }
 | '?' bgp_path_tail		{ $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; }
 | '+' bgp_path_tail 		{ $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_LOOP }, }); $$->next = $2; }
 | bgp_path_expr bgp_path_tail	{ $$ = $1; $$->next = $2; }
 | 				{ $$ = NULL; }
 ;
+11 −0
Original line number Diff line number Diff line
@@ -93,6 +93,8 @@ adata_empty(struct linpool *pool, int l)
static void
pm_format(const struct f_path_mask *p, buffer *buf)
{
  int loop = 0;

  buffer_puts(buf, "[= ");

  for (uint i=0; i<p->len; i++)
@@ -111,6 +113,10 @@ pm_format(const struct f_path_mask *p, buffer *buf)
      buffer_puts(buf, "* ");
      break;

    case PM_LOOP:
      loop = 1;
      break;

    case PM_ASN_RANGE:
      buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
      break;
@@ -119,6 +125,11 @@ pm_format(const struct f_path_mask *p, buffer *buf)
      ASSERT(0);
    }

    if (loop && (p->item[i].kind != PM_LOOP))
    {
      buffer_puts(buf, "+ ");
      loop = 0;
    }
  }

  buffer_puts(buf, "=]");
+11 −0
Original line number Diff line number Diff line
@@ -311,6 +311,17 @@
    for (uint i=0; i<whati->varcount; i++) {
      switch (vv(i).type) {
	case T_PATH_MASK_ITEM:
	  if (vv(i).val.pmi.kind == PM_LOOP)
	  {
	    if (i == 0)
	      runtime("Path mask iterator '+' cannot be first");

	    /* We want PM_LOOP as prefix operator */
	    pm->item[i] = pm->item[i - 1];
	    pm->item[i - 1] = vv(i).val.pmi;
	    break;
	  }

	  pm->item[i] = vv(i).val.pmi;
	  break;

+9 −2
Original line number Diff line number Diff line
@@ -646,7 +646,6 @@ int set set12;
	bt_assert(delete(p2, 3) = prepend(prepend(prepend(prepend(+empty+, 1), 2), 4), 5));
	bt_assert(filter(p2, [1..3]) = prepend(prepend(prepend(+empty+, 1), 2), 3));

	pm1 = [= 1 2 * 3 4 5 =];
	p2 = prepend( + empty +, 5 );
	p2 = prepend( p2, 4 );
	p2 = prepend( p2, 3 );
@@ -654,9 +653,17 @@ int set set12;
	p2 = prepend( p2, 2 );
	p2 = prepend( p2, 1 );

	bt_assert(p2 ~ pm1);
	bt_assert(p2 !~ [= 1 2 3 4 5 =]);
	bt_assert(p2 ~ [= 1 2 * 4 5 =]);
	bt_assert(p2 ~ [= 1 2 * 3 4 5 =]);
	bt_assert(p2 ~ [= 1 2 3+ 4 5 =]);
	bt_assert(p2 ~ [= 1 2 3+ 4+ 5 =]);
	bt_assert(p2 !~ [= 1 2 3+ 5+ 4 5 =]);
	bt_assert(p2 !~ [= 1 2 3 3 5+ 4 5 =]);
	bt_assert(delete(p2, 3) = prepend(prepend(prepend(prepend(+empty+, 5), 4), 2), 1));
	bt_assert(delete(p2, [4..5]) = prepend(prepend(prepend(prepend(+empty+, 3), 3), 2), 1));

	bt_assert(format([= 1 2+ 3 =]) = "[= 1 2 + 3 =]");
}

bt_test_suite(t_path, "Testing paths");
Loading