summaryrefslogtreecommitdiff
path: root/net/openbgpd/files/patch-bgpd_parse.y
diff options
context:
space:
mode:
Diffstat (limited to 'net/openbgpd/files/patch-bgpd_parse.y')
-rw-r--r--net/openbgpd/files/patch-bgpd_parse.y1034
1 files changed, 665 insertions, 369 deletions
diff --git a/net/openbgpd/files/patch-bgpd_parse.y b/net/openbgpd/files/patch-bgpd_parse.y
index ac37d5be9483..4f60625dae3a 100644
--- a/net/openbgpd/files/patch-bgpd_parse.y
+++ b/net/openbgpd/files/patch-bgpd_parse.y
@@ -1,46 +1,45 @@
Index: bgpd/parse.y
===================================================================
RCS file: /home/cvs/private/hrs/openbgpd/bgpd/parse.y,v
-retrieving revision 1.1.1.1
-retrieving revision 1.6
-diff -u -p -r1.1.1.1 -r1.6
---- bgpd/parse.y 30 Jun 2009 05:46:15 -0000 1.1.1.1
-+++ bgpd/parse.y 22 Oct 2009 15:10:02 -0000 1.6
+retrieving revision 1.1.1.8
+retrieving revision 1.7
+diff -u -p -r1.1.1.8 -r1.7
+--- bgpd/parse.y 14 Feb 2010 20:19:57 -0000 1.1.1.8
++++ bgpd/parse.y 4 Feb 2010 16:22:23 -0000 1.7
@@ -1,4 +1,4 @@
--/* $OpenBSD: parse.y,v 1.217 2008/07/08 13:14:58 claudio Exp $ */
-+/* $OpenBSD: parse.y,v 1.233 2009/08/03 13:14:07 claudio Exp $ */
+-/* $OpenBSD: parse.y,v 1.231 2009/06/06 01:10:29 claudio Exp $ */
++/* $OpenBSD: parse.y,v 1.248 2010/01/13 06:02:37 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
-@@ -39,6 +39,7 @@
- #include "bgpd.h"
- #include "mrt.h"
- #include "session.h"
-+#include "rde.h"
+@@ -105,7 +105,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;
- TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
- static struct file {
-@@ -110,7 +111,10 @@ struct filter_match_l {
struct peer *alloc_peer(void);
- struct peer *new_peer(void);
- struct peer *new_group(void);
--int add_mrtconfig(enum mrt_type, char *, time_t, struct peer *);
-+int add_mrtconfig(enum mrt_type, char *, time_t, struct peer *,
+@@ -128,7 +128,11 @@ void move_filterset(struct filter_set_
+ 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 *);
-+int add_rib(char *, u_int16_t);
-+int 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 *);
-@@ -155,11 +159,11 @@ typedef struct {
- %}
+ typedef struct {
+ union {
+@@ -161,9 +165,9 @@ typedef struct {
%token AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE RTABLE
--%token RDE EVALUATE IGNORE COMPARE
-+%token RDE RIB EVALUATE IGNORE COMPARE
+ %token RDE RIB EVALUATE IGNORE COMPARE
%token GROUP NEIGHBOR NETWORK
-%token REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART
--%token ANNOUNCE DEMOTE
+-%token ANNOUNCE DEMOTE CONNECTRETRY
-%token ENFORCE NEIGHBORAS CAPABILITIES REFLECTOR DEPEND DOWN SOFTRECONFIG
+%token REMOTEAS DESCR LLIFACE LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART
+%token ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY
@@ -48,21 +47,35 @@ diff -u -p -r1.1.1.1 -r1.6
%token DUMP IN OUT
%token LOG ROUTECOLL TRANSPARENT
%token TCP MD5SIG PASSWORD KEY TTLSECURITY
-@@ -178,7 +182,7 @@ typedef struct {
+@@ -171,17 +175,19 @@ typedef struct {
+ %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
+ %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.string> string
-+%type <v.string> string filter_rib
+-%type <v.number> espah family restart
++%type <v.number> espah family restart origincode
+ %type <v.string> string filter_rib
%type <v.addr> address
%type <v.prefix> prefix addrspec
- %type <v.u8> action quick direction delete
-@@ -207,8 +211,12 @@ grammar : /* empty */
+@@ -211,8 +217,12 @@ grammar : /* empty */
;
asnumber : NUMBER {
-- if ($1 < 0 || $1 >= USHRT_MAX) {
-- yyerror("AS too big: max %u", USHRT_MAX - 1);
+- 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.
@@ -72,7 +85,7 @@ diff -u -p -r1.1.1.1 -r1.6
YYERROR;
}
}
-@@ -270,6 +278,8 @@ yesno : STRING {
+@@ -274,6 +284,8 @@ yesno : STRING {
else if (!strcmp($1, "no"))
$$ = 0;
else {
@@ -81,76 +94,62 @@ diff -u -p -r1.1.1.1 -r1.6
free($1);
YYERROR;
}
-@@ -381,6 +391,24 @@ conf_main : AS as4number {
- else
- conf->flags &= ~BGPD_FLAG_NO_EVALUATE;
+@@ -318,7 +330,7 @@ conf_main : AS as4number {
+ conf->short_as = $3;
}
-+ | RDE RIB STRING {
-+ if (add_rib($3, F_RIB_NOFIB)) {
-+ free($3);
-+ YYERROR;
-+ }
-+ free($3);
-+ }
-+ | RDE RIB STRING yesno EVALUATE {
-+ if ($4) {
-+ free($3);
-+ YYERROR;
-+ }
-+ if (!add_rib($3, F_RIB_NOFIB | F_RIB_NOEVALUATE)) {
-+ free($3);
-+ YYERROR;
-+ }
-+ free($3);
-+ }
- | TRANSPARENT yesno {
- if ($2 == 1)
- conf->flags |= BGPD_FLAG_DECISION_TRANS_AS;
-@@ -469,12 +497,42 @@ conf_main : AS as4number {
+ | ROUTERID address {
+- if ($2.af != AF_INET) {
++ if ($2.aid != AID_INET) {
+ yyerror("router-id must be an IPv4 address");
YYERROR;
}
- free($2);
-- if (add_mrtconfig(action, $3, $4, NULL) == -1) {
-+ if (add_mrtconfig(action, $3, $4, NULL, NULL) == -1) {
+@@ -342,35 +354,13 @@ 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 {
+@@ -397,7 +387,7 @@ conf_main : AS as4number {
free($3);
YYERROR;
}
- free($3);
- }
-+ | DUMP RIB STRING STRING STRING optnumber {
-+ int action;
-+
-+ if ($6 < 0 || $6 > UINT_MAX) {
-+ yyerror("bad timeout");
-+ free($3);
-+ free($4);
-+ free($5);
-+ YYERROR;
-+ }
-+ if (!strcmp($4, "table"))
-+ action = MRT_TABLE_DUMP;
-+ else if (!strcmp($4, "table-mp"))
-+ action = MRT_TABLE_DUMP_MP;
-+ else {
-+ yyerror("unknown mrt dump type");
-+ free($3);
-+ free($4);
-+ free($5);
-+ YYERROR;
-+ }
-+ free($4);
-+ if (add_mrtconfig(action, $5, $6, NULL, $3) == -1) {
-+ free($3);
-+ free($5);
-+ YYERROR;
-+ }
-+ free($3);
-+ free($5);
-+ }
- | mrtdump
- | RDE STRING EVALUATE {
- if (!strcmp($2, "route-age"))
-@@ -523,11 +581,23 @@ conf_main : AS as4number {
+- if (!add_rib($3, F_RIB_NOEVALUATE)) {
++ if (!add_rib($3, F_RIB_NOFIB | F_RIB_NOEVALUATE)) {
+ free($3);
+ YYERROR;
+ }
+@@ -575,11 +565,16 @@ conf_main : AS as4number {
free($4);
}
| RTABLE NUMBER {
@@ -164,48 +163,50 @@ diff -u -p -r1.1.1.1 -r1.6
}
conf->rtableid = $2;
+#endif /* defined(__FreeBSD__) */
-+ }
-+ | CONNECTRETRY NUMBER {
-+ if ($2 > USHRT_MAX || $2 < 1) {
-+ yyerror("invalid connect-retry");
-+ YYERROR;
-+ }
-+ conf->connectretry = $2;
}
- ;
+ | CONNECTRETRY NUMBER {
+ if ($2 > USHRT_MAX || $2 < 1) {
+@@ -635,11 +630,11 @@ address : STRING {
+ }
+ free($1);
-@@ -550,7 +620,8 @@ mrtdump : DUMP STRING inout STRING optn
- free($4);
+- 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;
}
-- if (add_mrtconfig(action, $4, $5, curpeer) == -1) {
-+ if (add_mrtconfig(action, $4, $5, curpeer, NULL) ==
-+ -1) {
- free($2);
- free($4);
- YYERROR;
-@@ -653,6 +724,20 @@ neighbor : { curpeer = new_peer(); }
- if (($3.prefix.af == AF_INET && $3.len != 32) ||
- ($3.prefix.af == AF_INET6 && $3.len != 128))
+ }
+@@ -686,7 +681,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;
+@@ -710,9 +705,13 @@ neighbor : { curpeer = new_peer(); }
+ 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;
-+ switch (curpeer->conf.remote_addr.af) {
-+ case AF_INET:
-+ if (curpeer->conf.capabilities.mp_v4 !=
-+ SAFI_ALL)
-+ break;
-+ curpeer->conf.capabilities.mp_v4 = SAFI_UNICAST;
-+ break;
-+ case AF_INET6:
-+ if (curpeer->conf.capabilities.mp_v6 !=
-+ SAFI_ALL)
-+ break;
-+ curpeer->conf.capabilities.mp_v6 = SAFI_UNICAST;
-+ break;
-+ }
++ 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;
-@@ -742,6 +827,17 @@ peeropts : REMOTEAS as4number {
+@@ -802,6 +801,17 @@ peeropts : REMOTEAS as4number {
}
free($2);
}
@@ -223,30 +224,48 @@ diff -u -p -r1.1.1.1 -r1.6
| LOCALADDR address {
memcpy(&curpeer->conf.local_addr, &$2,
sizeof(curpeer->conf.local_addr));
-@@ -759,6 +855,22 @@ peeropts : REMOTEAS as4number {
- | DOWN {
- curpeer->conf.down = 1;
+@@ -852,13 +862,17 @@ peeropts : REMOTEAS as4number {
+ curpeer->conf.min_holdtime = $3;
}
-+ | RIB STRING {
-+ if (!find_rib($2)) {
-+ yyerror("rib \"%s\" does not exist.", $2);
-+ free($2);
-+ YYERROR;
-+ }
-+ if (strlcpy(curpeer->conf.rib, $2,
-+ sizeof(curpeer->conf.rib)) >=
-+ sizeof(curpeer->conf.rib)) {
-+ yyerror("rib name \"%s\" too long: max %u",
-+ $2, sizeof(curpeer->conf.rib) - 1);
-+ free($2);
+ | 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 +880,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;
-+ }
-+ free($2);
-+ }
- | HOLDTIME NUMBER {
- if ($2 < MIN_HOLDTIME || $2 > USHRT_MAX) {
- yyerror("holdtime must be between %u and %u",
-@@ -804,11 +916,22 @@ peeropts : REMOTEAS as4number {
+ }
++ curpeer->conf.capabilities.mp[aid] = val;
+ }
| ANNOUNCE CAPABILITIES yesno {
curpeer->conf.announce_capa = $3;
}
@@ -270,81 +289,178 @@ diff -u -p -r1.1.1.1 -r1.6
curpeer->conf.announce_type = ANNOUNCE_NONE;
else if (!strcmp($2, "all"))
curpeer->conf.announce_type = ANNOUNCE_ALL;
-@@ -1058,6 +1181,12 @@ peeropts : REMOTEAS as4number {
- else
- curpeer->conf.softreconfig_out = $3;
+@@ -1083,7 +1103,7 @@ peeropts : REMOTEAS as4number {
+ curpeer->conf.reflector_client = 1;
}
-+ | TRANSPARENT yesno {
-+ if ($2 == 1)
-+ curpeer->conf.flags |= PEERFLAG_TRANS_AS;
-+ else
-+ curpeer->conf.flags &= ~PEERFLAG_TRANS_AS;
-+ }
+ | REFLECTOR address {
+- if ($2.af != AF_INET) {
++ if ($2.aid != AID_INET) {
+ yyerror("route reflector cluster-id must be "
+ "an IPv4 address");
+ YYERROR;
+@@ -1336,12 +1356,12 @@ filter_prefix_l : filter_prefix { $$
;
- restart : /* nada */ { $$ = 0; }
-@@ -1115,16 +1244,37 @@ encspec : /* nada */ {
+ 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);
+@@ -1437,18 +1457,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) {
+@@ -1463,26 +1483,25 @@ filter_elm : filter_prefix_h {
+ 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);
+ }
+ | 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;
}
;
--filterrule : action quick direction filter_peer_h filter_match_h filter_set
-+filterrule : action quick filter_rib direction filter_peer_h filter_match_h filter_set
- {
- struct filter_rule r;
+@@ -1782,8 +1801,7 @@ filter_set_opt : LOCALPREF NUMBER {
+ else
+ $$->type = ACTION_SET_COMMUNITY;
- bzero(&r, sizeof(r));
- r.action = $1;
- r.quick = $2;
-- r.dir = $3;
--
-- if (expand_rule(&r, $4, &$5, $6) == -1)
-+ r.dir = $4;
-+ if ($3) {
-+ if (r.dir != DIR_IN) {
-+ yyerror("rib only allowed on \"from\" "
-+ "rules.");
-+ free($3);
-+ YYERROR;
-+ }
-+ if (!find_rib($3)) {
-+ yyerror("rib \"%s\" does not exist.",
-+ $3);
-+ free($3);
-+ YYERROR;
-+ }
-+ if (strlcpy(r.rib, $3, sizeof(r.rib)) >=
-+ sizeof(r.rib)) {
-+ yyerror("rib name \"%s\" too long: "
-+ "max %u", $3, sizeof(r.rib) - 1);
-+ free($3);
-+ YYERROR;
-+ }
-+ free($3);
-+ }
-+ if (expand_rule(&r, $5, &$6, $7) == -1)
+- if (parsecommunity($3, &$$->action.community.as,
+- &$$->action.community.type) == -1) {
++ if (parsecommunity(&$$->action.community, $3) == -1) {
+ free($3);
+ free($$);
YYERROR;
+@@ -1796,40 +1814,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;
}
;
-@@ -1142,6 +1292,9 @@ direction : FROM { $$ = DIR_IN; }
- | TO { $$ = DIR_OUT; }
- ;
-+filter_rib : /* empty */ { $$ = NULL; }
-+ | RIB STRING { $$ = $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);
++ };
+
- filter_peer_h : filter_peer
- | '{' filter_peer_l '}' { $$ = $2; }
+ comma : ","
+ | /* empty */
;
-@@ -1396,7 +1549,7 @@ prefixlenop : unaryop NUMBER {
- YYERROR;
- }
- if ($1 >= $3) {
-- yyerror("start prefixlen is bigger that end");
-+ yyerror("start prefixlen is bigger than end");
- YYERROR;
- }
- $$.op = $2;
-@@ -1767,10 +1920,12 @@ lookup(char *s)
+
+ 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 +1913,7 @@ lookup(char *s)
{ "allow", ALLOW},
{ "announce", ANNOUNCE},
{ "any", ANY},
@@ -352,12 +468,15 @@ diff -u -p -r1.1.1.1 -r1.6
{ "blackhole", BLACKHOLE},
{ "capabilities", CAPABILITIES},
{ "community", COMMUNITY},
- { "compare", COMPARE},
-+ { "connect-retry", CONNECTRETRY},
- { "connected", CONNECTED},
- { "delete", DELETE},
- { "demote", DEMOTE},
-@@ -1792,6 +1947,9 @@ lookup(char *s)
+@@ -1889,6 +1930,7 @@ lookup(char *s)
+ { "enforce", ENFORCE},
+ { "esp", ESP},
+ { "evaluate", EVALUATE},
++ { "ext-community", EXTCOMMUNITY},
+ { "fib-update", FIBUPDATE},
+ { "from", FROM},
+ { "group", GROUP},
+@@ -1899,6 +1941,9 @@ lookup(char *s)
{ "include", INCLUDE},
{ "inet", IPV4},
{ "inet6", IPV6},
@@ -367,7 +486,15 @@ diff -u -p -r1.1.1.1 -r1.6
{ "ipsec", IPSEC},
{ "key", KEY},
{ "listen", LISTEN},
-@@ -1823,9 +1981,11 @@ lookup(char *s)
+@@ -1918,6 +1963,7 @@ lookup(char *s)
+ { "nexthop", NEXTHOP},
+ { "no-modify", NOMODIFY},
+ { "on", ON},
++ { "origin", ORIGIN},
+ { "out", OUT},
+ { "passive", PASSIVE},
+ { "password", PASSWORD},
+@@ -1930,6 +1976,7 @@ lookup(char *s)
{ "qualify", QUALIFY},
{ "quick", QUICK},
{ "rde", RDE},
@@ -375,171 +502,308 @@ diff -u -p -r1.1.1.1 -r1.6
{ "reject", REJECT},
{ "remote-as", REMOTEAS},
{ "restart", RESTART},
-+ { "rib", RIB},
- { "route-collector", ROUTECOLL},
- { "route-reflector", REFLECTOR},
- { "router-id", ROUTERID},
-@@ -1933,11 +2093,13 @@ findeol(void)
- int c;
+@@ -2135,6 +2182,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;
+ }
- parsebuf = NULL;
-- pushback_index = 0;
+ #define allowed_to_end_number(x) \
+@@ -2505,27 +2572,27 @@ getcommunity(char *s)
+ }
- /* skip to either EOF or the first real EOL */
- while (1) {
-- c = lgetc(0);
-+ if (pushback_index)
-+ c = pushback_buffer[--pushback_index];
-+ else
-+ c = lgetc(0);
- if (c == '\n') {
- file->lineno++;
- break;
-@@ -2118,11 +2280,15 @@ pushfile(const char *name, int secret)
+ int
+-parsecommunity(char *s, int *as, int *type)
++parsecommunity(struct filter_community *c, char *s)
{
- struct file *nfile;
+ char *p;
+- int i;
++ int i, as;
-- if ((nfile = calloc(1, sizeof(struct file))) == NULL ||
-- (nfile->name = strdup(name)) == NULL) {
-+ if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
- log_warn("malloc");
- return (NULL);
+ /* 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);
}
-+ if ((nfile->name = strdup(name)) == NULL) {
-+ log_warn("malloc");
-+ free(nfile);
-+ return (NULL);
-+ }
- if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
- log_warn("%s", nfile->name);
- free(nfile->name);
-@@ -2207,6 +2373,9 @@ parse_config(char *filename, struct bgpd
- /* init the empty filter list for later */
- TAILQ_INIT(xfilter_l);
-+ add_rib("Adj-RIB-In", F_RIB_NOEVALUATE);
-+ add_rib("Loc-RIB", 0);
-+
- yyparse();
- errors = file->errors;
- popfile();
-@@ -2447,11 +2616,13 @@ 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;
-+ p->conf.capabilities.mp_v4 = SAFI_ALL;
-+ p->conf.capabilities.mp_v6 = SAFI_ALL;
- p->conf.capabilities.refresh = 1;
- p->conf.capabilities.restart = 0;
-- p->conf.capabilities.as4byte = 0;
-+ p->conf.capabilities.as4byte = 1;
-+ p->conf.local_as = conf->as;
-+ p->conf.local_short_as = conf->short_as;
- p->conf.softreconfig_in = 1;
- p->conf.softreconfig_out = 1;
+@@ -2537,23 +2604,175 @@ parsecommunity(char *s, int *as, int *ty
-@@ -2473,10 +2644,16 @@ 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;
+ if ((i = getcommunity(s)) == COMMUNITY_ERROR)
+ return (-1);
+- if (i == USHRT_MAX) {
++ if (i == COMMUNITY_WELLKNOWN) {
+ yyerror("Bad community AS number");
+ return (-1);
}
- p->next = NULL;
--
-+ if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS)
-+ p->conf.flags |= PEERFLAG_TRANS_AS;
- return (p);
- }
+- *as = i;
++ as = i;
-@@ -2487,11 +2664,15 @@ new_group(void)
- }
+ if ((i = getcommunity(p)) == COMMUNITY_ERROR)
+ return (-1);
+- *type = i;
++ c->as = as;
++ c->type = i;
- int
--add_mrtconfig(enum mrt_type type, char *name, time_t timeout, struct peer *p)
-+add_mrtconfig(enum mrt_type type, char *name, time_t timeout, struct peer *p,
-+ char *rib)
- {
- struct mrt *m, *n;
+ return (0);
+ }
- LIST_FOREACH(m, mrtconf, entry) {
-+ if ((rib && strcmp(rib, m->rib)) ||
-+ (!rib && *m->rib))
-+ continue;
- if (p == NULL) {
- if (m->peer_id != 0 || m->group_id != 0)
- continue;
-@@ -2527,6 +2708,20 @@ add_mrtconfig(enum mrt_type type, char *
- n->group_id = 0;
- }
- }
-+ if (rib) {
-+ if (!find_rib(rib)) {
-+ yyerror("rib \"%s\" does not exist.", rib);
-+ free(n);
++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);
+ }
-+ if (strlcpy(n->rib, rib, sizeof(n->rib)) >=
-+ sizeof(n->rib)) {
-+ yyerror("rib name \"%s\" too long: max %u",
-+ name, sizeof(n->rib) - 1);
-+ free(n);
++ *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);
+ }
-
- LIST_INSERT_HEAD(mrtconf, n, entry);
-
-@@ -2534,6 +2729,42 @@ add_mrtconfig(enum mrt_type type, char *
- }
-
- int
-+add_rib(char *name, u_int16_t flags)
++ return (-1);
++}
++
++int
++parseextcommunity(struct filter_extcommunity *c, char *t, char *s)
+{
-+ struct rde_rib *rr;
++ 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 (find_rib(name)) {
-+ yyerror("rib \"%s\" allready exists.", name);
++ if ((subtype = parsesubtype(t)) == -1) {
++ yyerror("Bad ext-community unknown type");
+ return (-1);
+ }
+
-+ 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);
-+ 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;
++ }
+ }
-+ rr->flags |= flags;
-+ SIMPLEQ_INSERT_TAIL(&ribnames, rr, entry);
-+ return (0);
-+}
++ c->type = type;
++ c->subtype = subtype;
+
-+int
-+find_rib(char *name)
-+{
-+ struct rde_rib *rr;
-+
-+ SIMPLEQ_FOREACH(rr, &ribnames, entry) {
-+ if (!strcmp(rr->name, name))
-+ return (1);
++ /* 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;
++ return (0);
++ }
+ }
-+ return (0);
++
++ yyerror("Bad ext-community bad format for type");
++ return (-1);
+}
+
-+int
- get_id(struct peer *newpeer)
+ struct peer *
+ alloc_peer(void)
{
struct peer *p;
-@@ -2713,10 +2944,6 @@ neighbor_consistent(struct peer *p)
++ u_int8_t i;
+
+ if ((p = calloc(1, sizeof(struct peer))) == NULL)
+ fatal("new_peer");
+@@ -2564,11 +2783,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.as4byte = 1;
+ p->conf.local_as = conf->as;
+ p->conf.local_short_as = conf->short_as;
+ p->conf.softreconfig_in = 1;
+@@ -2592,6 +2811,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;
+@@ -2715,7 +2937,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 +3078,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 +3093,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,10 +3113,6 @@ neighbor_consistent(struct peer *p)
return (-1);
}
@@ -550,16 +814,48 @@ diff -u -p -r1.1.1.1 -r1.6
/* set default values if they where undefined */
p->conf.ebgp = (p->conf.remote_as != conf->as);
if (p->conf.announce_type == ANNOUNCE_UNDEF)
-@@ -2733,6 +2960,12 @@ neighbor_consistent(struct peer *p)
+@@ -2909,6 +3129,11 @@ neighbor_consistent(struct peer *p)
return (-1);
}
+ /* the default MP capability is NONE */
-+ if (p->conf.capabilities.mp_v4 == SAFI_ALL)
-+ p->conf.capabilities.mp_v4 = SAFI_NONE;
-+ if (p->conf.capabilities.mp_v6 == SAFI_ALL)
-+ p->conf.capabilities.mp_v6 = SAFI_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 +3152,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 +3183,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);
+ }