diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2018-12-19 15:26:43 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2018-12-19 15:26:43 +0000 |
commit | 0fe71675d51168c8715c1ee09c98b8b61e16c074 (patch) | |
tree | 6c8422ea09a14bdd916c661c7de629b8476ee7b2 /usr.sbin/bgpd/parse.y | |
parent | b2370187484c0e92ae6a7cb4cc87f0458618d69d (diff) |
Fold ext-communities into filter_community so that bgpd can match
multiple ext-communities at the same time as well. Additionally this fixes
parsing some of the ext-community types. Now all communities are handled
by one common struct.
OK benno@ plus some input from denis@
Diffstat (limited to 'usr.sbin/bgpd/parse.y')
-rw-r--r-- | usr.sbin/bgpd/parse.y | 183 |
1 files changed, 95 insertions, 88 deletions
diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index d251eb86a91..984a1639300 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.365 2018/12/06 12:38:01 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.366 2018/12/19 15:26:42 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -155,8 +155,7 @@ struct filter_rule *get_rule(enum action_types); int parsecommunity(struct filter_community *, int, char *); int parsesubtype(char *, int *, int *); -int parseextvalue(char *, u_int32_t *); -int parseextcommunity(struct filter_extcommunity *, char *, +int parseextcommunity(struct filter_community *, char *, char *); static int new_as_set(char *); static void add_as_set(u_int32_t); @@ -1078,8 +1077,8 @@ rdomainopts_l : /* empty */ ; rdomainopts : RD STRING { - struct filter_extcommunity ext; - u_int64_t rd; + struct filter_community ext; + u_int64_t rd; if (parseextcommunity(&ext, "rt", $2) == -1) { free($2); @@ -1095,7 +1094,7 @@ rdomainopts : RD STRING { YYERROR; } rd = betoh64(rd) & 0xffffffffffffULL; - switch (ext.type) { + switch (ext.c.e.type) { case EXT_COMMUNITY_TRANS_TWO_AS: rd |= (0ULL << 48); break; @@ -1117,8 +1116,8 @@ rdomainopts : RD STRING { if ((set = calloc(1, sizeof(struct filter_set))) == NULL) fatal(NULL); - set->type = ACTION_SET_EXT_COMMUNITY; - if (parseextcommunity(&set->action.ext_community, + set->type = ACTION_SET_COMMUNITY; + if (parseextcommunity(&set->action.community, $2, $3) == -1) { free($3); free($2); @@ -1135,8 +1134,8 @@ rdomainopts : RD STRING { if ((set = calloc(1, sizeof(struct filter_set))) == NULL) fatal(NULL); - set->type = ACTION_SET_EXT_COMMUNITY; - if (parseextcommunity(&set->action.ext_community, + set->type = ACTION_SET_COMMUNITY; + if (parseextcommunity(&set->action.community, $2, $3) == -1) { free($3); free($2); @@ -2160,15 +2159,20 @@ filter_elm : filter_prefix_h { free($2); } | EXTCOMMUNITY STRING STRING { - if (fmopts.m.ext_community.flags & - EXT_COMMUNITY_FLAG_VALID) { - yyerror("\"ext-community\" already specified"); + int i; + for (i = 0; i < MAX_COMM_MATCH; i++) { + if (fmopts.m.community[i].type == + COMMUNITY_TYPE_NONE) + break; + } + if (i >= MAX_COMM_MATCH) { + yyerror("too many \"community\" filters " + "specified"); free($2); free($3); YYERROR; } - - if (parseextcommunity(&fmopts.m.ext_community, + if (parseextcommunity(&fmopts.m.community[i], $2, $3) == -1) { free($2); free($3); @@ -2178,14 +2182,19 @@ filter_elm : filter_prefix_h { free($3); } | EXTCOMMUNITY OVS STRING { - if (fmopts.m.ext_community.flags & - EXT_COMMUNITY_FLAG_VALID) { - yyerror("\"ext-community\" already specified"); + int i; + for (i = 0; i < MAX_COMM_MATCH; i++) { + if (fmopts.m.community[i].type == + COMMUNITY_TYPE_NONE) + break; + } + if (i >= MAX_COMM_MATCH) { + yyerror("too many \"community\" filters " + "specified"); free($3); YYERROR; } - - if (parseextcommunity(&fmopts.m.ext_community, + if (parseextcommunity(&fmopts.m.community[i], "ovs", $3) == -1) { free($3); YYERROR; @@ -2659,11 +2668,11 @@ filter_set_opt : LOCALPREF NUMBER { if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) fatal(NULL); if ($2) - $$->type = ACTION_DEL_EXT_COMMUNITY; + $$->type = ACTION_DEL_COMMUNITY; else - $$->type = ACTION_SET_EXT_COMMUNITY; + $$->type = ACTION_SET_COMMUNITY; - if (parseextcommunity(&$$->action.ext_community, + if (parseextcommunity(&$$->action.community, $3, $4) == -1) { free($3); free($4); @@ -2677,11 +2686,11 @@ filter_set_opt : LOCALPREF NUMBER { if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) fatal(NULL); if ($2) - $$->type = ACTION_DEL_EXT_COMMUNITY; + $$->type = ACTION_DEL_COMMUNITY; else - $$->type = ACTION_SET_EXT_COMMUNITY; + $$->type = ACTION_SET_COMMUNITY; - if (parseextcommunity(&$$->action.ext_community, + if (parseextcommunity(&$$->action.community, "ovs", $4) == -1) { free($4); free($$); @@ -3479,8 +3488,8 @@ setcommunity(struct filter_community *c, u_int32_t as, u_int32_t data, c->type = COMMUNITY_TYPE_BASIC; c->dflag1 = asflag; c->dflag2 = dataflag; - c->data1 = as; - c->data2 = data; + c->c.b.data1 = as; + c->c.b.data2 = data; } static int @@ -3500,9 +3509,9 @@ parselargecommunity(struct filter_community *c, char *s) } *q++ = 0; - if (getcommunity(s, 1, &c->data1, &c->dflag1) == -1 || - getcommunity(p, 1, &c->data2, &c->dflag2) == -1 || - getcommunity(q, 1, &c->data3, &c->dflag3) == -1) + if (getcommunity(s, 1, &c->c.l.data1, &c->dflag1) == -1 || + getcommunity(p, 1, &c->c.l.data2, &c->dflag2) == -1 || + getcommunity(q, 1, &c->c.l.data3, &c->dflag3) == -1) return (-1); c->type = COMMUNITY_TYPE_LARGE; return (0); @@ -3578,28 +3587,51 @@ parsesubtype(char *name, int *type, int *subtype) return (found); } -int -parseextvalue(char *s, u_int32_t *v) +static int +parseextvalue(int type, char *s, u_int32_t *v) { const char *errstr; char *p; struct in_addr ip; - u_int32_t uvalh = 0, uval; + u_int32_t uvalh, uval; - if ((p = strchr(s, '.')) == NULL) { + if (type != -1) { + /* nothing */ + } else if ((p = strchr(s, '.')) == NULL) { /* AS_PLAIN number (4 or 2 byte) */ - uval = strtonum(s, 0, UINT_MAX, &errstr); + strtonum(s, 0, USHRT_MAX, &errstr); + if (errstr == NULL) + type = EXT_COMMUNITY_TRANS_TWO_AS; + else + type = EXT_COMMUNITY_TRANS_FOUR_AS; + } else if (strchr(p + 1, '.') == NULL) { + /* AS_DOT number (4-byte) */ + type = EXT_COMMUNITY_TRANS_FOUR_AS; + } else { + /* more than one dot -> IP address */ + type = EXT_COMMUNITY_TRANS_IPV4; + } + + switch (type) { + case EXT_COMMUNITY_TRANS_TWO_AS: + uval = strtonum(s, 0, USHRT_MAX, &errstr); if (errstr) { yyerror("Bad ext-community %s is %s", s, errstr); return (-1); } *v = uval; - if (uval <= USHRT_MAX) - return (EXT_COMMUNITY_TRANS_TWO_AS); - else - return (EXT_COMMUNITY_TRANS_FOUR_AS); - } else if (strchr(p + 1, '.') == NULL) { - /* AS_DOT number (4-byte) */ + break; + case EXT_COMMUNITY_TRANS_FOUR_AS: + if ((p = strchr(s, '.')) == NULL) { + uval = strtonum(s, 0, UINT_MAX, &errstr); + if (errstr) { + yyerror("Bad ext-community %s is %s", s, + errstr); + return (-1); + } + *v = uval; + break; + } *p++ = '\0'; uvalh = strtonum(s, 0, USHRT_MAX, &errstr); if (errstr) { @@ -3612,21 +3644,22 @@ parseextvalue(char *s, u_int32_t *v) return (-1); } *v = uval | (uvalh << 16); - return (EXT_COMMUNITY_TRANS_FOUR_AS); - } else { - /* more than one dot -> IP address */ + break; + case EXT_COMMUNITY_TRANS_IPV4: if (inet_aton(s, &ip) == 0) { yyerror("Bad ext-community %s not parseable", s); return (-1); } - *v = ip.s_addr; - return (EXT_COMMUNITY_TRANS_IPV4); + *v = ntohl(ip.s_addr); + break; + default: + fatalx("%s: unexpected type %d", __func__, type); } - return (-1); + return (type); } int -parseextcommunity(struct filter_extcommunity *c, char *t, char *s) +parseextcommunity(struct filter_community *c, char *t, char *s) { const struct ext_comm_pairs *cp; const char *errstr; @@ -3641,13 +3674,16 @@ parseextcommunity(struct filter_extcommunity *c, char *t, char *s) } switch (type) { + case EXT_COMMUNITY_TRANS_TWO_AS: + case EXT_COMMUNITY_TRANS_FOUR_AS: + case EXT_COMMUNITY_TRANS_IPV4: case -1: if ((p = strchr(s, ':')) == NULL) { yyerror("Bad ext-community %s", s); return (-1); } *p++ = '\0'; - if ((type = parseextvalue(s, &uval)) == -1) + if ((type = parseextvalue(type, s, &uval)) == -1) return (-1); switch (type) { case EXT_COMMUNITY_TRANS_TWO_AS: @@ -3664,20 +3700,8 @@ parseextcommunity(struct filter_extcommunity *c, char *t, char *s) yyerror("Bad ext-community %s is %s", p, errstr); return (-1); } - switch (type) { - case EXT_COMMUNITY_TRANS_TWO_AS: - c->data.ext_as.as = uval; - c->data.ext_as.val = ullval; - break; - case EXT_COMMUNITY_TRANS_IPV4: - c->data.ext_ip.addr.s_addr = uval; - c->data.ext_ip.val = ullval; - break; - case EXT_COMMUNITY_TRANS_FOUR_AS: - c->data.ext_as4.as4 = uval; - c->data.ext_as4.val = ullval; - break; - } + c->c.e.data1 = uval; + c->c.e.data2 = ullval; break; case EXT_COMMUNITY_TRANS_OPAQUE: case EXT_COMMUNITY_TRANS_EVPN: @@ -3691,28 +3715,28 @@ parseextcommunity(struct filter_extcommunity *c, char *t, char *s) yyerror("Bad ext-community value too big"); return (-1); } - c->data.ext_opaq = ullval; + c->c.e.data2 = ullval; break; case EXT_COMMUNITY_NON_TRANS_OPAQUE: if (strcmp(s, "valid") == 0) - c->data.ext_opaq = EXT_COMMUNITY_OVS_VALID; + c->c.e.data2 = EXT_COMMUNITY_OVS_VALID; else if (strcmp(s, "invalid") == 0) - c->data.ext_opaq = EXT_COMMUNITY_OVS_INVALID; + c->c.e.data2 = EXT_COMMUNITY_OVS_INVALID; else if (strcmp(s, "not-found") == 0) - c->data.ext_opaq = EXT_COMMUNITY_OVS_NOTFOUND; + c->c.e.data2 = EXT_COMMUNITY_OVS_NOTFOUND; else { yyerror("Bad ext-community %s", s); return (-1); } break; } - c->type = type; - c->subtype = subtype; + c->c.e.type = type; + c->c.e.subtype = subtype; /* verify type/subtype combo */ for (cp = iana_ext_comms; cp->subname != NULL; cp++) { if (cp->type == type && cp->subtype == subtype) { - c->flags |= EXT_COMMUNITY_FLAG_VALID; + c->type = COMMUNITY_TYPE_EXT; return (0); } } @@ -4206,18 +4230,6 @@ filterset_add(struct filter_set_head *sh, struct filter_set *s) sizeof(s->action.community)) == 0) break; continue; - 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; - } else if (memcmp(&s->action.ext_community, - &t->action.ext_community, - sizeof(s->action.ext_community)) == 0) - break; - continue; case ACTION_SET_NEXTHOP: /* only last nexthop per AF matters */ if (s->action.nexthop.aid < @@ -4288,11 +4300,6 @@ merge_filterset(struct filter_set_head *sh, struct filter_set *s) 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)); |