[prev in list] [next in list] [prev in thread] [next in thread] 

List:       bird-users
Subject:    operator to prepend bgp path multiple times
From:       Alexander Zubkov <green () qrator ! net>
Date:       2022-01-01 19:24:00
Message-ID: CABr+u0b=9CYKrt4uaNcwG6dHfmgVJLkTDjgE5qP2M9jF8S0Mnw () mail ! gmail ! com
[Download RAW message or body]

Hi,

I suggest to add a new operator: prepend_times(P, A, N) - that will
allow to prepend AS A to path P several times (N). Now we need to use
some function like this:

function add_prepends(int asn, int num) {
  if num = 1 then {
    bgp_path.prepend(asn);
  } else if num = 2 then {
    bgp_path.prepend(asn);
    bgp_path.prepend(asn);
 } else if num = 3 then {
...
}

Usually the number of prepends is observable, so this function can fit
most of cases, but with available operator it will be a bit more
convenient, a little syntactic sugar. But it is not something that is
hard to live without, of course.

In my patch, I chose to "join" implementations of prepend() and
prepend_times(). It is questionable, because it requires some
additional supporting stuff if I understood right. So may be it is
better to implement it as separate operators.

["bird-prepend-times.patch" (text/x-patch)]

commit 876c19f58a5814241bd5110f6cd2f6889a581691
Author: Alexander Zubkov <green@qrator.net>
Date:   Sat Jan 1 06:05:45 2022 +0100

    Filter: add operator to prepend bgppath multiple times
    
    New operator allows to prepend ASN A to path P N times:
    prepend_times(P, A, N)
    P.prepend_times(A, N)

diff --git a/filter/config.Y b/filter/config.Y
index 8916ea97..78228a1f 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -22,6 +22,12 @@ static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
 #define f_generate_complex(fi_code, da, arg) \
   f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg), da)
 
+#define f_generate_complex2(fi_code, da, arg1, arg2) \
+  f_new_inst(FI_EA_SET, f_new_inst(fi_code, f_new_inst(FI_EA_GET, da), arg1, arg2), \
da) +
+#define f_new_int_const(arg) \
+  f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_INT, .val.i = arg, })
+
 /*
  * Sets and their items are during parsing handled as lists, linked
  * through left ptr. The first item in a list also contains a pointer
@@ -286,7 +292,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
 	DATA, DATA1, DATA2,
 	DEFINED,
 	ADD, DELETE, CONTAINS, RESET,
-	PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
+	PREPEND, PREPEND_TIMES, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
 	MIN, MAX,
 	EMPTY,
 	FILTER, WHERE, EVAL, ATTRIBUTE,
@@ -816,7 +822,8 @@ term:
  | '-' EMPTY '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_clist); }
  | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_CONSTANT, f_const_empty_eclist); }
  | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_CONSTANT, \
                f_const_empty_lclist); }
- | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5); }
+ | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND, $3, $5, \
f_new_int_const(1)); } + | PREPEND_TIMES '(' term ',' term ',' term ')' { $$ = \
f_new_inst(FI_PATH_PREPEND, $3, $5, $7); }  | ADD '(' term ',' term ')' { $$ = \
f_new_inst(FI_CLIST_ADD, $3, $5); }  | DELETE '(' term ',' term ')' { $$ = \
f_new_inst(FI_CLIST_DEL, $3, $5); }  | FILTER '(' term ',' term ')' { $$ = \
f_new_inst(FI_CLIST_FILTER, $3, $5); } @@ -908,7 +915,8 @@ cmd:
    }
 
  | dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($1); }
- | dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( \
FI_PATH_PREPEND, $1, $5 ); } + | dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = \
f_generate_complex2( FI_PATH_PREPEND, $1, $5, f_new_int_const(1) ); } + | \
dynamic_attr '.' PREPEND_TIMES '(' term ',' term ')' ';'   { $$ = \
f_generate_complex2( FI_PATH_PREPEND, $1, $5, $7 ); }  | dynamic_attr '.' ADD '(' \
term ')' ';'       { $$ = f_generate_complex( FI_CLIST_ADD, $1, $5 ); }  | \
dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( FI_CLIST_DEL, \
$1, $5 ); }  | dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( \
                FI_CLIST_FILTER, $1, $5 ); }
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 901d2939..5974f343 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -1143,10 +1143,15 @@
       ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i))) ]]);
   }
 
-  INST(FI_PATH_PREPEND, 2, 1) {	/* Path prepend */
+  INST(FI_PATH_PREPEND, 3, 1) {	/* Path prepend */
     ARG(1, T_PATH);
     ARG(2, T_INT);
-    RESULT(T_PATH, ad, [[ as_path_prepend(fpool, v1.val.ad, v2.val.i) ]]);
+    ARG(3, T_INT);
+    struct adata *path = v1.val.ad;
+    for (int i = 0; i < v3.val.i; ++i) {
+      path = as_path_prepend(fpool, path, v2.val.i);
+    }
+    RESULT(T_PATH, ad, path);
   }
 
   INST(FI_CLIST_ADD, 2, 1) {	/* (Extended) Community list add */
diff --git a/filter/test.conf b/filter/test.conf
index 6a28e4b3..2a64792f 100644
--- a/filter/test.conf
+++ b/filter/test.conf
@@ -665,6 +665,14 @@ int set set12;
 	bt_assert(delete(p2, [4..5]) = prepend(prepend(prepend(prepend(+empty+, 3), 3), 2), \
1));  
 	bt_assert(format([= 1 2+ 3 =]) = "[= 1 2 + 3 =]");
+
+	p2 = prepend_times( + empty +, 1, 3 );
+	p2 = prepend_times( p2, 2, 2 );
+	p2 = prepend_times( p2, 3, 0 );
+	p2 = prepend_times( p2, 4, 1 );
+
+	bt_assert(format(p2) = "(path 4 2 2 1 1 1)");
+	bt_assert(p2.len = 6);
 }
 
 bt_test_suite(t_path, "Testing paths");



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic