diff --git a/filter/config.Y b/filter/config.Y index 79786faa..09d4fd89 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -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); } ; diff --git a/filter/data.h b/filter/data.h index 21a78bf6..df8d6a8f 100644 --- a/filter/data.h +++ b/filter/data.h @@ -120,6 +120,7 @@ enum f_sa_code { SA_WEIGHT, SA_PREF, SA_GW_MPLS, + SA_GW_MPLS_STACK, SA_ONLINK, } PACKED; diff --git a/filter/f-inst.c b/filter/f-inst.c index a3f441fc..6593a381 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -692,6 +692,16 @@ 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: @@ -779,6 +789,36 @@ } 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; @@ -1262,6 +1302,14 @@ 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); @@ -1344,6 +1392,14 @@ 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); diff --git a/lib/ip.h b/lib/ip.h index 8dd925ed..0a25d5bc 100644 --- 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]; diff --git a/nest/rt-show.c b/nest/rt-show.c index 265d5c44..fb71fba8 100644 --- a/nest/rt-show.c +++ b/nest/rt-show.c @@ -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] = "";