#include "lib/socket.h"
#include "lib/timer.h"
#include "lib/string.h"
+#include "lib/mpls.h"
#include "nest/protocol.h"
#include "nest/iface.h"
#include "nest/route.h"
ip6_addr ip6;
net_addr net;
net_addr *net_ptr;
+ struct mpls_stack *mpls;
struct symbol *s;
char *t;
struct rtable_config *r;
%type <a> ipa
%type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_
+%type <mpls> mpls_stack_start mpls_stack
%type <t> text opttext
%left '!'
%nonassoc '.'
-CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN)
+CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS)
CF_GRAMMAR
}
;
+/* MPLS stack */
+
+mpls_stack_start: MPLS NUM
+{
+ $$ = cfg_allocz(sizeof(struct mpls_stack));
+ $$->len = 1;
+ $$->label[0] = $2;
+};
+
+mpls_stack:
+ mpls_stack_start
+ | mpls_stack '/' NUM { $1->label[$1->len++] = $3; $$ = $1; }
+;
+
datetime:
TEXT {
md5.c
md5.h
mempool.c
+mpls.h
resource.c
resource.h
slab.c
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE) /* ,ROA */
CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
-CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
+CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, MPLS_STACK, CLASS, DSCP)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
CF_ADDTO(dynamic_attr, IGP_METRIC
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_GEN_IGP_METRIC); })
+CF_ADDTO(dynamic_attr, MPLS_STACK
+ { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_GEN_MPLS_STACK); })
CF_CODE
#define EA_ID(ea) ((ea) & 0xff)
#define EA_GEN_IGP_METRIC EA_CODE(EAP_GENERIC, 0)
+#define EA_GEN_MPLS_STACK EA_CODE(EAP_GENERIC, 1)
#define EA_CODE_MASK 0xffff
#define EA_ALLOW_UNDEF 0x10000 /* ea_find: allow EAF_TYPE_UNDEF */
*buf += bsprintf(*buf, "igp_metric");
return GA_NAME;
}
+ else if (a->id == EA_GEN_MPLS_STACK)
+ {
+ *buf += bsprintf(*buf, "mpls");
+ struct adata *ad = a->u.ptr;
+ u32 *z = ad->data;
+ int len = ad->length / sizeof(u32);
+ int i;
+
+ *buf += bsprintf(*buf, " %d", z[0]);
+ for (i = 1; i < len; i++)
+ *buf += bsprintf(*buf, "/%d", z[i]);
+
+ return GA_FULL;
+ }
return GA_UNKNOWN;
}
stat_route_item:
cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); }
| BFD bool ';' { this_srt->use_bfd = $2; cf_check_bfd($2); }
+ | mpls_stack ';' { this_srt->mpls_stack = $1; }
;
stat_route_opts:
#include "filter/filter.h"
#include "lib/string.h"
#include "lib/alloca.h"
+#include "lib/mpls.h"
#include "static.h"
a.dest = r->dest;
a.gw = r->via;
a.iface = ifa;
+ if (r->mpls_stack) {
+ a.eattrs = lp_alloc(static_lp, sizeof(ea_list) + sizeof(eattr));
+ a.eattrs->next = NULL;
+ a.eattrs->flags = 0;
+ a.eattrs->count = 1;
+ a.eattrs->attrs[0].id = EA_GEN_MPLS_STACK;
+ a.eattrs->attrs[0].flags = 0;
+ a.eattrs->attrs[0].type = EAF_TYPE_INT_SET;
+
+ struct adata *ad = lp_alloc(static_lp, sizeof(struct adata) + r->mpls_stack->len*sizeof(u32));
+ ad->length = r->mpls_stack->len*sizeof(u32);
+ memcpy(ad->data, r->mpls_stack->label, ad->length);
+ a.eattrs->attrs[0].u.ptr = ad;
+ }
if (r->dest == RTD_MULTIPATH)
{
int installed; /* Installed in rt table, -1 for reinstall */
int use_bfd; /* Configured to use BFD */
int weight; /* Multipath next hop weight */
+ struct mpls_stack *mpls_stack; /* MPLS stack to apply to routed packets */
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
};