]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Filter: Add route attribute gw_mpls_stack
authorOndrej Zajicek <santiago@crfreenet.org>
Tue, 5 Mar 2024 15:38:24 +0000 (16:38 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 5 Mar 2024 15:47:08 +0000 (16:47 +0100)
Add route attribute gw_mpls_stack to make MPLS stack of route nexthop
accessible from filters. Its type is T_CLIST, which is really not correct
(as it is a list, while T_CLIST is a set). Therefore, we keep this
attribute *undocumented* and it will be *changed* without further notice.

Based on a patch from Trisha Biswas <tbiswas@fastly.com>, thanks!

filter/config.Y
filter/data.h
filter/f-inst.c
lib/ip.h
nest/rt-show.c

index 79786faa42260c2abd88050451203e9097c0acd1..09d4fd8909326b1c87253ac46a8fd41c13dbd45a 100644 (file)
@@ -362,7 +362,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
        IF, THEN, ELSE, CASE,
        FOR, DO,
        TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
-       FROM, GW, NET, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, ONLINK,
+       FROM, GW, NET, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, GW_MPLS_STACK, ONLINK,
        PREFERENCE,
        ROA_CHECK,
        DEFINED,
@@ -879,6 +879,7 @@ static_attr:
  | WEIGHT  { $$ = f_new_static_attr(T_INT,        SA_WEIGHT,   0); }
  | PREFERENCE { $$ = f_new_static_attr(T_INT,    SA_PREF,      0); }
  | GW_MPLS { $$ = f_new_static_attr(T_INT,        SA_GW_MPLS,  0); }
+ | GW_MPLS_STACK { $$ = f_new_static_attr(T_CLIST, SA_GW_MPLS_STACK,   0); }
  | ONLINK  { $$ = f_new_static_attr(T_BOOL,       SA_ONLINK,   0); }
  ;
 
index 21a78bf6c16e6a4dd5ba893c6ed3ccffc82f7bb3..df8d6a8f7cd75205d3e48dd036145ac932b81fe2 100644 (file)
@@ -120,6 +120,7 @@ enum f_sa_code {
   SA_WEIGHT,
   SA_PREF,
   SA_GW_MPLS,
+  SA_GW_MPLS_STACK,
   SA_ONLINK,
 } PACKED;
 
index a3f441fccfb7fffe3306c81b650aae7c1728c24f..6593a3812e66d0fb8e745eb81f2b58b2284c3a6e 100644 (file)
       case SA_WEIGHT:  RESULT(sa.f_type, i, rta->nh.weight + 1); break;
       case SA_PREF:    RESULT(sa.f_type, i, rta->pref); break;
       case SA_GW_MPLS: RESULT(sa.f_type, i, rta->nh.labels ? rta->nh.label[0] : MPLS_NULL); break;
+      case SA_GW_MPLS_STACK:
+        {
+         uint len = rta->nh.labels * sizeof(u32);
+         struct adata *list = falloc(sizeof(struct adata) + len);
+         list->length = len;
+         memcpy(list->data, rta->nh.label, len);
+         RESULT(sa.f_type, ad, list);
+         break;
+       }
+
       case SA_ONLINK:  RESULT(sa.f_type, i, rta->nh.flags & RNF_ONLINK ? 1 : 0); break;
 
       default:
          }
          else
            rta->nh.labels = 0;
+
+         rta->nh.labels_orig = rta->hostentry ? rta->nh.labels : 0;
+       }
+       break;
+
+      case SA_GW_MPLS_STACK:
+       {
+         int len = int_set_get_size(v1.val.ad);
+         u32 *l = int_set_get_data(v1.val.ad);
+
+         if (len > MPLS_MAX_LABEL_STACK)
+           runtime("Too many MPLS labels in stack (%d)", len);
+
+         int i;
+         for (i = 0; i < len; i++)
+         {
+           u32 label = l[i];
+
+           if (label >= 0x100000)
+             runtime("Invalid MPLS label (%u)", label);
+
+           /* Ignore rest of label stack if implicit-NULL label (3) is set */
+           if (label == MPLS_NULL)
+             break;
+
+           rta->nh.label[i] = label;
+         }
+
+         rta->nh.labels = i;
+         rta->nh.labels_orig = rta->hostentry ? i : 0;
        }
        break;
 
     RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, v2.val.i) ]]);
   }
 
+  /* Hack for gw_mpls_list */
+  INST(FI_CLIST_ADD_INT, 2, 1) {
+    ARG(1, T_CLIST);
+    ARG(2, T_INT);
+    METHOD_CONSTRUCTOR("add");
+    RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, v2.val.i) ]]);
+  }
+
   INST(FI_CLIST_ADD_IP, 2, 1) {
     ARG(1, T_CLIST);
     ARG(2, T_IP);
     RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, v2.val.i) ]]);
   }
 
+  /* Hack for gw_mpls_list */
+  INST(FI_CLIST_DELETE_INT, 2, 1) {
+    ARG(1, T_CLIST);
+    ARG(2, T_INT);
+    METHOD_CONSTRUCTOR("delete");
+    RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, v2.val.i) ]]);
+  }
+
   INST(FI_CLIST_DELETE_IP, 2, 1) {
     ARG(1, T_CLIST);
     ARG(2, T_IP);
index 8dd925ed2aeb0e0fab31ce90c2d47ca92de1598f..0a25d5bccaa319261609851c0cf5699aa1747581 100644 (file)
--- a/lib/ip.h
+++ b/lib/ip.h
@@ -392,6 +392,7 @@ static inline ip6_addr ip6_ntoh(ip6_addr a)
 #define MPLS_MAX_LABEL 0x100000
 
 #define MPLS_MAX_LABEL_STACK 8
+#define MPLS_MAX_LABEL_STRING MPLS_MAX_LABEL_STACK*12 + 5
 typedef struct mpls_label_stack {
   uint len;
   u32 stack[MPLS_MAX_LABEL_STACK];
index 265d5c4472d3d53989ab9a0786b01b0ff511a9c0..fb71fba85bbaef622f5db28339d8a0fb90872b84 100644 (file)
@@ -72,7 +72,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
   if (a->dest == RTD_UNICAST)
     for (nh = &(a->nh); nh; nh = nh->next)
     {
-      char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls;
+      char mpls[MPLS_MAX_LABEL_STRING], *lsp = mpls;
       char *onlink = (nh->flags & RNF_ONLINK) ? " onlink" : "";
       char weight[16] = "";