diff options
Diffstat (limited to 'net/openbgpd/files/patch-bgpd_parse.y')
-rw-r--r-- | net/openbgpd/files/patch-bgpd_parse.y | 1626 |
1 files changed, 0 insertions, 1626 deletions
diff --git a/net/openbgpd/files/patch-bgpd_parse.y b/net/openbgpd/files/patch-bgpd_parse.y deleted file mode 100644 index 0f9160187aac..000000000000 --- a/net/openbgpd/files/patch-bgpd_parse.y +++ /dev/null @@ -1,1626 +0,0 @@ -Index: bgpd/parse.y -=================================================================== -RCS file: /home/cvs/private/hrs/openbgpd/bgpd/parse.y,v -retrieving revision 1.1.1.8 -retrieving revision 1.12 -diff -u -p -r1.1.1.8 -r1.12 ---- bgpd/parse.y 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/parse.y 8 Dec 2012 20:17:59 -0000 1.12 -@@ -1,4 +1,4 @@ --/* $OpenBSD: parse.y,v 1.231 2009/06/06 01:10:29 claudio Exp $ */ -+/* $OpenBSD: parse.y,v 1.264 2012/09/23 09:39:17 claudio Exp $ */ - - /* - * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> -@@ -25,7 +25,10 @@ - #include <sys/stat.h> - #include <netinet/in.h> - #include <arpa/inet.h> -- -+#if !defined(__FreeBSD__) /* FreeBSD has no mpls support. */ -+#include <netmpls/mpls.h> -+#endif -+ - #include <ctype.h> - #include <err.h> - #include <unistd.h> -@@ -33,6 +36,9 @@ - #include <limits.h> - #include <stdarg.h> - #include <stdio.h> -+#if defined(__FreeBSD__) -+#include <stdlib.h> -+#endif - #include <string.h> - #include <syslog.h> - -@@ -74,10 +80,12 @@ char *symget(const char *); - - static struct bgpd_config *conf; - static struct mrt_head *mrtconf; --static struct network_head *netconf; -+static struct network_head *netconf, *gnetconf; - static struct peer *peer_l, *peer_l_old; - static struct peer *curpeer; - static struct peer *curgroup; -+static struct rdomain *currdom; -+static struct rdomain_head *rdom_l; - static struct filter_head *filter_l; - static struct filter_head *peerfilter_l; - static struct filter_head *groupfilter_l; -@@ -105,7 +113,7 @@ struct filter_match_l { - struct filter_match m; - struct filter_prefix_l *prefix_l; - struct filter_as_l *as_l; -- sa_family_t af; -+ u_int8_t aid; - } fmopts; - - struct peer *alloc_peer(void); -@@ -113,8 +121,8 @@ struct peer *new_peer(void); - struct peer *new_group(void); - int add_mrtconfig(enum mrt_type, char *, time_t, struct peer *, - char *); --int add_rib(char *, u_int16_t); --int find_rib(char *); -+int add_rib(char *, u_int, u_int16_t); -+struct rde_rib *find_rib(char *); - int get_id(struct peer *); - int expand_rule(struct filter_rule *, struct filter_peers_l *, - struct filter_match_l *, struct filter_set_head *); -@@ -123,12 +131,14 @@ int neighbor_consistent(struct peer *) - int merge_filterset(struct filter_set_head *, struct filter_set *); - void copy_filterset(struct filter_set_head *, - struct filter_set_head *); --void move_filterset(struct filter_set_head *, -- struct filter_set_head *); - struct filter_rule *get_rule(enum action_types); - - int getcommunity(char *); --int parsecommunity(char *, int *, int *); -+int parsecommunity(struct filter_community *, char *); -+int parsesubtype(char *); -+int parseextvalue(char *, u_int32_t *); -+int parseextcommunity(struct filter_extcommunity *, char *, -+ char *); - - typedef struct { - union { -@@ -159,29 +169,33 @@ typedef struct { - %} - - %token AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE RTABLE -+%token RDOMAIN RD EXPORTTRGT IMPORTTRGT - %token RDE RIB EVALUATE IGNORE COMPARE - %token GROUP NEIGHBOR NETWORK --%token REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART --%token ANNOUNCE DEMOTE CONNECTRETRY --%token ENFORCE NEIGHBORAS CAPABILITIES REFLECTOR DEPEND DOWN SOFTRECONFIG --%token DUMP IN OUT -+%token REMOTEAS DESCR LLIFACE LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART -+%token ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY -+%token DEMOTE ENFORCE NEIGHBORAS REFLECTOR DEPEND DOWN SOFTRECONFIG -+%token DUMP IN OUT SOCKET RESTRICTED - %token LOG ROUTECOLL TRANSPARENT - %token TCP MD5SIG PASSWORD KEY TTLSECURITY - %token ALLOW DENY MATCH - %token QUICK - %token FROM TO ANY - %token CONNECTED STATIC --%token PREFIX PREFIXLEN SOURCEAS TRANSITAS PEERAS COMMUNITY DELETE -+%token COMMUNITY EXTCOMMUNITY -+%token PREFIX PREFIXLEN SOURCEAS TRANSITAS PEERAS DELETE MAXASLEN MAXASSEQ - %token SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF --%token PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL -+%token PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN - %token ERROR INCLUDE - %token IPSEC ESP AH SPI IKE - %token IPV4 IPV6 - %token QUALIFY VIA -+%token NE LE GE XRANGE - %token <v.string> STRING - %token <v.number> NUMBER --%type <v.number> asnumber as4number optnumber yesno inout --%type <v.number> espah family restart -+%type <v.number> asnumber as4number optnumber -+%type <v.number> espah family restart origincode nettype -+%type <v.number> yesno inout restricted - %type <v.string> string filter_rib - %type <v.addr> address - %type <v.prefix> prefix addrspec -@@ -204,6 +218,7 @@ grammar : /* empty */ - | grammar include '\n' - | grammar conf_main '\n' - | grammar varset '\n' -+ | grammar rdomain '\n' - | grammar neighbor '\n' - | grammar group '\n' - | grammar filterrule '\n' -@@ -211,8 +226,12 @@ grammar : /* empty */ - ; - - asnumber : NUMBER { -- if ($1 < 0 || $1 >= ASNUM_MAX) { -- yyerror("AS too big: max %u", ASNUM_MAX - 1); -+ /* -+ * Accroding to iana 65535 and 4294967295 are reserved -+ * but enforcing this is not duty of the parser. -+ */ -+ if ($1 < 0 || $1 > UINT_MAX) { -+ yyerror("AS too big: max %u", UINT_MAX); - YYERROR; - } - } -@@ -274,6 +293,8 @@ yesno : STRING { - else if (!strcmp($1, "no")) - $$ = 0; - else { -+ yyerror("syntax error, " -+ "either yes or no expected"); - free($1); - YYERROR; - } -@@ -318,7 +339,7 @@ conf_main : AS as4number { - conf->short_as = $3; - } - | ROUTERID address { -- if ($2.af != AF_INET) { -+ if ($2.aid != AID_INET) { - yyerror("router-id must be an IPv4 address"); - YYERROR; - } -@@ -342,42 +363,25 @@ conf_main : AS as4number { - } - | LISTEN ON address { - struct listen_addr *la; -- struct sockaddr_in *in; -- struct sockaddr_in6 *in6; - - if ((la = calloc(1, sizeof(struct listen_addr))) == - NULL) - fatal("parse conf_main listen on calloc"); - - la->fd = -1; -- la->sa.ss_family = $3.af; -- switch ($3.af) { -- case AF_INET: -- la->sa.ss_len = sizeof(struct sockaddr_in); -- in = (struct sockaddr_in *)&la->sa; -- in->sin_addr.s_addr = $3.v4.s_addr; -- in->sin_port = htons(BGP_PORT); -- break; -- case AF_INET6: -- la->sa.ss_len = sizeof(struct sockaddr_in6); -- in6 = (struct sockaddr_in6 *)&la->sa; -- memcpy(&in6->sin6_addr, &$3.v6, -- sizeof(in6->sin6_addr)); -- in6->sin6_port = htons(BGP_PORT); -- break; -- default: -- yyerror("king bula does not like family %u", -- $3.af); -- YYERROR; -- } -- -+ memcpy(&la->sa, addr2sa(&$3, BGP_PORT), sizeof(la->sa)); - TAILQ_INSERT_TAIL(listen_addrs, la, entry); - } - | FIBUPDATE yesno { -+ struct rde_rib *rr; -+ rr = find_rib("Loc-RIB"); -+ if (rr == NULL) -+ fatalx("RTABLE can not find the main RIB!"); -+ - if ($2 == 0) -- conf->flags |= BGPD_FLAG_NO_FIB_UPDATE; -+ rr->flags |= F_RIB_NOFIBSYNC; - else -- conf->flags &= ~BGPD_FLAG_NO_FIB_UPDATE; -+ rr->flags &= ~F_RIB_NOFIBSYNC; - } - | ROUTECOLL yesno { - if ($2 == 1) -@@ -386,7 +390,7 @@ conf_main : AS as4number { - conf->flags &= ~BGPD_FLAG_NO_EVALUATE; - } - | RDE RIB STRING { -- if (add_rib($3, F_RIB_NOFIB)) { -+ if (add_rib($3, 0, F_RIB_NOFIB)) { - free($3); - YYERROR; - } -@@ -395,9 +399,27 @@ conf_main : AS as4number { - | RDE RIB STRING yesno EVALUATE { - if ($4) { - free($3); -+ yyerror("bad rde rib definition"); - YYERROR; - } -- if (!add_rib($3, F_RIB_NOEVALUATE)) { -+ if (add_rib($3, 0, F_RIB_NOFIB | F_RIB_NOEVALUATE)) { -+ free($3); -+ YYERROR; -+ } -+ free($3); -+ } -+ | RDE RIB STRING RTABLE NUMBER { -+ if (add_rib($3, $5, 0)) { -+ free($3); -+ YYERROR; -+ } -+ free($3); -+ } -+ | RDE RIB STRING RTABLE NUMBER FIBUPDATE yesno { -+ int flags = 0; -+ if ($7 == 0) -+ flags = F_RIB_NOFIBSYNC; -+ if (add_rib($3, $5, flags)) { - free($3); - YYERROR; - } -@@ -418,59 +440,7 @@ conf_main : AS as4number { - } - free($2); - } -- | NETWORK prefix filter_set { -- struct network *n; -- -- if ((n = calloc(1, sizeof(struct network))) == NULL) -- fatal("new_network"); -- memcpy(&n->net.prefix, &$2.prefix, -- sizeof(n->net.prefix)); -- n->net.prefixlen = $2.len; -- move_filterset($3, &n->net.attrset); -- free($3); -- -- TAILQ_INSERT_TAIL(netconf, n, entry); -- } -- | NETWORK family STATIC filter_set { -- if ($2 == AFI_IPv4) { -- conf->flags |= BGPD_FLAG_REDIST_STATIC; -- move_filterset($4, &conf->staticset); -- } else if ($2 == AFI_IPv6) { -- conf->flags |= BGPD_FLAG_REDIST6_STATIC; -- move_filterset($4, &conf->staticset6); -- } else { -- yyerror("unknown family"); -- free($4); -- YYERROR; -- } -- free($4); -- } -- | NETWORK family CONNECTED filter_set { -- if ($2 == AFI_IPv4) { -- conf->flags |= BGPD_FLAG_REDIST_CONNECTED; -- move_filterset($4, &conf->connectset); -- } else if ($2 == AFI_IPv6) { -- conf->flags |= BGPD_FLAG_REDIST6_CONNECTED; -- move_filterset($4, &conf->connectset6); -- } else { -- yyerror("unknown family"); -- free($4); -- YYERROR; -- } -- free($4); -- } -- | NETWORK STATIC filter_set { -- /* keep for compatibility till after next release */ -- conf->flags |= BGPD_FLAG_REDIST_STATIC; -- move_filterset($3, &conf->staticset); -- free($3); -- } -- | NETWORK CONNECTED filter_set { -- /* keep for compatibility till after next release */ -- conf->flags |= BGPD_FLAG_REDIST_CONNECTED; -- move_filterset($3, &conf->connectset); -- free($3); -- } -+ | network - | DUMP STRING STRING optnumber { - int action; - -@@ -484,6 +454,8 @@ conf_main : AS as4number { - action = MRT_TABLE_DUMP; - else if (!strcmp($2, "table-mp")) - action = MRT_TABLE_DUMP_MP; -+ else if (!strcmp($2, "table-v2")) -+ action = MRT_TABLE_DUMP_V2; - else { - yyerror("unknown mrt dump type"); - free($2); -@@ -511,6 +483,8 @@ conf_main : AS as4number { - action = MRT_TABLE_DUMP; - else if (!strcmp($4, "table-mp")) - action = MRT_TABLE_DUMP_MP; -+ else if (!strcmp($4, "table-v2")) -+ action = MRT_TABLE_DUMP_V2; - else { - yyerror("unknown mrt dump type"); - free($3); -@@ -575,11 +549,20 @@ conf_main : AS as4number { - free($4); - } - | RTABLE NUMBER { -- if ($2 > RT_TABLEID_MAX || $2 < 0) { -- yyerror("invalid rtable id"); -+#if defined(__FreeBSD__) /* FreeBSD does not support RTABLE */ -+ yyerror("rtable id not supported in FreeBSD, yet"); -+ YYERROR; -+#else -+ struct rde_rib *rr; -+ if (ktable_exists($2, NULL) != 1) { -+ yyerror("rtable id %lld does not exist", $2); - YYERROR; - } -- conf->rtableid = $2; -+ rr = find_rib("Loc-RIB"); -+ if (rr == NULL) -+ fatalx("RTABLE can not find the main RIB!"); -+ rr->rtableid = $2; -+#endif /* defined(__FreeBSD__) */ - } - | CONNECTRETRY NUMBER { - if ($2 > USHRT_MAX || $2 < 1) { -@@ -588,6 +571,15 @@ conf_main : AS as4number { - } - conf->connectretry = $2; - } -+ | SOCKET STRING restricted { -+ if ($3) { -+ free(conf->rcsock); -+ conf->rcsock = $2; -+ } else { -+ free(conf->csock); -+ conf->csock = $2; -+ } -+ } - ; - - mrtdump : DUMP STRING inout STRING optnumber { -@@ -620,10 +612,47 @@ mrtdump : DUMP STRING inout STRING optn - } - ; - -+network : NETWORK prefix filter_set { -+ struct network *n; -+ -+ if ((n = calloc(1, sizeof(struct network))) == NULL) -+ fatal("new_network"); -+ memcpy(&n->net.prefix, &$2.prefix, -+ sizeof(n->net.prefix)); -+ n->net.prefixlen = $2.len; -+ filterset_move($3, &n->net.attrset); -+ free($3); -+ -+ TAILQ_INSERT_TAIL(netconf, n, entry); -+ } -+ | NETWORK family nettype filter_set { -+ struct network *n; -+ -+ if ((n = calloc(1, sizeof(struct network))) == NULL) -+ fatal("new_network"); -+ if (afi2aid($2, SAFI_UNICAST, &n->net.prefix.aid) == -+ -1) { -+ yyerror("unknown family"); -+ filterset_free($4); -+ free($4); -+ YYERROR; -+ } -+ n->net.type = $3 ? NETWORK_STATIC : NETWORK_CONNECTED; -+ filterset_move($4, &n->net.attrset); -+ free($4); -+ -+ TAILQ_INSERT_TAIL(netconf, n, entry); -+ } -+ ; -+ - inout : IN { $$ = 1; } - | OUT { $$ = 0; } - ; - -+restricted : RESTRICTED { $$ = 1; } -+ | /* nothing */ { $$ = 0; } -+ ; -+ - address : STRING { - u_int8_t len; - -@@ -635,11 +664,11 @@ address : STRING { - } - free($1); - -- if (($$.af == AF_INET && len != 32) || -- ($$.af == AF_INET6 && len != 128)) { -+ if (($$.aid == AID_INET && len != 32) || -+ ($$.aid == AID_INET6 && len != 128)) { - /* unreachable */ - yyerror("got prefixlen %u, expected %u", -- len, $$.af == AF_INET ? 32 : 128); -+ len, $$.aid == AID_INET ? 32 : 128); - YYERROR; - } - } -@@ -653,7 +682,7 @@ prefix : STRING '/' NUMBER { - free($1); - YYERROR; - } -- if (asprintf(&s, "%s/%lld", $1, $3) == -1) -+ if (asprintf(&s, "%s/%lld", $1, (long long int)$3) == -1) - fatal(NULL); - free($1); - -@@ -672,7 +701,7 @@ prefix : STRING '/' NUMBER { - yyerror("bad prefix %lld/%lld", $1, $3); - YYERROR; - } -- if (asprintf(&s, "%lld/%lld", $1, $3) == -1) -+ if (asprintf(&s, "%lld/%lld", (long long int)$1, (long long int)$3) == -1) - fatal(NULL); - - if (!host(s, &$$.prefix, &$$.len)) { -@@ -686,7 +715,7 @@ prefix : STRING '/' NUMBER { - - addrspec : address { - memcpy(&$$.prefix, &$1, sizeof(struct bgpd_addr)); -- if ($$.prefix.af == AF_INET) -+ if ($$.prefix.aid == AID_INET) - $$.len = 32; - else - $$.len = 128; -@@ -705,14 +734,150 @@ optnumber : /* empty */ { $$ = 0; } - | NUMBER - ; - -+rdomain : RDOMAIN NUMBER optnl '{' optnl { -+ if (ktable_exists($2, NULL) != 1) { -+ yyerror("rdomain %lld does not exist", $2); -+ YYERROR; -+ } -+ if (!(currdom = calloc(1, sizeof(struct rdomain)))) -+ fatal(NULL); -+ currdom->rtableid = $2; -+ TAILQ_INIT(&currdom->import); -+ TAILQ_INIT(&currdom->export); -+ TAILQ_INIT(&currdom->net_l); -+ netconf = &currdom->net_l; -+ } -+ rdomainopts_l '}' { -+ /* insert into list */ -+ SIMPLEQ_INSERT_TAIL(rdom_l, currdom, entry); -+ currdom = NULL; -+ netconf = gnetconf; -+ } -+ -+rdomainopts_l : rdomainopts_l rdomainoptsl -+ | rdomainoptsl -+ ; -+ -+rdomainoptsl : rdomainopts nl -+ ; -+ -+rdomainopts : RD STRING { -+ struct filter_extcommunity ext; -+ u_int64_t rd; -+ -+ if (parseextcommunity(&ext, "rt", $2) == -1) { -+ free($2); -+ YYERROR; -+ } -+ free($2); -+ /* -+ * RD is almost encode like an ext-community, -+ * but only almost so convert here. -+ */ -+ if (community_ext_conv(&ext, 0, &rd)) { -+ yyerror("bad encoding of rd"); -+ YYERROR; -+ } -+ rd = betoh64(rd) & 0xffffffffffffULL; -+ switch (ext.type) { -+ case EXT_COMMUNITY_TWO_AS: -+ rd |= (0ULL << 48); -+ break; -+ case EXT_COMMUNITY_IPV4: -+ rd |= (1ULL << 48); -+ break; -+ case EXT_COMMUNITY_FOUR_AS: -+ rd |= (2ULL << 48); -+ break; -+ default: -+ yyerror("bad encoding of rd"); -+ YYERROR; -+ } -+ currdom->rd = htobe64(rd); -+ } -+ | EXPORTTRGT STRING STRING { -+ struct filter_set *set; -+ -+ if ((set = calloc(1, sizeof(struct filter_set))) == -+ NULL) -+ fatal(NULL); -+ set->type = ACTION_SET_EXT_COMMUNITY; -+ if (parseextcommunity(&set->action.ext_community, -+ $2, $3) == -1) { -+ free($3); -+ free($2); -+ free(set); -+ YYERROR; -+ } -+ free($3); -+ free($2); -+ TAILQ_INSERT_TAIL(&currdom->export, set, entry); -+ } -+ | IMPORTTRGT STRING STRING { -+ struct filter_set *set; -+ -+ if ((set = calloc(1, sizeof(struct filter_set))) == -+ NULL) -+ fatal(NULL); -+ set->type = ACTION_SET_EXT_COMMUNITY; -+ if (parseextcommunity(&set->action.ext_community, -+ $2, $3) == -1) { -+ free($3); -+ free($2); -+ free(set); -+ YYERROR; -+ } -+ free($3); -+ free($2); -+ TAILQ_INSERT_TAIL(&currdom->import, set, entry); -+ } -+ | DESCR string { -+ if (strlcpy(currdom->descr, $2, -+ sizeof(currdom->descr)) >= -+ sizeof(currdom->descr)) { -+ yyerror("descr \"%s\" too long: max %u", -+ $2, sizeof(currdom->descr) - 1); -+ free($2); -+ YYERROR; -+ } -+ free($2); -+ } -+ | FIBUPDATE yesno { -+ if ($2 == 0) -+ currdom->flags |= F_RIB_NOFIBSYNC; -+ else -+ currdom->flags &= ~F_RIB_NOFIBSYNC; -+ } -+ | network -+ | DEPEND ON STRING { -+ /* XXX this is a hack */ -+ if (if_nametoindex($3) == 0) { -+ yyerror("interface %s does not exist", $3); -+ free($3); -+ YYERROR; -+ } -+ strlcpy(currdom->ifmpe, $3, IFNAMSIZ); -+ free($3); -+ if (get_mpe_label(currdom)) { -+ yyerror("failed to get mpls label from %s", -+ currdom->ifmpe); -+ YYERROR; -+ } -+ } -+ ; -+ - neighbor : { curpeer = new_peer(); } - NEIGHBOR addrspec { - memcpy(&curpeer->conf.remote_addr, &$3.prefix, - sizeof(curpeer->conf.remote_addr)); - curpeer->conf.remote_masklen = $3.len; -- if (($3.prefix.af == AF_INET && $3.len != 32) || -- ($3.prefix.af == AF_INET6 && $3.len != 128)) -+ if (($3.prefix.aid == AID_INET && $3.len != 32) || -+ ($3.prefix.aid == AID_INET6 && $3.len != 128)) - curpeer->conf.template = 1; -+ if (curpeer->conf.capabilities.mp[ -+ curpeer->conf.remote_addr.aid] == -1) -+ curpeer->conf.capabilities.mp[ -+ curpeer->conf.remote_addr.aid] = 1; - if (get_id(curpeer)) { - yyerror("get_id failed"); - YYERROR; -@@ -802,6 +967,17 @@ peeropts : REMOTEAS as4number { - } - free($2); - } -+ | LLIFACE string { -+ if (strlcpy(curpeer->conf.lliface, $2, -+ sizeof(curpeer->conf.lliface)) >= -+ sizeof(curpeer->conf.lliface)) { -+ yyerror("lliface \"%s\" too long: max %u", -+ $2, sizeof(curpeer->conf.lliface) - 1); -+ free($2); -+ YYERROR; -+ } -+ free($2); -+ } - | LOCALADDR address { - memcpy(&curpeer->conf.local_addr, &$2, - sizeof(curpeer->conf.local_addr)); -@@ -852,13 +1028,17 @@ peeropts : REMOTEAS as4number { - curpeer->conf.min_holdtime = $3; - } - | ANNOUNCE family STRING { -- u_int8_t safi; -+ u_int8_t aid, safi; -+ int8_t val = 1; - -- if (!strcmp($3, "none")) -- safi = SAFI_NONE; -- else if (!strcmp($3, "unicast")) -+ if (!strcmp($3, "none")) { - safi = SAFI_UNICAST; -- else { -+ val = 0; -+ } else if (!strcmp($3, "unicast")) { -+ safi = SAFI_UNICAST; -+ } else if (!strcmp($3, "vpn")) { -+ safi = SAFI_MPLSVPN; -+ } else { - yyerror("unknown/unsupported SAFI \"%s\"", - $3); - free($3); -@@ -866,25 +1046,31 @@ peeropts : REMOTEAS as4number { - } - free($3); - -- switch ($2) { -- case AFI_IPv4: -- curpeer->conf.capabilities.mp_v4 = safi; -- break; -- case AFI_IPv6: -- curpeer->conf.capabilities.mp_v6 = safi; -- break; -- default: -- fatal("king bula sees borked AFI"); -+ if (afi2aid($2, safi, &aid) == -1) { -+ yyerror("unknown AFI/SAFI pair"); -+ YYERROR; - } -+ curpeer->conf.capabilities.mp[aid] = val; - } - | ANNOUNCE CAPABILITIES yesno { - curpeer->conf.announce_capa = $3; - } -+ | ANNOUNCE REFRESH yesno { -+ curpeer->conf.capabilities.refresh = $3; -+ } -+ | ANNOUNCE RESTART yesno { -+ curpeer->conf.capabilities.grestart.restart = $3; -+ } -+ | ANNOUNCE AS4BYTE yesno { -+ curpeer->conf.capabilities.as4byte = $3; -+ } - | ANNOUNCE SELF { - curpeer->conf.announce_type = ANNOUNCE_SELF; - } - | ANNOUNCE STRING { -- if (!strcmp($2, "none")) -+ if (!strcmp($2, "self")) -+ curpeer->conf.announce_type = ANNOUNCE_SELF; -+ else if (!strcmp($2, "none")) - curpeer->conf.announce_type = ANNOUNCE_NONE; - else if (!strcmp($2, "all")) - curpeer->conf.announce_type = ANNOUNCE_ALL; -@@ -1083,7 +1269,7 @@ peeropts : REMOTEAS as4number { - curpeer->conf.reflector_client = 1; - } - | REFLECTOR address { -- if ($2.af != AF_INET) { -+ if ($2.aid != AID_INET) { - yyerror("route reflector cluster-id must be " - "an IPv4 address"); - YYERROR; -@@ -1157,6 +1343,10 @@ family : IPV4 { $$ = AFI_IPv4; } - | IPV6 { $$ = AFI_IPv6; } - ; - -+nettype : STATIC { $$ = 1; }, -+ | CONNECTED { $$ = 0; } -+ ; -+ - espah : ESP { $$ = 1; } - | AH { $$ = 0; } - ; -@@ -1336,12 +1526,12 @@ filter_prefix_l : filter_prefix { $$ - ; - - filter_prefix : prefix { -- if (fmopts.af && fmopts.af != $1.prefix.af) { -+ if (fmopts.aid && fmopts.aid != $1.prefix.aid) { - yyerror("rules with mixed address families " - "are not allowed"); - YYERROR; - } else -- fmopts.af = $1.prefix.af; -+ fmopts.aid = $1.prefix.aid; - if (($$ = calloc(1, sizeof(struct filter_prefix_l))) == - NULL) - fatal(NULL); -@@ -1410,6 +1600,12 @@ filter_as : as4number { - fatal(NULL); - $$->a.as = $1; - } -+ | NEIGHBORAS { -+ if (($$ = calloc(1, sizeof(struct filter_as_l))) == -+ NULL) -+ fatal(NULL); -+ $$->a.flags = AS_FLAG_NEIGHBORAS; -+ } - ; - - filter_match_h : /* empty */ { -@@ -1437,18 +1633,18 @@ filter_elm : filter_prefix_h { - fmopts.prefix_l = $1; - } - | PREFIXLEN prefixlenop { -- if (fmopts.af == 0) { -+ if (fmopts.aid == 0) { - yyerror("address family needs to be specified " - "before \"prefixlen\""); - YYERROR; - } -- if (fmopts.m.prefixlen.af) { -+ if (fmopts.m.prefixlen.aid) { - yyerror("\"prefixlen\" already specified"); - YYERROR; - } - memcpy(&fmopts.m.prefixlen, &$2, - sizeof(fmopts.m.prefixlen)); -- fmopts.m.prefixlen.af = fmopts.af; -+ fmopts.m.prefixlen.aid = fmopts.aid; - } - | filter_as_h { - if (fmopts.as_l != NULL) { -@@ -1457,32 +1653,93 @@ filter_elm : filter_prefix_h { - } - fmopts.as_l = $1; - } -+ | MAXASLEN NUMBER { -+ if (fmopts.m.aslen.type != ASLEN_NONE) { -+ yyerror("AS length filters already specified"); -+ YYERROR; -+ } -+ if ($2 < 0 || $2 > UINT_MAX) { -+ yyerror("bad max-as-len %lld", $2); -+ YYERROR; -+ } -+ fmopts.m.aslen.type = ASLEN_MAX; -+ fmopts.m.aslen.aslen = $2; -+ } -+ | MAXASSEQ NUMBER { -+ if (fmopts.m.aslen.type != ASLEN_NONE) { -+ yyerror("AS length filters already specified"); -+ YYERROR; -+ } -+ if ($2 < 0 || $2 > UINT_MAX) { -+ yyerror("bad max-as-seq %lld", $2); -+ YYERROR; -+ } -+ fmopts.m.aslen.type = ASLEN_SEQ; -+ fmopts.m.aslen.aslen = $2; -+ } - | COMMUNITY STRING { - if (fmopts.m.community.as != COMMUNITY_UNSET) { - yyerror("\"community\" already specified"); - free($2); - YYERROR; - } -- if (parsecommunity($2, &fmopts.m.community.as, -- &fmopts.m.community.type) == -1) { -+ if (parsecommunity(&fmopts.m.community, $2) == -1) { - free($2); - YYERROR; - } - free($2); - } -+ | EXTCOMMUNITY STRING STRING { -+ if (fmopts.m.ext_community.flags & -+ EXT_COMMUNITY_FLAG_VALID) { -+ yyerror("\"ext-community\" already specified"); -+ free($2); -+ free($3); -+ YYERROR; -+ } -+ -+ if (parseextcommunity(&fmopts.m.ext_community, -+ $2, $3) == -1) { -+ free($2); -+ free($3); -+ YYERROR; -+ } -+ free($2); -+ free($3); -+ } - | IPV4 { -- if (fmopts.af) { -+ if (fmopts.aid) { - yyerror("address family already specified"); - YYERROR; - } -- fmopts.af = AF_INET; -+ fmopts.aid = AID_INET; - } - | IPV6 { -- if (fmopts.af) { -+ if (fmopts.aid) { - yyerror("address family already specified"); - YYERROR; - } -- fmopts.af = AF_INET6; -+ fmopts.aid = AID_INET6; -+ } -+ | NEXTHOP address { -+ if (fmopts.m.nexthop.flags) { -+ yyerror("nexthop already specified"); -+ YYERROR; -+ } -+ if (fmopts.aid && fmopts.aid != $2.aid) { -+ yyerror("nexthop address family doesn't match " -+ "rule address family"); -+ YYERROR; -+ } -+ fmopts.m.nexthop.addr = $2; -+ fmopts.m.nexthop.flags = FILTER_NEXTHOP_ADDR; -+ } -+ | NEXTHOP NEIGHBOR { -+ if (fmopts.m.nexthop.flags) { -+ yyerror("nexthop already specified"); -+ YYERROR; -+ } -+ fmopts.m.nexthop.flags = FILTER_NEXTHOP_NEIGHBOR; - } - ; - -@@ -1588,7 +1845,7 @@ filter_set_opt : LOCALPREF NUMBER { - } - if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) - fatal(NULL); -- if ($2 > 0) { -+ if ($2 >= 0) { - $$->type = ACTION_SET_MED; - $$->action.metric = $2; - } else { -@@ -1623,7 +1880,7 @@ filter_set_opt : LOCALPREF NUMBER { - } - if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) - fatal(NULL); -- if ($2 > 0) { -+ if ($2 >= 0) { - $$->type = ACTION_SET_MED; - $$->action.metric = $2; - } else { -@@ -1782,8 +2039,7 @@ filter_set_opt : LOCALPREF NUMBER { - else - $$->type = ACTION_SET_COMMUNITY; - -- if (parsecommunity($3, &$$->action.community.as, -- &$$->action.community.type) == -1) { -+ if (parsecommunity(&$$->action.community, $3) == -1) { - free($3); - free($$); - YYERROR; -@@ -1796,40 +2052,62 @@ filter_set_opt : LOCALPREF NUMBER { - free($$); - YYERROR; - } -- /* Don't allow setting of unknown well-known types */ -- if ($$->action.community.as == COMMUNITY_WELLKNOWN) { -- switch ($$->action.community.type) { -- case COMMUNITY_NO_EXPORT: -- case COMMUNITY_NO_ADVERTISE: -- case COMMUNITY_NO_EXPSUBCONFED: -- case COMMUNITY_NO_PEER: -- /* valid */ -- break; -- default: -- /* unknown */ -- yyerror("Invalid well-known community"); -- free($$); -- YYERROR; -- break; -- } -+ } -+ | EXTCOMMUNITY delete STRING STRING { -+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) -+ fatal(NULL); -+ if ($2) -+ $$->type = ACTION_DEL_EXT_COMMUNITY; -+ else -+ $$->type = ACTION_SET_EXT_COMMUNITY; -+ -+ if (parseextcommunity(&$$->action.ext_community, -+ $3, $4) == -1) { -+ free($3); -+ free($4); -+ free($$); -+ YYERROR; - } -+ free($3); -+ free($4); -+ } -+ | ORIGIN origincode { -+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) -+ fatal(NULL); -+ $$->type = ACTION_SET_ORIGIN; -+ $$->action.origin = $2; - } - ; - -+origincode : string { -+ if (!strcmp($1, "egp")) -+ $$ = ORIGIN_EGP; -+ else if (!strcmp($1, "igp")) -+ $$ = ORIGIN_IGP; -+ else if (!strcmp($1, "incomplete")) -+ $$ = ORIGIN_INCOMPLETE; -+ else { -+ yyerror("unknown origin \"%s\"", $1); -+ free($1); -+ YYERROR; -+ } -+ free($1); -+ }; -+ - comma : "," - | /* empty */ - ; - - unaryop : '=' { $$ = OP_EQ; } -- | '!' '=' { $$ = OP_NE; } -- | '<' '=' { $$ = OP_LE; } -+ | NE { $$ = OP_NE; } -+ | LE { $$ = OP_LE; } - | '<' { $$ = OP_LT; } -- | '>' '=' { $$ = OP_GE; } -+ | GE { $$ = OP_GE; } - | '>' { $$ = OP_GT; } - ; - - binaryop : '-' { $$ = OP_RANGE; } -- | '>' '<' { $$ = OP_XRANGE; } -+ | XRANGE { $$ = OP_XRANGE; } - ; - - %% -@@ -1873,6 +2151,7 @@ lookup(char *s) - { "allow", ALLOW}, - { "announce", ANNOUNCE}, - { "any", ANY}, -+ { "as-4byte", AS4BYTE }, - { "blackhole", BLACKHOLE}, - { "capabilities", CAPABILITIES}, - { "community", COMMUNITY}, -@@ -1889,16 +2168,22 @@ lookup(char *s) - { "enforce", ENFORCE}, - { "esp", ESP}, - { "evaluate", EVALUATE}, -+ { "export-target", EXPORTTRGT}, -+ { "ext-community", EXTCOMMUNITY}, - { "fib-update", FIBUPDATE}, - { "from", FROM}, - { "group", GROUP}, - { "holdtime", HOLDTIME}, - { "ignore", IGNORE}, - { "ike", IKE}, -+ { "import-target", IMPORTTRGT}, - { "in", IN}, - { "include", INCLUDE}, - { "inet", IPV4}, - { "inet6", IPV6}, -+#if defined(IPV6_LINKLOCAL_PEER) -+ { "interface", LLIFACE}, -+#endif - { "ipsec", IPSEC}, - { "key", KEY}, - { "listen", LISTEN}, -@@ -1906,6 +2191,8 @@ lookup(char *s) - { "localpref", LOCALPREF}, - { "log", LOG}, - { "match", MATCH}, -+ { "max-as-len", MAXASLEN}, -+ { "max-as-seq", MAXASSEQ}, - { "max-prefix", MAXPREFIX}, - { "md5sig", MD5SIG}, - { "med", MED}, -@@ -1918,6 +2205,7 @@ lookup(char *s) - { "nexthop", NEXTHOP}, - { "no-modify", NOMODIFY}, - { "on", ON}, -+ { "origin", ORIGIN}, - { "out", OUT}, - { "passive", PASSIVE}, - { "password", PASSWORD}, -@@ -1929,10 +2217,14 @@ lookup(char *s) - { "prepend-self", PREPEND_SELF}, - { "qualify", QUALIFY}, - { "quick", QUICK}, -+ { "rd", RD}, - { "rde", RDE}, -+ { "rdomain", RDOMAIN}, -+ { "refresh", REFRESH }, - { "reject", REJECT}, - { "remote-as", REMOTEAS}, - { "restart", RESTART}, -+ { "restricted", RESTRICTED}, - { "rib", RIB}, - { "route-collector", ROUTECOLL}, - { "route-reflector", REFLECTOR}, -@@ -1941,6 +2233,7 @@ lookup(char *s) - { "rtlabel", RTLABEL}, - { "self", SELF}, - { "set", SET}, -+ { "socket", SOCKET }, - { "softreconfig", SOFTRECONFIG}, - { "source-as", SOURCEAS}, - { "spi", SPI}, -@@ -2117,9 +2410,10 @@ top: - return (0); - if (next == quotec || c == ' ' || c == '\t') - c = next; -- else if (next == '\n') -+ else if (next == '\n') { -+ file->lineno++; - continue; -- else -+ } else - lungetc(next); - } else if (c == quotec) { - *p = '\0'; -@@ -2135,6 +2429,26 @@ top: - if (yylval.v.string == NULL) - fatal("yylex: strdup"); - return (STRING); -+ case '!': -+ next = lgetc(0); -+ if (next == '=') -+ return (NE); -+ lungetc(next); -+ break; -+ case '<': -+ next = lgetc(0); -+ if (next == '=') -+ return (LE); -+ lungetc(next); -+ break; -+ case '>': -+ next = lgetc(0); -+ if (next == '<') -+ return (XRANGE); -+ else if (next == '=') -+ return (GE); -+ lungetc(next); -+ break; - } - - #define allowed_to_end_number(x) \ -@@ -2274,18 +2588,21 @@ popfile(void) - int - parse_config(char *filename, struct bgpd_config *xconf, - struct mrt_head *xmconf, struct peer **xpeers, struct network_head *nc, -- struct filter_head *xfilter_l) -+ struct filter_head *xfilter_l, struct rdomain_head *xrdom_l) - { - struct sym *sym, *next; - struct peer *p, *pnext; - struct listen_addr *la; - struct network *n; - struct filter_rule *r; -+ struct rde_rib *rr; -+ struct rdomain *rd; - int errors = 0; - - if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL) - fatal(NULL); - conf->opts = xconf->opts; -+ conf->csock = strdup(SOCKET_NAME); - - if ((file = pushfile(filename, 1)) == NULL) { - free(conf); -@@ -2316,13 +2633,15 @@ parse_config(char *filename, struct bgpd - id = 1; - - /* network list is always empty in the parent */ -- netconf = nc; -+ gnetconf = netconf = nc; - TAILQ_INIT(netconf); - /* init the empty filter list for later */ - TAILQ_INIT(xfilter_l); -+ SIMPLEQ_INIT(xrdom_l); -+ rdom_l = xrdom_l; - -- add_rib("Adj-RIB-In", F_RIB_NOEVALUATE); -- add_rib("Loc-RIB", 0); -+ add_rib("Adj-RIB-In", 0, F_RIB_NOFIB | F_RIB_NOEVALUATE); -+ add_rib("Loc-RIB", 0, 0); - - yyparse(); - errors = file->errors; -@@ -2344,6 +2663,9 @@ parse_config(char *filename, struct bgpd - - if (errors) { - /* XXX more leaks in this case */ -+ free(conf->csock); -+ free(conf->rcsock); -+ - while ((la = TAILQ_FIRST(listen_addrs)) != NULL) { - TAILQ_REMOVE(listen_addrs, la, entry); - free(la); -@@ -2357,23 +2679,44 @@ parse_config(char *filename, struct bgpd - - while ((n = TAILQ_FIRST(netconf)) != NULL) { - TAILQ_REMOVE(netconf, n, entry); -+ filterset_free(&n->net.attrset); - free(n); - } - - while ((r = TAILQ_FIRST(filter_l)) != NULL) { - TAILQ_REMOVE(filter_l, r, entry); -+ filterset_free(&r->set); - free(r); - } - - while ((r = TAILQ_FIRST(peerfilter_l)) != NULL) { - TAILQ_REMOVE(peerfilter_l, r, entry); -+ filterset_free(&r->set); - free(r); - } - - while ((r = TAILQ_FIRST(groupfilter_l)) != NULL) { - TAILQ_REMOVE(groupfilter_l, r, entry); -+ filterset_free(&r->set); - free(r); - } -+ while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) { -+ SIMPLEQ_REMOVE_HEAD(&ribnames, entry); -+ free(rr); -+ } -+ while ((rd = SIMPLEQ_FIRST(rdom_l)) != NULL) { -+ SIMPLEQ_REMOVE_HEAD(rdom_l, entry); -+ filterset_free(&rd->export); -+ filterset_free(&rd->import); -+ -+ while ((n = TAILQ_FIRST(&rd->net_l)) != NULL) { -+ TAILQ_REMOVE(&rd->net_l, n, entry); -+ filterset_free(&n->net.attrset); -+ free(n); -+ } -+ -+ free(rd); -+ } - } else { - errors += merge_config(xconf, conf, peer_l, listen_addrs); - errors += mrt_mergeconfig(xmconf, mrtconf); -@@ -2505,27 +2848,27 @@ getcommunity(char *s) - } - - int --parsecommunity(char *s, int *as, int *type) -+parsecommunity(struct filter_community *c, char *s) - { - char *p; -- int i; -+ int i, as; - - /* Well-known communities */ - if (strcasecmp(s, "NO_EXPORT") == 0) { -- *as = COMMUNITY_WELLKNOWN; -- *type = COMMUNITY_NO_EXPORT; -+ c->as = COMMUNITY_WELLKNOWN; -+ c->type = COMMUNITY_NO_EXPORT; - return (0); - } else if (strcasecmp(s, "NO_ADVERTISE") == 0) { -- *as = COMMUNITY_WELLKNOWN; -- *type = COMMUNITY_NO_ADVERTISE; -+ c->as = COMMUNITY_WELLKNOWN; -+ c->type = COMMUNITY_NO_ADVERTISE; - return (0); - } else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) { -- *as = COMMUNITY_WELLKNOWN; -- *type = COMMUNITY_NO_EXPSUBCONFED; -+ c->as = COMMUNITY_WELLKNOWN; -+ c->type = COMMUNITY_NO_EXPSUBCONFED; - return (0); - } else if (strcasecmp(s, "NO_PEER") == 0) { -- *as = COMMUNITY_WELLKNOWN; -- *type = COMMUNITY_NO_PEER; -+ c->as = COMMUNITY_WELLKNOWN; -+ c->type = COMMUNITY_NO_PEER; - return (0); - } - -@@ -2537,23 +2880,176 @@ parsecommunity(char *s, int *as, int *ty - - if ((i = getcommunity(s)) == COMMUNITY_ERROR) - return (-1); -- if (i == USHRT_MAX) { -+ if (i == COMMUNITY_WELLKNOWN) { - yyerror("Bad community AS number"); - return (-1); - } -- *as = i; -+ as = i; - - if ((i = getcommunity(p)) == COMMUNITY_ERROR) - return (-1); -- *type = i; -+ c->as = as; -+ c->type = i; - - return (0); - } - -+int -+parsesubtype(char *type) -+{ -+ /* this has to be sorted always */ -+ static const struct keywords keywords[] = { -+ { "bdc", EXT_COMMUNITY_BGP_COLLECT }, -+ { "odi", EXT_COMMUNITY_OSPF_DOM_ID }, -+ { "ori", EXT_COMMUNITY_OSPF_RTR_ID }, -+ { "ort", EXT_COMMUNITY_OSPF_RTR_TYPE }, -+ { "rt", EXT_COMMUNITY_ROUTE_TGT }, -+ { "soo", EXT_CUMMUNITY_ROUTE_ORIG } -+ }; -+ const struct keywords *p; -+ -+ p = bsearch(type, keywords, sizeof(keywords)/sizeof(keywords[0]), -+ sizeof(keywords[0]), kw_cmp); -+ -+ if (p) -+ return (p->k_val); -+ else -+ return (-1); -+} -+ -+int -+parseextvalue(char *s, u_int32_t *v) -+{ -+ const char *errstr; -+ char *p; -+ struct in_addr ip; -+ u_int32_t uvalh = 0, uval; -+ -+ if ((p = strchr(s, '.')) == NULL) { -+ /* AS_PLAIN number (4 or 2 byte) */ -+ uval = strtonum(s, 0, UINT_MAX, &errstr); -+ if (errstr) { -+ yyerror("Bad ext-community %s is %s", s, errstr); -+ return (-1); -+ } -+ *v = uval; -+ if (uval > USHRT_MAX) -+ return (EXT_COMMUNITY_FOUR_AS); -+ else -+ return (EXT_COMMUNITY_TWO_AS); -+ } else if (strchr(p + 1, '.') == NULL) { -+ /* AS_DOT number (4-byte) */ -+ *p++ = '\0'; -+ uvalh = strtonum(s, 0, USHRT_MAX, &errstr); -+ if (errstr) { -+ yyerror("Bad ext-community %s is %s", s, errstr); -+ return (-1); -+ } -+ uval = strtonum(p, 0, USHRT_MAX, &errstr); -+ if (errstr) { -+ yyerror("Bad ext-community %s is %s", p, errstr); -+ return (-1); -+ } -+ *v = uval | (uvalh << 16); -+ return (EXT_COMMUNITY_FOUR_AS); -+ } else { -+ /* more then one dot -> IP address */ -+ if (inet_aton(s, &ip) == 0) { -+ yyerror("Bad ext-community %s not parseable", s); -+ return (-1); -+ } -+ *v = ip.s_addr; -+ return (EXT_COMMUNITY_IPV4); -+ } -+ return (-1); -+} -+ -+int -+parseextcommunity(struct filter_extcommunity *c, char *t, char *s) -+{ -+ const struct ext_comm_pairs iana[] = IANA_EXT_COMMUNITIES; -+ const char *errstr; -+ u_int64_t ullval = 0; -+ u_int32_t uval; -+ char *p, *ep; -+ unsigned int i; -+ int type, subtype; -+ -+ if ((subtype = parsesubtype(t)) == -1) { -+ yyerror("Bad ext-community unknown type"); -+ return (-1); -+ } -+ -+ if ((p = strchr(s, ':')) == NULL) { -+ type = EXT_COMMUNITY_OPAQUE, -+ errno = 0; -+ ullval = strtoull(s, &ep, 0); -+ if (s[0] == '\0' || *ep != '\0') { -+ yyerror("Bad ext-community bad value"); -+ return (-1); -+ } -+ if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) { -+ yyerror("Bad ext-community value to big"); -+ return (-1); -+ } -+ c->data.ext_opaq = ullval; -+ } else { -+ *p++ = '\0'; -+ if ((type = parseextvalue(s, &uval)) == -1) -+ return (-1); -+ switch (type) { -+ case EXT_COMMUNITY_TWO_AS: -+ ullval = strtonum(p, 0, UINT_MAX, &errstr); -+ break; -+ case EXT_COMMUNITY_IPV4: -+ case EXT_COMMUNITY_FOUR_AS: -+ ullval = strtonum(p, 0, USHRT_MAX, &errstr); -+ break; -+ default: -+ fatalx("parseextcommunity: unexpected result"); -+ } -+ if (errstr) { -+ yyerror("Bad ext-community %s is %s", p, -+ errstr); -+ return (-1); -+ } -+ switch (type) { -+ case EXT_COMMUNITY_TWO_AS: -+ c->data.ext_as.as = uval; -+ c->data.ext_as.val = ullval; -+ break; -+ case EXT_COMMUNITY_IPV4: -+ c->data.ext_ip.addr.s_addr = uval; -+ c->data.ext_ip.val = ullval; -+ break; -+ case EXT_COMMUNITY_FOUR_AS: -+ c->data.ext_as4.as4 = uval; -+ c->data.ext_as4.val = ullval; -+ break; -+ } -+ } -+ c->type = type; -+ c->subtype = subtype; -+ -+ /* verify type/subtype combo */ -+ for (i = 0; i < sizeof(iana)/sizeof(iana[0]); i++) { -+ if (iana[i].type == type && iana[i].subtype == subtype) { -+ if (iana[i].transitive) -+ c->type |= EXT_COMMUNITY_TRANSITIVE; -+ c->flags |= EXT_COMMUNITY_FLAG_VALID; -+ return (0); -+ } -+ } -+ -+ yyerror("Bad ext-community bad format for type"); -+ return (-1); -+} -+ - struct peer * - alloc_peer(void) - { - struct peer *p; -+ u_int8_t i; - - if ((p = calloc(1, sizeof(struct peer))) == NULL) - fatal("new_peer"); -@@ -2564,11 +3060,11 @@ alloc_peer(void) - p->conf.distance = 1; - p->conf.announce_type = ANNOUNCE_UNDEF; - p->conf.announce_capa = 1; -- p->conf.capabilities.mp_v4 = SAFI_UNICAST; -- p->conf.capabilities.mp_v6 = SAFI_NONE; -+ for (i = 0; i < AID_MAX; i++) -+ p->conf.capabilities.mp[i] = -1; - p->conf.capabilities.refresh = 1; -- p->conf.capabilities.restart = 0; -- p->conf.capabilities.as4byte = 0; -+ p->conf.capabilities.grestart.restart = 1; -+ p->conf.capabilities.as4byte = 1; - p->conf.local_as = conf->as; - p->conf.local_short_as = conf->short_as; - p->conf.softreconfig_in = 1; -@@ -2592,6 +3088,9 @@ new_peer(void) - if (strlcpy(p->conf.descr, curgroup->conf.descr, - sizeof(p->conf.descr)) >= sizeof(p->conf.descr)) - fatalx("new_peer descr strlcpy"); -+ if (strlcpy(p->conf.lliface, curgroup->conf.lliface, -+ sizeof(p->conf.lliface)) >= sizeof(p->conf.lliface)) -+ fatalx("new_peer lliface strlcpy"); - p->conf.groupid = curgroup->conf.id; - p->conf.local_as = curgroup->conf.local_as; - p->conf.local_short_as = curgroup->conf.local_short_as; -@@ -2674,39 +3173,52 @@ add_mrtconfig(enum mrt_type type, char * - } - - int --add_rib(char *name, u_int16_t flags) -+add_rib(char *name, u_int rtableid, u_int16_t flags) - { - struct rde_rib *rr; -+ u_int rdom; - -- if (find_rib(name)) { -- yyerror("rib \"%s\" allready exists.", name); -- return (-1); -- } -- -- if ((rr = calloc(1, sizeof(*rr))) == NULL) { -- log_warn("add_rib"); -- return (-1); -+ if ((rr = find_rib(name)) == NULL) { -+ if ((rr = calloc(1, sizeof(*rr))) == NULL) { -+ log_warn("add_rib"); -+ return (-1); -+ } - } - if (strlcpy(rr->name, name, sizeof(rr->name)) >= sizeof(rr->name)) { - yyerror("rib name \"%s\" too long: max %u", - name, sizeof(rr->name) - 1); -+ free(rr); - return (-1); - } - rr->flags |= flags; -+ if ((rr->flags & F_RIB_HASNOFIB) == 0) { -+ if (ktable_exists(rtableid, &rdom) != 1) { -+ yyerror("rtable id %lld does not exist", rtableid); -+ free(rr); -+ return (-1); -+ } -+ if (rdom != 0) { -+ yyerror("rtable %lld does not belong to rdomain 0", -+ rtableid); -+ free(rr); -+ return (-1); -+ } -+ rr->rtableid = rtableid; -+ } - SIMPLEQ_INSERT_TAIL(&ribnames, rr, entry); - return (0); - } - --int -+struct rde_rib * - find_rib(char *name) - { - struct rde_rib *rr; - - SIMPLEQ_FOREACH(rr, &ribnames, entry) { - if (!strcmp(rr->name, name)) -- return (1); -+ return (rr); - } -- return (0); -+ return (NULL); - } - - int -@@ -2715,7 +3227,7 @@ get_id(struct peer *newpeer) - struct peer *p; - - for (p = peer_l_old; p != NULL; p = p->next) -- if (newpeer->conf.remote_addr.af) { -+ if (newpeer->conf.remote_addr.aid) { - if (!memcmp(&p->conf.remote_addr, - &newpeer->conf.remote_addr, - sizeof(p->conf.remote_addr))) { -@@ -2856,9 +3368,11 @@ str2key(char *s, char *dest, size_t max_ - int - neighbor_consistent(struct peer *p) - { -+ u_int8_t i; -+ - /* local-address and peer's address: same address family */ -- if (p->conf.local_addr.af && -- p->conf.local_addr.af != p->conf.remote_addr.af) { -+ if (p->conf.local_addr.aid && -+ p->conf.local_addr.aid != p->conf.remote_addr.aid) { - yyerror("local-address and neighbor address " - "must be of the same address family"); - return (-1); -@@ -2869,7 +3383,7 @@ neighbor_consistent(struct peer *p) - p->conf.auth.method == AUTH_IPSEC_IKE_AH || - p->conf.auth.method == AUTH_IPSEC_MANUAL_ESP || - p->conf.auth.method == AUTH_IPSEC_MANUAL_AH) && -- !p->conf.local_addr.af) { -+ !p->conf.local_addr.aid) { - yyerror("neighbors with any form of IPsec configured " - "need local-address to be specified"); - return (-1); -@@ -2889,18 +3403,14 @@ neighbor_consistent(struct peer *p) - return (-1); - } - -- /* for testing: enable 4-byte AS number capability if necessary */ -- if (conf->as > USHRT_MAX || p->conf.remote_as > USHRT_MAX) -- p->conf.capabilities.as4byte = 1; -- - /* set default values if they where undefined */ - p->conf.ebgp = (p->conf.remote_as != conf->as); - if (p->conf.announce_type == ANNOUNCE_UNDEF) -- p->conf.announce_type = p->conf.ebgp == 0 ? -- ANNOUNCE_ALL : ANNOUNCE_SELF; -+ p->conf.announce_type = p->conf.ebgp ? -+ ANNOUNCE_SELF : ANNOUNCE_ALL; - if (p->conf.enforce_as == ENFORCE_AS_UNDEF) -- p->conf.enforce_as = p->conf.ebgp == 0 ? -- ENFORCE_AS_OFF : ENFORCE_AS_ON; -+ p->conf.enforce_as = p->conf.ebgp ? -+ ENFORCE_AS_ON : ENFORCE_AS_OFF; - - /* EBGP neighbors are not allowed in route reflector clusters */ - if (p->conf.reflector_client && p->conf.ebgp) { -@@ -2909,6 +3419,11 @@ neighbor_consistent(struct peer *p) - return (-1); - } - -+ /* the default MP capability is NONE */ -+ for (i = 0; i < AID_MAX; i++) -+ if (p->conf.capabilities.mp[i] == -1) -+ p->conf.capabilities.mp[i] = 0; -+ - return (0); - } - -@@ -2927,6 +3442,11 @@ merge_filterset(struct filter_set_head * - yyerror("community is already set"); - else if (s->type == ACTION_DEL_COMMUNITY) - yyerror("community will already be deleted"); -+ else if (s->type == ACTION_SET_EXT_COMMUNITY) -+ yyerror("ext-community is already set"); -+ else if (s->type == ACTION_DEL_EXT_COMMUNITY) -+ yyerror( -+ "ext-community will already be deleted"); - else - yyerror("redefining set parameter %s", - filterset_name(s->type)); -@@ -2953,9 +3473,18 @@ merge_filterset(struct filter_set_head * - return (0); - } - break; -+ case ACTION_SET_EXT_COMMUNITY: -+ case ACTION_DEL_EXT_COMMUNITY: -+ if (memcmp(&s->action.ext_community, -+ &t->action.ext_community, -+ sizeof(s->action.ext_community)) < 0) { -+ TAILQ_INSERT_BEFORE(t, s, entry); -+ return (0); -+ } -+ break; - case ACTION_SET_NEXTHOP: -- if (s->action.nexthop.af < -- t->action.nexthop.af) { -+ if (s->action.nexthop.aid < -+ t->action.nexthop.aid) { - TAILQ_INSERT_BEFORE(t, s, entry); - return (0); - } -@@ -2985,22 +3514,6 @@ copy_filterset(struct filter_set_head *s - } - } - --void --move_filterset(struct filter_set_head *source, struct filter_set_head *dest) --{ -- struct filter_set *s; -- -- TAILQ_INIT(dest); -- -- if (source == NULL) -- return; -- -- while ((s = TAILQ_FIRST(source)) != NULL) { -- TAILQ_REMOVE(source, s, entry); -- TAILQ_INSERT_TAIL(dest, s, entry); -- } --} -- - struct filter_rule * - get_rule(enum action_types type) - { |