Time to 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. Rather large diff again so more testing and review very welcome. After this more refactoring will be possible (esp on the attribute matching and altering side).
-- :wq Claudio PS: diff is agains /usr/src since it includes bgpctl and bgpd diffs. Index: usr.sbin/bgpctl/bgpctl.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v retrieving revision 1.226 diff -u -p -r1.226 bgpctl.c --- usr.sbin/bgpctl/bgpctl.c 11 Dec 2018 09:03:36 -0000 1.226 +++ usr.sbin/bgpctl/bgpctl.c 12 Dec 2018 08:29:35 -0000 @@ -281,8 +281,6 @@ main(int argc, char *argv[]) ribreq.as = res->as; if (res->community.type != COMMUNITY_TYPE_NONE) ribreq.community = res->community; - if (res->extcommunity.flags == EXT_COMMUNITY_FLAG_VALID) - ribreq.extcommunity = res->extcommunity; ribreq.neighbor = neighbor; strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib)); ribreq.aid = res->aid; Index: usr.sbin/bgpctl/parser.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/parser.c,v retrieving revision 1.87 diff -u -p -r1.87 parser.c --- usr.sbin/bgpctl/parser.c 28 Nov 2018 08:33:59 -0000 1.87 +++ usr.sbin/bgpctl/parser.c 12 Dec 2018 08:29:35 -0000 @@ -662,8 +662,8 @@ match_token(int *argc, char **argv[], co case EXTCOM_SUBTYPE: if (word != NULL && strncmp(word, table[i].keyword, wordlen) == 0) { - if (parsesubtype(word, &res.extcommunity.type, - &res.extcommunity.subtype) == 0) + if (parsesubtype(word, &res.community.c.e.type, + &res.community.c.e.subtype) == 0) errx(1, "Bad ext-community unknown " "type"); match++; @@ -1084,8 +1084,8 @@ done: err(1, NULL); fs->type = ACTION_SET_COMMUNITY; fs->action.community.type = COMMUNITY_TYPE_BASIC; - fs->action.community.data1 = as; - fs->action.community.data2 = type; + fs->action.community.c.b.data1 = as; + fs->action.community.c.b.data2 = type; fs->action.community.dflag1 = asflag; fs->action.community.dflag2 = tflag; @@ -1160,7 +1160,7 @@ parseextvalue(const char *s, u_int32_t * s); return (-1); } - *v = ip.s_addr; + *v = ntohl(ip.s_addr); return (EXT_COMMUNITY_TRANS_IPV4); } return (-1); @@ -1177,7 +1177,7 @@ parseextcommunity(const char *word, stru char *p, *ep; int type; - type = r->extcommunity.type; + type = r->community.c.e.type; switch (type) { case 0xff: @@ -1208,16 +1208,13 @@ parseextcommunity(const char *word, stru } switch (type) { case EXT_COMMUNITY_TRANS_TWO_AS: - r->extcommunity.data.ext_as.as = uval; - r->extcommunity.data.ext_as.val = ullval; + r->community.c.e.data1 = uval; + r->community.c.e.data2 = ullval; break; case EXT_COMMUNITY_TRANS_IPV4: - r->extcommunity.data.ext_ip.addr.s_addr = uval; - r->extcommunity.data.ext_ip.val = ullval; - break; case EXT_COMMUNITY_TRANS_FOUR_AS: - r->extcommunity.data.ext_as4.as4 = uval; - r->extcommunity.data.ext_as4.val = ullval; + r->community.c.e.data1 = uval; + r->community.c.e.data2 = ullval; break; } break; @@ -1233,36 +1230,34 @@ parseextcommunity(const char *word, stru fprintf(stderr, "Bad ext-community: too big\n"); return (0); } - r->extcommunity.data.ext_opaq = ullval; + r->community.c.e.data2 = ullval; break; case EXT_COMMUNITY_NON_TRANS_OPAQUE: if (strcmp(word, "valid") == 0) - r->extcommunity.data.ext_opaq = EXT_COMMUNITY_OVS_VALID; + r->community.c.e.data2 = EXT_COMMUNITY_OVS_VALID; else if (strcmp(word, "invalid") == 0) - r->extcommunity.data.ext_opaq = - EXT_COMMUNITY_OVS_INVALID; + r->community.c.e.data2 = EXT_COMMUNITY_OVS_INVALID; else if (strcmp(word, "not-found") == 0) - r->extcommunity.data.ext_opaq = - EXT_COMMUNITY_OVS_NOTFOUND; + r->community.c.e.data2 = EXT_COMMUNITY_OVS_NOTFOUND; else { fprintf(stderr, "Bad ext-community value: %s\n", word); return (0); } break; } - r->extcommunity.type = type; + r->community.c.e.type = type; /* verify type/subtype combo */ for (cp = iana_ext_comms; cp->subname != NULL; cp++) { - if (cp->type == r->extcommunity.type && - cp->subtype == r->extcommunity.subtype) { - r->extcommunity.flags |= EXT_COMMUNITY_FLAG_VALID; + if (cp->type == r->community.c.e.type && + cp->subtype == r->community.c.e.subtype) { + r->community.type = COMMUNITY_TYPE_EXT;; if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) err(1, NULL); - fs->type = ACTION_SET_EXT_COMMUNITY; - memcpy(&fs->action.ext_community, &r->extcommunity, - sizeof(struct filter_extcommunity)); + fs->type = ACTION_SET_COMMUNITY; + memcpy(&fs->action.community, &r->community, + sizeof(struct filter_community)); TAILQ_INSERT_TAIL(&r->set, fs, entry); return (1); @@ -1303,9 +1298,9 @@ parse_largecommunity(const char *word, s err(1, NULL); fs->type = ACTION_SET_COMMUNITY; fs->action.community.type = COMMUNITY_TYPE_LARGE; - fs->action.community.data1 = as; - fs->action.community.data2 = ld1; - fs->action.community.data3 = ld2; + fs->action.community.c.l.data1 = as; + fs->action.community.c.l.data2 = ld1; + fs->action.community.c.l.data3 = ld2; fs->action.community.dflag1 = asflag; fs->action.community.dflag2 = ld1flag; fs->action.community.dflag3 = ld2flag; Index: usr.sbin/bgpctl/parser.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/parser.h,v retrieving revision 1.32 diff -u -p -r1.32 parser.h --- usr.sbin/bgpctl/parser.h 28 Nov 2018 08:33:59 -0000 1.32 +++ usr.sbin/bgpctl/parser.h 12 Dec 2018 08:29:35 -0000 @@ -63,7 +63,6 @@ struct parse_result { struct filter_as as; struct filter_set_head set; struct filter_community community; - struct filter_extcommunity extcommunity; char peerdesc[PEER_DESCR_LEN]; char rib[PEER_DESCR_LEN]; char shutcomm[SHUT_COMM_LEN]; Index: usr.sbin/bgpd/bgpd.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v retrieving revision 1.357 diff -u -p -r1.357 bgpd.h --- usr.sbin/bgpd/bgpd.h 11 Dec 2018 09:02:14 -0000 1.357 +++ usr.sbin/bgpd/bgpd.h 12 Dec 2018 12:56:51 -0000 @@ -742,30 +742,23 @@ struct filter_community { u_int8_t dflag1; /* one of set, any, local-as, neighbor-as */ u_int8_t dflag2; u_int8_t dflag3; - u_int32_t data1; - u_int32_t data2; - u_int32_t data3; -}; - -struct filter_extcommunity { - u_int16_t flags; - u_int8_t type; - u_int8_t subtype; /* if extended type */ union { - struct ext_as { - u_int16_t as; - u_int32_t val; - } ext_as; - struct ext_as4 { - u_int32_t as4; - u_int16_t val; - } ext_as4; - struct ext_ip { - struct in_addr addr; - u_int16_t val; - } ext_ip; - u_int64_t ext_opaq; /* only 48 bits */ - } data; + struct basic { + u_int32_t data1; + u_int32_t data2; + } b; + struct large { + u_int32_t data1; + u_int32_t data2; + u_int32_t data3; + } l; + struct ext { + u_int32_t data1; + u_int64_t data2; + u_int8_t type; + u_int8_t subtype; /* if extended type */ + } e; + } c; }; struct ctl_show_rib_request { @@ -774,7 +767,6 @@ struct ctl_show_rib_request { struct bgpd_addr prefix; struct filter_as as; struct filter_community community; - struct filter_extcommunity extcommunity; u_int32_t peerid; u_int32_t flags; u_int8_t validation_state; @@ -929,7 +921,6 @@ struct filter_match { struct filter_as as; struct filter_aslen aslen; struct filter_community community[MAX_COMM_MATCH]; - struct filter_extcommunity ext_community; struct filter_prefixset prefixset; struct filter_originset originset; struct filter_ovs ovs; @@ -968,8 +959,6 @@ enum action_types { ACTION_SET_NEXTHOP_SELF, ACTION_DEL_COMMUNITY, ACTION_SET_COMMUNITY, - ACTION_DEL_EXT_COMMUNITY, - ACTION_SET_EXT_COMMUNITY, ACTION_PFTABLE, ACTION_PFTABLE_ID, ACTION_RTLABEL, @@ -988,7 +977,6 @@ struct filter_set { struct bgpd_addr nexthop; struct nexthop *nh; struct filter_community community; - struct filter_extcommunity ext_community; char pftable[PFTABLE_LEN]; char rtlabel[RTLABEL_LEN]; u_int8_t origin; Index: usr.sbin/bgpd/parse.y =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v retrieving revision 1.365 diff -u -p -r1.365 parse.y --- usr.sbin/bgpd/parse.y 6 Dec 2018 12:38:01 -0000 1.365 +++ usr.sbin/bgpd/parse.y 12 Dec 2018 12:56:51 -0000 @@ -155,8 +155,7 @@ struct filter_rule *get_rule(enum action 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, 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_commun } *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 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; - 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,20 @@ 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; } - 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 +3672,16 @@ parseextcommunity(struct filter_extcommu } 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 +3698,8 @@ parseextcommunity(struct filter_extcommu 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 +3713,28 @@ parseextcommunity(struct filter_extcommu 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 +4228,6 @@ filterset_add(struct filter_set_head *sh 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 +4298,6 @@ 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)); Index: usr.sbin/bgpd/printconf.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v retrieving revision 1.124 diff -u -p -r1.124 printconf.c --- usr.sbin/bgpd/printconf.c 28 Nov 2018 08:32:27 -0000 1.124 +++ usr.sbin/bgpd/printconf.c 12 Dec 2018 12:56:51 -0000 @@ -32,8 +32,6 @@ void print_prefix(struct filter_prefix *p); const char *community_type(struct filter_community *c); void print_community(struct filter_community *c); -void print_largecommunity(int64_t, int64_t, int64_t); -void print_extcommunity(struct filter_extcommunity *); void print_origin(u_int8_t); void print_set(struct filter_set_head *); void print_mainconf(struct bgpd_config *); @@ -113,6 +111,8 @@ community_type(struct filter_community * return "community"; case COMMUNITY_TYPE_LARGE: return "large-community"; + case COMMUNITY_TYPE_EXT: + return "ext-community"; default: return "???"; } @@ -121,6 +121,8 @@ community_type(struct filter_community * void print_community(struct filter_community *c) { + struct in_addr addr; + switch (c->type) { case COMMUNITY_TYPE_BASIC: switch (c->dflag1) { @@ -134,7 +136,7 @@ print_community(struct filter_community printf("local-as:"); break; default: - printf("%u:", c->data1); + printf("%u:", c->c.b.data1); break; } switch (c->dflag2) { @@ -148,7 +150,7 @@ print_community(struct filter_community printf("local-as "); break; default: - printf("%u ", c->data2); + printf("%u ", c->c.b.data2); break; } break; @@ -164,7 +166,7 @@ print_community(struct filter_community printf("local-as:"); break; default: - printf("%u:", c->data1); + printf("%u:", c->c.l.data1); break; } switch (c->dflag2) { @@ -178,7 +180,7 @@ print_community(struct filter_community printf("local-as:"); break; default: - printf("%u:", c->data2); + printf("%u:", c->c.l.data2); break; } switch (c->dflag3) { @@ -192,50 +194,44 @@ print_community(struct filter_community printf("local-as "); break; default: - printf("%u ", c->data3); + printf("%u ", c->c.l.data3); break; } break; - } -} - -void -print_extcommunity(struct filter_extcommunity *c) -{ - printf("%s ", log_ext_subtype(c->type, c->subtype)); - - switch (c->type) { - case EXT_COMMUNITY_TRANS_TWO_AS: - printf("%hu:%u ", c->data.ext_as.as, c->data.ext_as.val); - break; - case EXT_COMMUNITY_TRANS_IPV4: - printf("%s:%u ", inet_ntoa(c->data.ext_ip.addr), - c->data.ext_ip.val); - break; - case EXT_COMMUNITY_TRANS_FOUR_AS: - printf("%s:%u ", log_as(c->data.ext_as4.as4), - c->data.ext_as.val); - break; - case EXT_COMMUNITY_TRANS_OPAQUE: - case EXT_COMMUNITY_TRANS_EVPN: - printf("0x%llx ", c->data.ext_opaq); - break; - case EXT_COMMUNITY_NON_TRANS_OPAQUE: - switch (c->data.ext_opaq) { - case EXT_COMMUNITY_OVS_VALID: - printf("valid "); - break; - case EXT_COMMUNITY_OVS_NOTFOUND: - printf("not-found "); + case COMMUNITY_TYPE_EXT: + printf("%s ", log_ext_subtype(c->c.e.type, c->c.e.subtype)); + switch (c->c.e.type) { + case EXT_COMMUNITY_TRANS_TWO_AS: + case EXT_COMMUNITY_TRANS_FOUR_AS: + printf("%s:%llu ", log_as(c->c.e.data1), + c->c.e.data2); + break; + case EXT_COMMUNITY_TRANS_IPV4: + addr.s_addr = htonl(c->c.e.data1); + printf("%s:%llu ", inet_ntoa(addr), + c->c.e.data2); + break; + case EXT_COMMUNITY_TRANS_OPAQUE: + case EXT_COMMUNITY_TRANS_EVPN: + printf("0x%llx ", c->c.e.data2); + break; + case EXT_COMMUNITY_NON_TRANS_OPAQUE: + switch (c->c.e.data2) { + case EXT_COMMUNITY_OVS_VALID: + printf("valid "); + break; + case EXT_COMMUNITY_OVS_NOTFOUND: + printf("not-found "); + break; + case EXT_COMMUNITY_OVS_INVALID: + printf("invalid "); + break; + } break; - case EXT_COMMUNITY_OVS_INVALID: - printf("invalid "); + default: + printf("0x%llx ", c->c.e.data2); break; } - break; - default: - printf("0x%llx ", c->data.ext_opaq); - break; } } @@ -326,14 +322,6 @@ print_set(struct filter_set_head *set) /* not possible */ printf("king bula saiz: config broken"); break; - case ACTION_SET_EXT_COMMUNITY: - printf("ext-community "); - print_extcommunity(&s->action.ext_community); - break; - case ACTION_DEL_EXT_COMMUNITY: - printf("ext-community delete "); - print_extcommunity(&s->action.ext_community); - break; } } printf("}"); @@ -391,7 +379,7 @@ print_rdomain_targets(struct filter_set_ struct filter_set *s; TAILQ_FOREACH(s, set, entry) { printf("\t%s ", tgt); - print_extcommunity(&s->action.ext_community); + print_community(&s->action.community); printf("\n"); } } @@ -847,10 +835,6 @@ print_rule(struct peer *peer_l, struct f printf("%s ", community_type(c)); print_community(c); } - } - if (r->match.ext_community.flags & EXT_COMMUNITY_FLAG_VALID) { - printf("ext-community "); - print_extcommunity(&r->match.ext_community); } print_set(&r->set); Index: usr.sbin/bgpd/rde.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v retrieving revision 1.452 diff -u -p -r1.452 rde.c --- usr.sbin/bgpd/rde.c 11 Dec 2018 09:02:14 -0000 1.452 +++ usr.sbin/bgpd/rde.c 12 Dec 2018 12:56:51 -0000 @@ -2229,10 +2229,11 @@ rde_dump_filter(struct prefix *p, struct if (!community_large_match(asp, &req->community, NULL)) return; break; + case COMMUNITY_TYPE_EXT: + if (!community_ext_match(asp, &req->community, 0)) + return; + break; } - if (req->extcommunity.flags == EXT_COMMUNITY_FLAG_VALID && - !community_ext_match(asp, &req->extcommunity, 0)) - return; if (!ovs_match(p, req->flags)) return; rde_dump_rib_as(p, asp, req->pid, req->flags); @@ -2436,7 +2437,7 @@ rde_rdomain_import(struct rde_aspath *as struct filter_set *s; TAILQ_FOREACH(s, &rd->import, entry) { - if (community_ext_match(asp, &s->action.ext_community, 0)) + if (community_match(asp, &s->action.community, 0)) return (1); } return (0); Index: usr.sbin/bgpd/rde.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v retrieving revision 1.204 diff -u -p -r1.204 rde.h --- usr.sbin/bgpd/rde.h 11 Dec 2018 09:02:14 -0000 1.204 +++ usr.sbin/bgpd/rde.h 12 Dec 2018 12:56:51 -0000 @@ -375,12 +375,12 @@ int community_large_set(struct rde_aspa void community_large_delete(struct rde_aspath *, struct filter_community *, struct rde_peer *); int community_ext_match(struct rde_aspath *, - struct filter_extcommunity *, u_int16_t); + struct filter_community *, struct rde_peer *); int community_ext_set(struct rde_aspath *, - struct filter_extcommunity *, u_int16_t); + struct filter_community *, struct rde_peer *); void community_ext_delete(struct rde_aspath *, - struct filter_extcommunity *, u_int16_t); -int community_ext_conv(struct filter_extcommunity *, u_int16_t, + struct filter_community *, struct rde_peer *); +int community_ext_conv(struct filter_community *, struct rde_peer *, u_int64_t *); u_char *community_ext_delete_non_trans(u_char *, u_int16_t, u_int16_t *); Index: usr.sbin/bgpd/rde_attr.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_attr.c,v retrieving revision 1.114 diff -u -p -r1.114 rde_attr.c --- usr.sbin/bgpd/rde_attr.c 11 Dec 2018 09:02:14 -0000 1.114 +++ usr.sbin/bgpd/rde_attr.c 12 Dec 2018 12:56:51 -0000 @@ -1106,8 +1106,6 @@ aspath_lenmatch(struct aspath *a, enum a * Functions handling communities and extended communities. */ -int community_ext_matchone(struct filter_extcommunity *, u_int16_t, u_int64_t); - static int community_extract(struct filter_community *fc, struct rde_peer *peer, int field, int large, u_int32_t *value) @@ -1117,15 +1115,21 @@ community_extract(struct filter_communit switch (field) { case 1: flag = fc->dflag1; - data = fc->data1; + if (large) + data = fc->c.l.data1; + else + data = fc->c.b.data1; break; case 2: flag = fc->dflag2; - data = fc->data2; + if (large) + data = fc->c.l.data2; + else + data = fc->c.b.data2; break; case 3: flag = fc->dflag3; - data = fc->data3; + data = fc->c.l.data3; break; default: fatalx("%s: unknown field %d", __func__, field); @@ -1148,6 +1152,73 @@ community_extract(struct filter_communit return 0; } +static int +community_ext_matchone(struct filter_community *c, struct rde_peer *peer, + u_int64_t community) +{ + u_int64_t com, mask; + + community = betoh64(community); + + com = (u_int64_t)c->c.e.type << 56; + mask = 0xffULL << 56; + if ((com & mask) != (community & mask)) + return (0); + + switch (c->c.e.type & EXT_COMMUNITY_VALUE) { + case EXT_COMMUNITY_TRANS_TWO_AS: + case EXT_COMMUNITY_TRANS_IPV4: + case EXT_COMMUNITY_TRANS_FOUR_AS: + case EXT_COMMUNITY_TRANS_OPAQUE: + com = (u_int64_t)c->c.e.subtype << 48; + mask = 0xffULL << 48; + if ((com & mask) != (community & mask)) + return (0); + break; + default: + com = c->c.e.data2 & 0xffffffffffffffULL; + mask = 0xffffffffffffffULL; + if ((com & mask) == (community & mask)) + return (1); + return (0); + } + + + switch (c->c.e.type & EXT_COMMUNITY_VALUE) { + case EXT_COMMUNITY_TRANS_TWO_AS: + com = (u_int64_t)c->c.e.data1 << 32; + mask = 0xffffULL << 32; + if ((com & mask) != (community & mask)) + return (0); + + com = c->c.e.data2; + mask = 0xffffffffULL; + if ((com & mask) == (community & mask)) + return (1); + break; + case EXT_COMMUNITY_TRANS_IPV4: + case EXT_COMMUNITY_TRANS_FOUR_AS: + com = (u_int64_t)c->c.e.data1 << 16; + mask = 0xffffffffULL << 16; + if ((com & mask) != (community & mask)) + return (0); + + com = c->c.e.data2; + mask = 0xffff; + if ((com & mask) == (community & mask)) + return (1); + break; + case EXT_COMMUNITY_TRANS_OPAQUE: + com = c->c.e.data2; + mask = EXT_COMMUNITY_OPAQUE_MAX; + if ((com & mask) == (community & mask)) + return (1); + break; + } + + return (0); +} + int community_match(struct rde_aspath *asp, struct filter_community *fc, struct rde_peer *peer) @@ -1308,8 +1379,8 @@ community_delete(struct rde_aspath *asp, } int -community_ext_match(struct rde_aspath *asp, struct filter_extcommunity *c, - u_int16_t neighas) +community_ext_match(struct rde_aspath *asp, struct filter_community *c, + struct rde_peer *peer) { struct attr *attr; u_int8_t *p; @@ -1324,7 +1395,7 @@ community_ext_match(struct rde_aspath *a p = attr->data; for (len = attr->len / sizeof(ec); len > 0; len--) { memcpy(&ec, p, sizeof(ec)); - if (community_ext_matchone(c, neighas, ec)) + if (community_ext_matchone(c, peer, ec)) return (1); p += sizeof(ec); } @@ -1333,8 +1404,8 @@ community_ext_match(struct rde_aspath *a } int -community_ext_set(struct rde_aspath *asp, struct filter_extcommunity *c, - u_int16_t neighas) +community_ext_set(struct rde_aspath *asp, struct filter_community *c, + struct rde_peer *peer) { struct attr *attr; u_int8_t *p = NULL; @@ -1342,7 +1413,7 @@ community_ext_set(struct rde_aspath *asp unsigned int i, ncommunities = 0; u_int8_t f = ATTR_OPTIONAL|ATTR_TRANSITIVE; - if (community_ext_conv(c, neighas, &community)) + if (community_ext_conv(c, peer, &community)) return (0); attr = attr_optget(asp, ATTR_EXT_COMMUNITIES); @@ -1381,8 +1452,8 @@ community_ext_set(struct rde_aspath *asp } void -community_ext_delete(struct rde_aspath *asp, struct filter_extcommunity *c, - u_int16_t neighas) +community_ext_delete(struct rde_aspath *asp, struct filter_community *c, + struct rde_peer *peer) { struct attr *attr; u_int8_t *p, *n; @@ -1390,7 +1461,7 @@ community_ext_delete(struct rde_aspath * u_int16_t l, len = 0; u_int8_t f; - if (community_ext_conv(c, neighas, &community)) + if (community_ext_conv(c, peer, &community)) return; attr = attr_optget(asp, ATTR_EXT_COMMUNITIES); @@ -1432,119 +1503,34 @@ community_ext_delete(struct rde_aspath * } int -community_ext_conv(struct filter_extcommunity *c, u_int16_t neighas, +community_ext_conv(struct filter_community *c, struct rde_peer *peer, u_int64_t *community) { u_int64_t com; - u_int32_t ip; - com = (u_int64_t)c->type << 56; - switch (c->type & EXT_COMMUNITY_VALUE) { + com = (u_int64_t)c->c.e.type << 56; + switch (c->c.e.type & EXT_COMMUNITY_VALUE) { case EXT_COMMUNITY_TRANS_TWO_AS: - com |= (u_int64_t)c->subtype << 48; - com |= (u_int64_t)c->data.ext_as.as << 32; - com |= c->data.ext_as.val; + com |= (u_int64_t)c->c.e.subtype << 48; + com |= (u_int64_t)c->c.e.data1 << 32; + com |= c->c.e.data2 & 0xffffffff; break; case EXT_COMMUNITY_TRANS_IPV4: - com |= (u_int64_t)c->subtype << 48; - ip = ntohl(c->data.ext_ip.addr.s_addr); - com |= (u_int64_t)ip << 16; - com |= c->data.ext_ip.val; - break; case EXT_COMMUNITY_TRANS_FOUR_AS: - com |= (u_int64_t)c->subtype << 48; - com |= (u_int64_t)c->data.ext_as4.as4 << 16; - com |= c->data.ext_as4.val; + com |= (u_int64_t)c->c.e.subtype << 48; + com |= (u_int64_t)c->c.e.data1 << 16; + com |= c->c.e.data2 & 0xffff; break; case EXT_COMMUNITY_TRANS_OPAQUE: - com |= (u_int64_t)c->subtype << 48; - com |= c->data.ext_opaq & EXT_COMMUNITY_OPAQUE_MAX; + com |= (u_int64_t)c->c.e.subtype << 48; + com |= c->c.e.data2 & EXT_COMMUNITY_OPAQUE_MAX; break; default: - com |= c->data.ext_opaq & 0xffffffffffffffULL; + com |= c->c.e.data2 & 0xffffffffffffffULL; break; } *community = htobe64(com); - - return (0); -} - -int -community_ext_matchone(struct filter_extcommunity *c, u_int16_t neighas, - u_int64_t community) -{ - u_int64_t com, mask; - u_int32_t ip; - - community = betoh64(community); - - com = (u_int64_t)c->type << 56; - mask = 0xffULL << 56; - if ((com & mask) != (community & mask)) - return (0); - - switch (c->type & EXT_COMMUNITY_VALUE) { - case EXT_COMMUNITY_TRANS_TWO_AS: - case EXT_COMMUNITY_TRANS_IPV4: - case EXT_COMMUNITY_TRANS_FOUR_AS: - case EXT_COMMUNITY_TRANS_OPAQUE: - com = (u_int64_t)c->subtype << 48; - mask = 0xffULL << 48; - if ((com & mask) != (community & mask)) - return (0); - break; - default: - com = c->data.ext_opaq & 0xffffffffffffffULL; - mask = 0xffffffffffffffULL; - if ((com & mask) == (community & mask)) - return (1); - return (0); - } - - - switch (c->type & EXT_COMMUNITY_VALUE) { - case EXT_COMMUNITY_TRANS_TWO_AS: - com = (u_int64_t)c->data.ext_as.as << 32; - mask = 0xffffULL << 32; - if ((com & mask) != (community & mask)) - return (0); - - com = c->data.ext_as.val; - mask = 0xffffffffULL; - if ((com & mask) == (community & mask)) - return (1); - break; - case EXT_COMMUNITY_TRANS_IPV4: - ip = ntohl(c->data.ext_ip.addr.s_addr); - com = (u_int64_t)ip << 16; - mask = 0xffffffff0000ULL; - if ((com & mask) != (community & mask)) - return (0); - - com = c->data.ext_ip.val; - mask = 0xffff; - if ((com & mask) == (community & mask)) - return (1); - break; - case EXT_COMMUNITY_TRANS_FOUR_AS: - com = (u_int64_t)c->data.ext_as4.as4 << 16; - mask = 0xffffffffULL << 16; - if ((com & mask) != (community & mask)) - return (0); - - com = c->data.ext_as4.val; - mask = 0xffff; - if ((com & mask) == (community & mask)) - return (1); - break; - case EXT_COMMUNITY_TRANS_OPAQUE: - com = c->data.ext_opaq & EXT_COMMUNITY_OPAQUE_MAX; - mask = EXT_COMMUNITY_OPAQUE_MAX; - if ((com & mask) == (community & mask)) - return (1); - break; - } return (0); } Index: usr.sbin/bgpd/rde_filter.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_filter.c,v retrieving revision 1.115 diff -u -p -r1.115 rde_filter.c --- usr.sbin/bgpd/rde_filter.c 11 Dec 2018 09:02:14 -0000 1.115 +++ usr.sbin/bgpd/rde_filter.c 12 Dec 2018 12:56:51 -0000 @@ -149,6 +149,10 @@ rde_apply_set(struct filter_set_head *sh community_large_set(&state->aspath, &set->action.community, peer); break; + case COMMUNITY_TYPE_EXT: + community_ext_set(&state->aspath, + &set->action.community, peer); + break; } break; case ACTION_DEL_COMMUNITY: @@ -161,6 +165,9 @@ rde_apply_set(struct filter_set_head *sh community_large_delete(&state->aspath, &set->action.community, peer); break; + case COMMUNITY_TYPE_EXT: + community_ext_delete(&state->aspath, + &set->action.community, peer); } break; case ACTION_PFTABLE: @@ -184,16 +191,6 @@ rde_apply_set(struct filter_set_head *sh case ACTION_SET_ORIGIN: state->aspath.origin = set->action.origin; break; - case ACTION_SET_EXT_COMMUNITY: - community_ext_set(&state->aspath, - &set->action.ext_community, - peer->conf.remote_as); - break; - case ACTION_DEL_EXT_COMMUNITY: - community_ext_delete(&state->aspath, - &set->action.ext_community, - peer->conf.remote_as); - break; } } } @@ -244,13 +241,12 @@ rde_filter_match(struct filter_rule *f, peer) == 0) return (0); break; + case COMMUNITY_TYPE_EXT: + if (community_ext_match(asp, &f->match.community[i], + peer) == 0) + return (0); } } - if (asp != NULL && - (f->match.ext_community.flags & EXT_COMMUNITY_FLAG_VALID)) - if (community_ext_match(asp, &f->match.ext_community, - peer->conf.remote_as) == 0) - return (0); if (state != NULL && f->match.nexthop.flags != 0) { struct bgpd_addr *nexthop, *cmpaddr; @@ -540,12 +536,6 @@ filterset_cmp(struct filter_set *a, stru sizeof(a->action.community))); } - if (a->type == ACTION_SET_EXT_COMMUNITY || - a->type == ACTION_DEL_EXT_COMMUNITY) { /* a->type == b->type */ - return (memcmp(&a->action.ext_community, - &b->action.ext_community, sizeof(a->action.ext_community))); - } - if (a->type == ACTION_SET_NEXTHOP && b->type == ACTION_SET_NEXTHOP) { /* * This is the only interesting case, all others are considered @@ -658,14 +648,6 @@ filterset_equal(struct filter_set_head * a->action.origin == b->action.origin) continue; break; - case ACTION_SET_EXT_COMMUNITY: - case ACTION_DEL_EXT_COMMUNITY: - if (a->type == b->type && memcmp( - &a->action.ext_community, - &b->action.ext_community, - sizeof(a->action.ext_community)) == 0) - continue; - break; } /* compare failed */ return (0); @@ -710,10 +692,6 @@ filterset_name(enum action_types type) return ("rtlabel"); case ACTION_SET_ORIGIN: return ("origin"); - case ACTION_SET_EXT_COMMUNITY: - return ("ext-community"); - case ACTION_DEL_EXT_COMMUNITY: - return ("ext-community delete"); } fatalx("filterset_name: got lost"); Index: usr.sbin/bgpd/rde_update.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v retrieving revision 1.105 diff -u -p -r1.105 rde_update.c --- usr.sbin/bgpd/rde_update.c 29 Nov 2018 12:10:51 -0000 1.105 +++ usr.sbin/bgpd/rde_update.c 12 Dec 2018 12:56:51 -0000 @@ -68,18 +68,18 @@ SIPHASH_KEY uptree_key; static struct filter_community comm_no_advertise = { .type = COMMUNITY_TYPE_BASIC, - .data1 = COMMUNITY_WELLKNOWN, - .data2 = COMMUNITY_NO_ADVERTISE + .c.b.data1 = COMMUNITY_WELLKNOWN, + .c.b.data2 = COMMUNITY_NO_ADVERTISE }; static struct filter_community comm_no_export = { .type = COMMUNITY_TYPE_BASIC, - .data1 = COMMUNITY_WELLKNOWN, - .data2 = COMMUNITY_NO_EXPORT + .c.b.data1 = COMMUNITY_WELLKNOWN, + .c.b.data2 = COMMUNITY_NO_EXPORT }; static struct filter_community comm_no_expsubconfed = { .type = COMMUNITY_TYPE_BASIC, - .data1 = COMMUNITY_WELLKNOWN, - .data2 = COMMUNITY_NO_EXPSUBCONFED + .c.b.data1 = COMMUNITY_WELLKNOWN, + .c.b.data2 = COMMUNITY_NO_EXPSUBCONFED }; void