diff options
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 44 | ||||
-rw-r--r-- | usr.sbin/bgpd/control.c | 10 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 241 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 186 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.c | 37 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.h | 43 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_attr.c | 189 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_filter.c | 296 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_update.c | 32 |
9 files changed, 452 insertions, 626 deletions
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 1792de03f7b..8acea21297b 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.354 2018/11/14 14:03:36 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.355 2018/11/28 08:32:26 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -50,6 +50,7 @@ #define READ_BUF_SIZE 65535 #define RT_BUF_SIZE 16384 #define MAX_RTSOCK_BUF (2 * 1024 * 1024) +#define MAX_COMM_MATCH 3 #define BGPD_OPT_VERBOSE 0x0001 #define BGPD_OPT_VERBOSE2 0x0002 @@ -427,12 +428,8 @@ enum imsg_type { IMSG_CTL_SHOW_NEXTHOP, IMSG_CTL_SHOW_INTERFACE, IMSG_CTL_SHOW_RIB, - IMSG_CTL_SHOW_RIB_AS, IMSG_CTL_SHOW_RIB_PREFIX, IMSG_CTL_SHOW_RIB_ATTR, - IMSG_CTL_SHOW_RIB_COMMUNITY, - IMSG_CTL_SHOW_RIB_EXTCOMMUNITY, - IMSG_CTL_SHOW_RIB_LARGECOMMUNITY, IMSG_CTL_SHOW_NETWORK, IMSG_CTL_SHOW_RIB_MEM, IMSG_CTL_SHOW_RIB_HASH, @@ -741,14 +738,13 @@ struct filter_ovs { }; struct filter_community { - int as; - int type; -}; - -struct filter_largecommunity { - int64_t as; - int64_t ld1; - int64_t ld2; + u_int8_t type; + 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 { @@ -779,7 +775,6 @@ struct ctl_show_rib_request { struct filter_as as; struct filter_community community; struct filter_extcommunity extcommunity; - struct filter_largecommunity large_community; u_int32_t peerid; u_int32_t flags; u_int8_t validation_state; @@ -829,11 +824,16 @@ struct filter_peers { }; /* special community type */ -#define COMMUNITY_ERROR -1 -#define COMMUNITY_ANY -2 -#define COMMUNITY_NEIGHBOR_AS -3 -#define COMMUNITY_LOCAL_AS -4 -#define COMMUNITY_UNSET -5 +#define COMMUNITY_TYPE_NONE 0 +#define COMMUNITY_TYPE_BASIC 1 +#define COMMUNITY_TYPE_EXT 2 +#define COMMUNITY_TYPE_LARGE 3 + +#define COMMUNITY_ANY 1 +#define COMMUNITY_NEIGHBOR_AS 2 +#define COMMUNITY_LOCAL_AS 3 + +/* wellknown community definitions */ #define COMMUNITY_WELLKNOWN 0xffff #define COMMUNITY_GRACEFUL_SHUTDOWN 0x0000 /* RFC 8326 */ #define COMMUNITY_BLACKHOLE 0x029A /* RFC 7999 */ @@ -928,8 +928,7 @@ struct filter_match { struct filter_nexthop nexthop; struct filter_as as; struct filter_aslen aslen; - struct filter_community community; - struct filter_largecommunity large_community; + struct filter_community community[MAX_COMM_MATCH]; struct filter_extcommunity ext_community; struct filter_prefixset prefixset; struct filter_originset originset; @@ -969,8 +968,6 @@ enum action_types { ACTION_SET_NEXTHOP_SELF, ACTION_SET_COMMUNITY, ACTION_DEL_COMMUNITY, - ACTION_DEL_LARGE_COMMUNITY, - ACTION_SET_LARGE_COMMUNITY, ACTION_SET_EXT_COMMUNITY, ACTION_DEL_EXT_COMMUNITY, ACTION_PFTABLE, @@ -991,7 +988,6 @@ struct filter_set { struct bgpd_addr nexthop; struct nexthop *nh; struct filter_community community; - struct filter_largecommunity large_community; struct filter_extcommunity ext_community; char pftable[PFTABLE_LEN]; char rtlabel[RTLABEL_LEN]; diff --git a/usr.sbin/bgpd/control.c b/usr.sbin/bgpd/control.c index 633a6344180..3ba8ed1c86d 100644 --- a/usr.sbin/bgpd/control.c +++ b/usr.sbin/bgpd/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.90 2017/08/11 16:02:53 claudio Exp $ */ +/* $OpenBSD: control.c,v 1.91 2018/11/28 08:32:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -248,12 +248,8 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) case IMSG_CTL_SHOW_NEXTHOP: case IMSG_CTL_SHOW_INTERFACE: case IMSG_CTL_SHOW_RIB: - case IMSG_CTL_SHOW_RIB_AS: case IMSG_CTL_SHOW_RIB_PREFIX: case IMSG_CTL_SHOW_RIB_MEM: - case IMSG_CTL_SHOW_RIB_COMMUNITY: - case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY: - case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY: case IMSG_CTL_SHOW_NETWORK: case IMSG_CTL_SHOW_TERSE: case IMSG_CTL_SHOW_TIMER: @@ -421,7 +417,6 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) IMSG_HEADER_SIZE); break; case IMSG_CTL_SHOW_RIB: - case IMSG_CTL_SHOW_RIB_AS: case IMSG_CTL_SHOW_RIB_PREFIX: if (imsg.hdr.len == IMSG_HEADER_SIZE + sizeof(struct ctl_show_rib_request)) { @@ -471,9 +466,6 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) "wrong length"); break; case IMSG_CTL_SHOW_RIB_MEM: - case IMSG_CTL_SHOW_RIB_COMMUNITY: - case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY: - case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY: case IMSG_CTL_SHOW_NETWORK: c->ibuf.pid = imsg.hdr.pid; imsg_ctl_rde(imsg.hdr.type, imsg.hdr.pid, diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index 41ef8411ce6..fecf647da96 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.363 2018/11/18 09:36:23 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.364 2018/11/28 08:32:27 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -153,9 +153,7 @@ int merge_filterset(struct filter_set_head *, struct filter_set *); void merge_filter_lists(struct filter_head *, struct filter_head *); struct filter_rule *get_rule(enum action_types); -int64_t getcommunity(char *, int); -int parsecommunity(struct filter_community *, char *); -int parselargecommunity(struct filter_largecommunity *, char *); +int parsecommunity(struct filter_community *, int, char *); int parsesubtype(char *, int *, int *); int parseextvalue(char *, u_int32_t *); int parseextcommunity(struct filter_extcommunity *, char *, @@ -232,7 +230,7 @@ typedef struct { %type <v.addr> address %type <v.prefix> prefix addrspec %type <v.prefixset_item> prefixset_item -%type <v.u8> action quick direction delete +%type <v.u8> action quick direction delete community %type <v.filter_rib> filter_rib_h filter_rib_l filter_rib %type <v.filter_peers> filter_peer filter_peer_l filter_peer_h %type <v.filter_match> filter_match filter_elm filter_match_h @@ -2085,13 +2083,9 @@ filter_as : as4number_any { filter_match_h : /* empty */ { bzero(&$$, sizeof($$)); - $$.m.community.as = COMMUNITY_UNSET; - $$.m.large_community.as = COMMUNITY_UNSET; } | { bzero(&fmopts, sizeof(fmopts)); - fmopts.m.community.as = COMMUNITY_UNSET; - fmopts.m.large_community.as = COMMUNITY_UNSET; } filter_match { memcpy(&$$, &fmopts, sizeof($$)); @@ -2146,25 +2140,20 @@ filter_elm : filter_prefix_h { 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; + | community STRING { + int i; + for (i = 0; i < MAX_COMM_MATCH; i++) { + if (fmopts.m.community[i].type == + COMMUNITY_TYPE_NONE) + break; } - if (parsecommunity(&fmopts.m.community, $2) == -1) { + if (i >= MAX_COMM_MATCH) { + yyerror("too many \"community\" filters " + "specified"); free($2); YYERROR; } - free($2); - } - | LARGECOMMUNITY STRING { - if (fmopts.m.large_community.as != COMMUNITY_UNSET) { - yyerror("\"large-community\" already specified"); - free($2); - YYERROR; - } - if (parselargecommunity(&fmopts.m.large_community, $2) == -1) { + if (parsecommunity(&fmopts.m.community[i], $1, $2) == -1) { free($2); YYERROR; } @@ -2405,6 +2394,10 @@ filter_set_l : filter_set_l comma filter_set_opt { } ; +community : COMMUNITY { $$ = COMMUNITY_TYPE_BASIC; } + | LARGECOMMUNITY { $$ = COMMUNITY_TYPE_LARGE; } + ; + delete : /* empty */ { $$ = 0; } | DELETE { $$ = 1; } ; @@ -2637,7 +2630,7 @@ filter_set_opt : LOCALPREF NUMBER { } free($2); } - | COMMUNITY delete STRING { + | community delete STRING { if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) fatal(NULL); if ($2) @@ -2645,30 +2638,8 @@ filter_set_opt : LOCALPREF NUMBER { else $$->type = ACTION_SET_COMMUNITY; - if (parsecommunity(&$$->action.community, $3) == -1) { - free($3); - free($$); - YYERROR; - } - free($3); - /* Don't allow setting of any match */ - if (!$2 && ($$->action.community.as == COMMUNITY_ANY || - $$->action.community.type == COMMUNITY_ANY)) { - yyerror("'*' is not allowed in set community"); - free($$); - YYERROR; - } - } - | LARGECOMMUNITY delete STRING { - if (($$ = calloc(1, sizeof(struct filter_set))) == NULL) - fatal(NULL); - if ($2) - $$->type = ACTION_DEL_LARGE_COMMUNITY; - else - $$->type = ACTION_SET_LARGE_COMMUNITY; - - if (parselargecommunity(&$$->action.large_community, - $3) == -1) { + if (parsecommunity(&$$->action.community, $1, $3) == + -1) { free($3); free($$); YYERROR; @@ -2676,9 +2647,9 @@ filter_set_opt : LOCALPREF NUMBER { free($3); /* Don't allow setting of any match */ if (!$2 && - ($$->action.large_community.as == COMMUNITY_ANY || - $$->action.large_community.ld1 == COMMUNITY_ANY || - $$->action.large_community.ld2 == COMMUNITY_ANY)) { + ($$->action.community.dflag1 == COMMUNITY_ANY || + $$->action.community.dflag2 == COMMUNITY_ANY || + $$->action.community.dflag3 == COMMUNITY_ANY)) { yyerror("'*' is not allowed in set community"); free($$); YYERROR; @@ -3470,60 +3441,105 @@ symget(const char *nam) return (NULL); } -int64_t -getcommunity(char *s, int large) +static int +getcommunity(char *s, int large, u_int32_t *val, u_int8_t *flag) { int64_t max = USHRT_MAX; - u_int val; const char *errstr; - if (strcmp(s, "*") == 0) - return (COMMUNITY_ANY); - if (strcmp(s, "neighbor-as") == 0) - return (COMMUNITY_NEIGHBOR_AS); - if (strcmp(s, "local-as") == 0) - return (COMMUNITY_LOCAL_AS); + *flag = 0; + *val = 0; + if (strcmp(s, "*") == 0) { + *flag = COMMUNITY_ANY; + return 0; + } else if (strcmp(s, "neighbor-as") == 0) { + *flag = COMMUNITY_NEIGHBOR_AS; + return 0; + } else if (strcmp(s, "local-as") == 0) { + *flag = COMMUNITY_LOCAL_AS; + return 0; + } if (large) max = UINT_MAX; - val = strtonum(s, 0, max, &errstr); + *val = strtonum(s, 0, max, &errstr); if (errstr) { yyerror("Community %s is %s (max: %llu)", s, errstr, max); - return (COMMUNITY_ERROR); + return -1; } - return (val); + return 0; +} + +static void +setcommunity(struct filter_community *c, u_int32_t as, u_int32_t data, + u_int8_t asflag, u_int8_t dataflag) +{ + memset(c, 0, sizeof(*c)); + c->type = COMMUNITY_TYPE_BASIC; + c->dflag1 = asflag; + c->dflag2 = dataflag; + c->data1 = as; + c->data2 = data; } +static int +parselargecommunity(struct filter_community *c, char *s) +{ + char *p, *q; + + if ((p = strchr(s, ':')) == NULL) { + yyerror("Bad community syntax"); + return (-1); + } + *p++ = 0; + + if ((q = strchr(p, ':')) == NULL) { + yyerror("Bad community syntax"); + return (-1); + } + *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) + return (-1); + c->type = COMMUNITY_TYPE_LARGE; + return (0); +} int -parsecommunity(struct filter_community *c, char *s) +parsecommunity(struct filter_community *c, int type, char *s) { char *p; - int i, as; + u_int32_t as, data; + u_int8_t asflag, dataflag; + + if (type == COMMUNITY_TYPE_LARGE) + return parselargecommunity(c, s); /* Well-known communities */ if (strcasecmp(s, "GRACEFUL_SHUTDOWN") == 0) { - c->as = COMMUNITY_WELLKNOWN; - c->type = COMMUNITY_GRACEFUL_SHUTDOWN; + setcommunity(c, COMMUNITY_WELLKNOWN, + COMMUNITY_GRACEFUL_SHUTDOWN, 0, 0); return (0); } else if (strcasecmp(s, "NO_EXPORT") == 0) { - c->as = COMMUNITY_WELLKNOWN; - c->type = COMMUNITY_NO_EXPORT; + setcommunity(c, COMMUNITY_WELLKNOWN, + COMMUNITY_NO_EXPORT, 0, 0); return (0); } else if (strcasecmp(s, "NO_ADVERTISE") == 0) { - c->as = COMMUNITY_WELLKNOWN; - c->type = COMMUNITY_NO_ADVERTISE; + setcommunity(c, COMMUNITY_WELLKNOWN, + COMMUNITY_NO_ADVERTISE, 0, 0); return (0); } else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) { - c->as = COMMUNITY_WELLKNOWN; - c->type = COMMUNITY_NO_EXPSUBCONFED; + setcommunity(c, COMMUNITY_WELLKNOWN, + COMMUNITY_NO_EXPSUBCONFED, 0, 0); return (0); } else if (strcasecmp(s, "NO_PEER") == 0) { - c->as = COMMUNITY_WELLKNOWN; - c->type = COMMUNITY_NO_PEER; + setcommunity(c, COMMUNITY_WELLKNOWN, + COMMUNITY_NO_PEER, 0, 0); return (0); } else if (strcasecmp(s, "BLACKHOLE") == 0) { - c->as = COMMUNITY_WELLKNOWN; - c->type = COMMUNITY_BLACKHOLE; + setcommunity(c, COMMUNITY_WELLKNOWN, + COMMUNITY_BLACKHOLE, 0, 0); return (0); } @@ -3533,49 +3549,10 @@ parsecommunity(struct filter_community *c, char *s) } *p++ = 0; - if ((i = getcommunity(s, 0)) == COMMUNITY_ERROR) - return (-1); - as = i; - - if ((i = getcommunity(p, 0)) == COMMUNITY_ERROR) - return (-1); - c->as = as; - c->type = i; - - return (0); -} - -int -parselargecommunity(struct filter_largecommunity *c, char *s) -{ - char *p, *q; - int64_t as, ld1, ld2; - - if ((p = strchr(s, ':')) == NULL) { - yyerror("Bad community syntax"); - return (-1); - } - *p++ = 0; - - if ((q = strchr(p, ':')) == NULL) { - yyerror("Bad community syntax"); - return (-1); - } - *q++ = 0; - - if ((as = getcommunity(s, 1)) == COMMUNITY_ERROR) - return (-1); - - if ((ld1 = getcommunity(p, 1)) == COMMUNITY_ERROR) + if (getcommunity(s, 0, &as, &asflag) == -1 || + getcommunity(p, 0, &data, &dataflag) == -1) return (-1); - - if ((ld2 = getcommunity(q, 1)) == COMMUNITY_ERROR) - return (-1); - - c->as = as; - c->ld1 = ld1; - c->ld2 = ld2; - + setcommunity(c, as, data, asflag, dataflag); return (0); } @@ -4218,10 +4195,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_LARGE_COMMUNITY) - yyerror("large-community is already set"); - else if (s->type == ACTION_DEL_LARGE_COMMUNITY) - yyerror("large-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) @@ -4243,21 +4216,9 @@ merge_filterset(struct filter_set_head *sh, struct filter_set *s) switch (s->type) { case ACTION_SET_COMMUNITY: case ACTION_DEL_COMMUNITY: - if (s->action.community.as < - t->action.community.as || - (s->action.community.as == - t->action.community.as && - s->action.community.type < - t->action.community.type)) { - TAILQ_INSERT_BEFORE(t, s, entry); - return (0); - } - break; - case ACTION_SET_LARGE_COMMUNITY: - case ACTION_DEL_LARGE_COMMUNITY: - if (memcmp(&s->action.large_community, - &t->action.large_community, - sizeof(s->action.large_community)) < 0) { + if (memcmp(&s->action.community, + &t->action.community, + sizeof(s->action.community)) < 0) { TAILQ_INSERT_BEFORE(t, s, entry); return (0); } @@ -4321,8 +4282,6 @@ get_rule(enum action_types type) r->quick = 0; r->dir = out ? DIR_OUT : DIR_IN; r->action = ACTION_NONE; - r->match.community.as = COMMUNITY_UNSET; - r->match.large_community.as = COMMUNITY_UNSET; TAILQ_INIT(&r->set); if (curpeer == curgroup) { /* group */ diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c index e9dfebdffa4..3f7fcaa6266 100644 --- a/usr.sbin/bgpd/printconf.c +++ b/usr.sbin/bgpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.123 2018/09/29 08:11:11 claudio Exp $ */ +/* $OpenBSD: printconf.c,v 1.124 2018/11/28 08:32:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -30,7 +30,8 @@ #include "log.h" void print_prefix(struct filter_prefix *p); -void print_community(int, int); +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); @@ -104,61 +105,100 @@ print_prefix(struct filter_prefix *p) } } -void -print_community(int as, int type) +const char * +community_type(struct filter_community *c) { - if (as == COMMUNITY_ANY) - printf("*:"); - else if (as == COMMUNITY_NEIGHBOR_AS) - printf("neighbor-as:"); - else if (as == COMMUNITY_LOCAL_AS) - printf("local-as:"); - else - printf("%u:", (unsigned int)as); - - if (type == COMMUNITY_ANY) - printf("* "); - else if (type == COMMUNITY_NEIGHBOR_AS) - printf("neighbor-as "); - else if (type == COMMUNITY_LOCAL_AS) - printf("local-as"); - else - printf("%d ", type); + switch (c->type) { + case COMMUNITY_TYPE_BASIC: + return "community"; + case COMMUNITY_TYPE_LARGE: + return "large-community"; + default: + return "???"; + } } void -print_largecommunity(int64_t as, int64_t ld1, int64_t ld2) +print_community(struct filter_community *c) { - if (as == COMMUNITY_ANY) - printf("*:"); - else if (as == COMMUNITY_NEIGHBOR_AS) - printf("neighbor-as:"); - else if (as == COMMUNITY_LOCAL_AS) - printf("local-as:"); - else - printf("%lld:", as); - - if (ld1 == COMMUNITY_ANY) - printf("*:"); - else if (ld1 == COMMUNITY_NEIGHBOR_AS) - printf("neighbor-as:"); - else if (ld1 == COMMUNITY_LOCAL_AS) - printf("local-as:"); - else - printf("%lld:", ld1); - - if (ld2 == COMMUNITY_ANY) - printf("* "); - else if (ld2 == COMMUNITY_NEIGHBOR_AS) - printf("neighbor-as "); - else if (ld2 == COMMUNITY_LOCAL_AS) - printf("local-as "); - else - printf("%lld ", ld2); - + switch (c->type) { + case COMMUNITY_TYPE_BASIC: + switch (c->dflag1) { + case COMMUNITY_ANY: + printf("*:"); + break; + case COMMUNITY_NEIGHBOR_AS: + printf("neighbor-as:"); + break; + case COMMUNITY_LOCAL_AS: + printf("local-as:"); + break; + default: + printf("%u:", c->data1); + break; + } + switch (c->dflag2) { + case COMMUNITY_ANY: + printf("* "); + break; + case COMMUNITY_NEIGHBOR_AS: + printf("neighbor-as "); + break; + case COMMUNITY_LOCAL_AS: + printf("local-as "); + break; + default: + printf("%u ", c->data2); + break; + } + break; + case COMMUNITY_TYPE_LARGE: + switch (c->dflag1) { + case COMMUNITY_ANY: + printf("*:"); + break; + case COMMUNITY_NEIGHBOR_AS: + printf("neighbor-as:"); + break; + case COMMUNITY_LOCAL_AS: + printf("local-as:"); + break; + default: + printf("%u:", c->data1); + break; + } + switch (c->dflag2) { + case COMMUNITY_ANY: + printf("*:"); + break; + case COMMUNITY_NEIGHBOR_AS: + printf("neighbor-as:"); + break; + case COMMUNITY_LOCAL_AS: + printf("local-as:"); + break; + default: + printf("%u:", c->data2); + break; + } + switch (c->dflag3) { + case COMMUNITY_ANY: + printf("* "); + break; + case COMMUNITY_NEIGHBOR_AS: + printf("neighbor-as "); + break; + case COMMUNITY_LOCAL_AS: + printf("local-as "); + break; + default: + printf("%u ", c->data3); + break; + } + break; + } } - void print_extcommunity(struct filter_extcommunity *c) { @@ -263,30 +303,13 @@ print_set(struct filter_set_head *set) printf("prepend-neighbor %u ", s->action.prepend); break; case ACTION_DEL_COMMUNITY: - printf("community delete "); - print_community(s->action.community.as, - s->action.community.type); - printf(" "); + printf("%s delete ", + community_type(&s->action.community)); + print_community(&s->action.community); break; case ACTION_SET_COMMUNITY: - printf("community "); - print_community(s->action.community.as, - s->action.community.type); - printf(" "); - break; - case ACTION_DEL_LARGE_COMMUNITY: - printf("large-community delete "); - print_largecommunity(s->action.large_community.as, - s->action.large_community.ld1, - s->action.large_community.ld2); - printf(" "); - break; - case ACTION_SET_LARGE_COMMUNITY: - printf("large-community "); - print_largecommunity(s->action.large_community.as, - s->action.large_community.ld1, - s->action.large_community.ld2); - printf(" "); + printf("%s ", community_type(&s->action.community)); + print_community(&s->action.community); break; case ACTION_PFTABLE: printf("pftable %s ", s->action.pftable); @@ -715,7 +738,8 @@ void print_as(struct filter_rule *r) void print_rule(struct peer *peer_l, struct filter_rule *r) { - struct peer *p; + struct peer *p; + int i; if (r->action == ACTION_ALLOW) printf("allow "); @@ -817,21 +841,17 @@ print_rule(struct peer *peer_l, struct filter_rule *r) "max-as-len" : "max-as-seq", r->match.aslen.aslen); } - if (r->match.community.as != COMMUNITY_UNSET) { - printf("community "); - print_community(r->match.community.as, - r->match.community.type); + for (i = 0; i < MAX_COMM_MATCH; i++) { + struct filter_community *c = &r->match.community[i]; + if (c->type != COMMUNITY_TYPE_NONE) { + 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); } - if (r->match.large_community.as != COMMUNITY_UNSET) { - printf("large-community "); - print_largecommunity(r->match.large_community.as, - r->match.large_community.ld1, - r->match.large_community.ld2); - } print_set(&r->set); diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 26b06cfa6ed..2692890b0ce 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.449 2018/11/10 11:19:01 denis Exp $ */ +/* $OpenBSD: rde.c,v 1.450 2018/11/28 08:32:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -583,10 +583,6 @@ badnetdel: break; case IMSG_CTL_SHOW_NETWORK: case IMSG_CTL_SHOW_RIB: - case IMSG_CTL_SHOW_RIB_AS: - case IMSG_CTL_SHOW_RIB_COMMUNITY: - case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY: - case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY: case IMSG_CTL_SHOW_RIB_PREFIX: if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) { log_warnx("rde_dispatch: wrong imsg len"); @@ -2224,21 +2220,24 @@ rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req) if ((req->flags & F_CTL_INVALID) && (asp->flags & F_ATTR_PARSE_ERR) == 0) return; - if (req->type == IMSG_CTL_SHOW_RIB_AS && - !aspath_match(asp->aspath->data, asp->aspath->len, - &req->as, 0)) + if (req->as.type != AS_UNDEF && !aspath_match(asp->aspath->data, + asp->aspath->len, &req->as, 0)) return; - if (req->type == IMSG_CTL_SHOW_RIB_COMMUNITY && - !community_match(asp, req->community.as, - req->community.type)) - return; - if (req->type == IMSG_CTL_SHOW_RIB_EXTCOMMUNITY && + switch (req->community.type) { + case COMMUNITY_TYPE_NONE: + break; + case COMMUNITY_TYPE_BASIC: + if (!community_match(asp, &req->community, NULL)) + return; + break; + case COMMUNITY_TYPE_LARGE: + if (!community_large_match(asp, &req->community, NULL)) + return; + break; + } + if (req->extcommunity.flags == EXT_COMMUNITY_FLAG_VALID && !community_ext_match(asp, &req->extcommunity, 0)) return; - if (req->type == IMSG_CTL_SHOW_RIB_LARGECOMMUNITY && - !community_large_match(asp, req->large_community.as, - req->large_community.ld1, req->large_community.ld2)) - return; if (!ovs_match(p, req->flags)) return; rde_dump_rib_as(p, asp, req->pid, req->flags); @@ -2334,10 +2333,6 @@ rde_dump_ctx_new(struct ctl_show_rib_request *req, pid_t pid, goto nomem; break; case IMSG_CTL_SHOW_RIB: - case IMSG_CTL_SHOW_RIB_AS: - case IMSG_CTL_SHOW_RIB_COMMUNITY: - case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY: - case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY: if (rib_dump_new(rid, ctx->req.aid, CTL_MSG_HIGH_MARK, ctx, rde_dump_upcall, rde_dump_done, rde_dump_throttled) == -1) goto nomem; diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h index f98c23243ee..0ee5964de04 100644 --- a/usr.sbin/bgpd/rde.h +++ b/usr.sbin/bgpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.202 2018/11/04 12:34:54 claudio Exp $ */ +/* $OpenBSD: rde.h,v 1.203 2018/11/28 08:32:27 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and @@ -361,25 +361,28 @@ int aspath_loopfree(struct aspath *, u_int32_t); int aspath_compare(struct aspath *, struct aspath *); u_char *aspath_prepend(struct aspath *, u_int32_t, int, u_int16_t *); int aspath_lenmatch(struct aspath *, enum aslen_spec, u_int); -int community_match(struct rde_aspath *, int, int); -int community_set(struct rde_aspath *, int, int); -void community_delete(struct rde_aspath *, int, int); -int community_large_match(struct rde_aspath *, int64_t, int64_t, - int64_t); -int community_large_set(struct rde_aspath *, int64_t, int64_t, - int64_t); -void community_large_delete(struct rde_aspath *, int64_t, - int64_t, int64_t); -int community_ext_match(struct rde_aspath *, - struct filter_extcommunity *, u_int16_t); -int community_ext_set(struct rde_aspath *, - struct filter_extcommunity *, u_int16_t); -void community_ext_delete(struct rde_aspath *, - struct filter_extcommunity *, u_int16_t); -int community_ext_conv(struct filter_extcommunity *, u_int16_t, - u_int64_t *); -u_char *community_ext_delete_non_trans(u_char *, u_int16_t, - u_int16_t *); + +int community_match(struct rde_aspath *, struct filter_community *, + struct rde_peer *); +int community_set(struct rde_aspath *, struct filter_community *, + struct rde_peer *); +void community_delete(struct rde_aspath *, struct filter_community *, + struct rde_peer *); +int community_large_match(struct rde_aspath *, struct filter_community *, + struct rde_peer *); +int community_large_set(struct rde_aspath *, struct filter_community *, + struct rde_peer *); +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); +int community_ext_set(struct rde_aspath *, + struct filter_extcommunity *, u_int16_t); +void community_ext_delete(struct rde_aspath *, + struct filter_extcommunity *, u_int16_t); +int community_ext_conv(struct filter_extcommunity *, u_int16_t, + u_int64_t *); +u_char *community_ext_delete_non_trans(u_char *, u_int16_t, u_int16_t *); /* rde_decide.c */ void prefix_evaluate(struct prefix *, struct rib_entry *); diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c index 21b4fbf5f61..897c3a370ca 100644 --- a/usr.sbin/bgpd/rde_attr.c +++ b/usr.sbin/bgpd/rde_attr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_attr.c,v 1.112 2018/10/10 06:21:47 deraadt Exp $ */ +/* $OpenBSD: rde_attr.c,v 1.113 2018/11/28 08:32:27 claudio Exp $ */ /* * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> @@ -995,18 +995,65 @@ aspath_lenmatch(struct aspath *a, enum aslen_spec type, u_int aslen) 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) +{ + u_int32_t data; + u_int8_t flag; + switch (field) { + case 1: + flag = fc->dflag1; + data = fc->data1; + break; + case 2: + flag = fc->dflag2; + data = fc->data2; + break; + case 3: + flag = fc->dflag3; + data = fc->data3; + break; + default: + fatalx("%s: unknown field %d", __func__, field); + } + + switch (flag) { + case COMMUNITY_NEIGHBOR_AS: + if (peer == NULL) + return -1; + *value = peer->conf.remote_as; + case COMMUNITY_LOCAL_AS: + if (peer == NULL) + return -1; + *value = peer->conf.local_as; + default: + *value = data; + } + if (!large && *value > USHRT_MAX) + return -1; + return 0; +} + int -community_match(struct rde_aspath *asp, int as, int type) +community_match(struct rde_aspath *asp, struct filter_community *fc, + struct rde_peer *peer) { struct attr *a; u_int8_t *p; - u_int16_t eas, etype, len; + u_int32_t as, type, eas, etype; + u_int16_t len; a = attr_optget(asp, ATTR_COMMUNITIES); if (a == NULL) /* no communities, no match */ return (0); + if (community_extract(fc, peer, 1, 0, &as) == -1 || + community_extract(fc, peer, 2, 0, &type) == -1) + /* can't match community */ + return (0); + p = a->data; for (len = a->len / 4; len > 0; len--) { eas = *p++; @@ -1015,21 +1062,29 @@ community_match(struct rde_aspath *asp, int as, int type) etype = *p++; etype <<= 8; etype |= *p++; - if ((as == COMMUNITY_ANY || (u_int16_t)as == eas) && - (type == COMMUNITY_ANY || (u_int16_t)type == etype)) + if ((fc->dflag1 == COMMUNITY_ANY || as == eas) && + (fc->dflag2 == COMMUNITY_ANY || type == etype)) return (1); } return (0); } int -community_set(struct rde_aspath *asp, int as, int type) +community_set(struct rde_aspath *asp, struct filter_community *fc, + struct rde_peer *peer) { struct attr *attr; u_int8_t *p = NULL; unsigned int i, ncommunities = 0; + u_int32_t as, type; u_int8_t f = ATTR_OPTIONAL|ATTR_TRANSITIVE; + if (fc->dflag1 == COMMUNITY_ANY || fc->dflag2 == COMMUNITY_ANY || + community_extract(fc, peer, 1, 0, &as) == -1 || + community_extract(fc, peer, 2, 0, &type) == -1) + /* bad community */ + return (0); + attr = attr_optget(asp, ATTR_COMMUNITIES); if (attr != NULL) { p = attr->data; @@ -1070,12 +1125,13 @@ community_set(struct rde_aspath *asp, int as, int type) } void -community_delete(struct rde_aspath *asp, int as, int type) +community_delete(struct rde_aspath *asp, struct filter_community *fc, + struct rde_peer *peer) { struct attr *attr; u_int8_t *p, *n; u_int16_t l, len = 0; - u_int16_t eas, etype; + u_int32_t as, type, eas, etype; u_int8_t f; attr = attr_optget(asp, ATTR_COMMUNITIES); @@ -1083,6 +1139,11 @@ community_delete(struct rde_aspath *asp, int as, int type) /* no attr nothing to do */ return; + if (community_extract(fc, peer, 1, 0, &as) == -1 || + community_extract(fc, peer, 2, 0, &type) == -1) + /* bad community, nothing to do */ + return; + p = attr->data; for (l = 0; l < attr->len; l += 4) { eas = *p++; @@ -1092,8 +1153,8 @@ community_delete(struct rde_aspath *asp, int as, int type) etype <<= 8; etype |= *p++; - if ((as == COMMUNITY_ANY || (u_int16_t)as == eas) && - (type == COMMUNITY_ANY || (u_int16_t)type == etype)) + if ((fc->dflag1 == COMMUNITY_ANY || as == eas) && + (fc->dflag2 == COMMUNITY_ANY || type == etype)) /* match */ continue; len += 4; @@ -1116,8 +1177,8 @@ community_delete(struct rde_aspath *asp, int as, int type) etype <<= 8; etype |= *p++; - if ((as == COMMUNITY_ANY || (u_int16_t)as == eas) && - (type == COMMUNITY_ANY || (u_int16_t)type == etype)) + if ((fc->dflag1 == COMMUNITY_ANY || as == eas) && + (fc->dflag2 == COMMUNITY_ANY || type == etype)) /* match */ continue; n[l++] = eas >> 8; @@ -1382,46 +1443,66 @@ struct wire_largecommunity { }; int -community_large_match(struct rde_aspath *asp, int64_t as, int64_t ld1, - int64_t ld2) +community_large_match(struct rde_aspath *asp, struct filter_community *fc, + struct rde_peer *peer) { - struct wire_largecommunity *bar; + struct wire_largecommunity *wlc; struct attr *a; u_int8_t *p; u_int16_t len; - u_int32_t eas, eld1, eld2; + u_int32_t as, ld1, ld2; a = attr_optget(asp, ATTR_LARGE_COMMUNITIES); if (a == NULL) /* no communities, no match */ return (0); + if (community_extract(fc, peer, 1, 1, &as) == -1 || + community_extract(fc, peer, 2, 1, &ld1) == -1 || + community_extract(fc, peer, 3, 1, &ld2) == -1) + /* can't match community */ + return (0); + + as = htonl(as); + ld1 = htonl(ld1); + ld2 = htonl(ld2); + p = a->data; for (len = a->len / 12; len > 0; len--) { - bar = (struct wire_largecommunity *)p; + wlc = (struct wire_largecommunity *)p; p += 12; - eas = betoh32(bar->as); - eld1 = betoh32(bar->ld1); - eld2 = betoh32(bar->ld2); - if ((as == COMMUNITY_ANY || as == eas) && - (ld1 == COMMUNITY_ANY || ld1 == eld1) && - (ld2 == COMMUNITY_ANY || ld2 == eld2)) + if ((fc->dflag1 == COMMUNITY_ANY || as == wlc->as) && + (fc->dflag2 == COMMUNITY_ANY || ld1 == wlc->ld1) && + (fc->dflag3 == COMMUNITY_ANY || ld2 == wlc->ld2)) return (1); } return (0); } int -community_large_set(struct rde_aspath *asp, int64_t as, int64_t ld1, - int64_t ld2) +community_large_set(struct rde_aspath *asp, struct filter_community *fc, + struct rde_peer *peer) { - struct wire_largecommunity *bar; + struct wire_largecommunity *wlc; struct attr *attr; u_int8_t *p = NULL; unsigned int i, ncommunities = 0; + u_int32_t as, ld1, ld2; u_int8_t f = ATTR_OPTIONAL|ATTR_TRANSITIVE; + if (fc->dflag1 == COMMUNITY_ANY || fc->dflag2 == COMMUNITY_ANY || + fc->dflag3 == COMMUNITY_ANY || + community_extract(fc, peer, 1, 1, &as) == -1 || + community_extract(fc, peer, 2, 1, &ld1) == -1 || + community_extract(fc, peer, 3, 1, &ld2) == -1) + /* can't match community */ + return (0); + + as = htonl(as); + ld1 = htonl(ld1); + ld2 = htonl(ld2); + attr = attr_optget(asp, ATTR_LARGE_COMMUNITIES); if (attr != NULL) { p = attr->data; @@ -1430,9 +1511,8 @@ community_large_set(struct rde_aspath *asp, int64_t as, int64_t ld1, /* first check if the community is not already set */ for (i = 0; i < ncommunities; i++) { - bar = (struct wire_largecommunity *)p; - if (bar->as == htobe32(as) && bar->ld1 == htobe32(ld1) && - bar->ld2 == htobe32(ld2)) + wlc = (struct wire_largecommunity *)p; + if (wlc->as == as && wlc->ld1 == ld1 && wlc->ld2 == ld2) /* already present, nothing todo */ return (1); p += 12; @@ -1445,10 +1525,10 @@ community_large_set(struct rde_aspath *asp, int64_t as, int64_t ld1, if ((p = reallocarray(NULL, ncommunities, 12)) == NULL) fatal("community_set"); - bar = (struct wire_largecommunity *)p; - bar->as = htobe32(as); - bar->ld1 = htobe32(ld1); - bar->ld2 = htobe32(ld2); + wlc = (struct wire_largecommunity *)p; + wlc->as = as; + wlc->ld1 = ld1; + wlc->ld2 = ld2; if (attr != NULL) { memcpy(p + 12, attr->data, attr->len); @@ -1463,14 +1543,14 @@ community_large_set(struct rde_aspath *asp, int64_t as, int64_t ld1, } void -community_large_delete(struct rde_aspath *asp, int64_t as, int64_t ld1, - int64_t ld2) +community_large_delete(struct rde_aspath *asp, struct filter_community *fc, + struct rde_peer *peer) { - struct wire_largecommunity *bar; + struct wire_largecommunity *wlc; struct attr *attr; u_int8_t *p, *n; u_int16_t l = 0, len = 0; - u_int32_t eas, eld1, eld2; + u_int32_t as, ld1, ld2; u_int8_t f; attr = attr_optget(asp, ATTR_LARGE_COMMUNITIES); @@ -1478,17 +1558,24 @@ community_large_delete(struct rde_aspath *asp, int64_t as, int64_t ld1, /* no attr nothing to do */ return; + if (community_extract(fc, peer, 1, 1, &as) == -1 || + community_extract(fc, peer, 2, 1, &ld1) == -1 || + community_extract(fc, peer, 3, 1, &ld2) == -1) + /* can't match community */ + return; + + as = htonl(as); + ld1 = htonl(ld1); + ld2 = htonl(ld2); + p = attr->data; for (len = 0; l < attr->len; l += 12) { - bar = (struct wire_largecommunity *)p; + wlc = (struct wire_largecommunity *)p; p += 12; - eas = betoh32(bar->as); - eld1 = betoh32(bar->ld1); - eld2 = betoh32(bar->ld2); - if ((as == COMMUNITY_ANY || as == eas) && - (ld1 == COMMUNITY_ANY || ld1 == eld1) && - (ld2 == COMMUNITY_ANY || ld2 == eld2)) + if ((fc->dflag1 == COMMUNITY_ANY || as == wlc->as) && + (fc->dflag2 == COMMUNITY_ANY || ld1 == wlc->ld1) && + (fc->dflag3 == COMMUNITY_ANY || ld2 == wlc->ld2)) /* match */ continue; len += 12; @@ -1504,18 +1591,15 @@ community_large_delete(struct rde_aspath *asp, int64_t as, int64_t ld1, p = attr->data; for (l = 0; l < len && p < attr->data + attr->len; ) { - bar = (struct wire_largecommunity *)p; + wlc = (struct wire_largecommunity *)p; p += 12; - eas = betoh32(bar->as); - eld1 = betoh32(bar->ld1); - eld2 = betoh32(bar->ld2); - if ((as == COMMUNITY_ANY || as == eas) && - (ld1 == COMMUNITY_ANY || ld1 == eld1) && - (ld2 == COMMUNITY_ANY || ld2 == eld2)) + if ((fc->dflag1 == COMMUNITY_ANY || as == wlc->as) && + (fc->dflag2 == COMMUNITY_ANY || ld1 == wlc->ld1) && + (fc->dflag3 == COMMUNITY_ANY || ld2 == wlc->ld2)) /* match */ continue; - memcpy(n + l, bar, sizeof(*bar)); + memcpy(n + l, wlc, sizeof(*wlc)); l += 12; } @@ -1526,7 +1610,6 @@ community_large_delete(struct rde_aspath *asp, int64_t as, int64_t ld1, free(n); } - u_char * community_ext_delete_non_trans(u_char *data, u_int16_t len, u_int16_t *newlen) { diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c index 79d2bd1728c..d731bed35cc 100644 --- a/usr.sbin/bgpd/rde_filter.c +++ b/usr.sbin/bgpd/rde_filter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_filter.c,v 1.113 2018/11/14 14:03:36 claudio Exp $ */ +/* $OpenBSD: rde_filter.c,v 1.114 2018/11/28 08:32:27 claudio Exp $ */ /* * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> @@ -40,8 +40,6 @@ rde_apply_set(struct filter_set_head *sh, struct filterstate *state, { struct filter_set *set; u_char *np; - int as, type; - int64_t las, ld1, ld2; u_int32_t prep_as; u_int16_t nl; u_int8_t prepend; @@ -142,172 +140,28 @@ rde_apply_set(struct filter_set_head *sh, struct filterstate *state, &state->nexthop, &state->nhflags); break; case ACTION_SET_COMMUNITY: - switch (set->action.community.as) { - case COMMUNITY_ERROR: - case COMMUNITY_ANY: - fatalx("%s: bad community string", __func__); - case COMMUNITY_NEIGHBOR_AS: - as = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - as = peer->conf.local_as; - break; - default: - as = set->action.community.as; - break; - } - switch (set->action.community.type) { - case COMMUNITY_ERROR: - case COMMUNITY_ANY: - fatalx("%s: bad community string", __func__); - case COMMUNITY_NEIGHBOR_AS: - type = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - type = peer->conf.local_as; + case COMMUNITY_TYPE_BASIC: + community_set(&state->aspath, + &set->action.community, peer); break; - default: - type = set->action.community.type; + case COMMUNITY_TYPE_LARGE: + community_large_set(&state->aspath, + &set->action.community, peer); break; } - - community_set(&state->aspath, as, type); break; case ACTION_DEL_COMMUNITY: - switch (set->action.community.as) { - case COMMUNITY_ERROR: - fatalx("%s: bad community string", __func__); - case COMMUNITY_NEIGHBOR_AS: - as = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - as = peer->conf.local_as; - break; - case COMMUNITY_ANY: - default: - as = set->action.community.as; - break; - } - switch (set->action.community.type) { - case COMMUNITY_ERROR: - fatalx("%s: bad community string", __func__); - case COMMUNITY_NEIGHBOR_AS: - type = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - type = peer->conf.local_as; - break; - case COMMUNITY_ANY: - default: - type = set->action.community.type; - break; - } - - community_delete(&state->aspath, as, type); - break; - case ACTION_SET_LARGE_COMMUNITY: - switch (set->action.large_community.as) { - case COMMUNITY_ERROR: - fatalx("%s: bad large community string", - __func__); - case COMMUNITY_NEIGHBOR_AS: - las = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - las = peer->conf.local_as; - break; - case COMMUNITY_ANY: - default: - las = set->action.large_community.as; - break; - } - - switch (set->action.large_community.ld1) { - case COMMUNITY_ERROR: - fatalx("%s: bad large community string", - __func__); - case COMMUNITY_NEIGHBOR_AS: - ld1 = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - ld1 = peer->conf.local_as; + case COMMUNITY_TYPE_BASIC: + community_delete(&state->aspath, + &set->action.community, peer); break; - case COMMUNITY_ANY: - default: - ld1 = set->action.large_community.ld1; + case COMMUNITY_TYPE_LARGE: + community_large_delete(&state->aspath, + &set->action.community, peer); break; } - - switch (set->action.large_community.ld2) { - case COMMUNITY_ERROR: - fatalx("%s: bad large community string", - __func__); - case COMMUNITY_NEIGHBOR_AS: - ld2 = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - ld2 = peer->conf.local_as; - break; - case COMMUNITY_ANY: - default: - ld2 = set->action.large_community.ld2; - break; - } - - community_large_set(&state->aspath, las, ld1, ld2); - break; - case ACTION_DEL_LARGE_COMMUNITY: - switch (set->action.large_community.as) { - case COMMUNITY_ERROR: - fatalx("%s: bad large community string", - __func__); - case COMMUNITY_NEIGHBOR_AS: - las = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - las = peer->conf.local_as; - break; - case COMMUNITY_ANY: - default: - las = set->action.large_community.as; - break; - } - - switch (set->action.large_community.ld1) { - case COMMUNITY_ERROR: - fatalx("%s: bad large community string", - __func__); - case COMMUNITY_NEIGHBOR_AS: - ld1 = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - ld1 = peer->conf.local_as; - break; - case COMMUNITY_ANY: - default: - ld1 = set->action.large_community.ld1; - break; - } - - switch (set->action.large_community.ld2) { - case COMMUNITY_ERROR: - fatalx("%s: bad large community string", - __func__); - case COMMUNITY_NEIGHBOR_AS: - ld2 = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - ld2 = peer->conf.local_as; - break; - case COMMUNITY_ANY: - default: - ld2 = set->action.large_community.ld2; - break; - } - - community_large_delete(&state->aspath, las, ld1, ld2); break; case ACTION_PFTABLE: /* convert pftable name to an id */ @@ -348,9 +202,8 @@ int rde_filter_match(struct filter_rule *f, struct rde_peer *peer, struct filterstate *state, struct prefix *p) { - int cas, type; - int64_t las, ld1, ld2; - struct rde_aspath *asp = NULL; + struct rde_aspath *asp = NULL; + int i; if (state != NULL) asp = &state->aspath; @@ -376,89 +229,28 @@ rde_filter_match(struct filter_rule *f, struct rde_peer *peer, f->match.aslen.aslen) == 0) return (0); - if (asp != NULL && f->match.community.as != COMMUNITY_UNSET) { - switch (f->match.community.as) { - case COMMUNITY_ERROR: - fatalx("rde_filter_match bad community string"); - case COMMUNITY_NEIGHBOR_AS: - cas = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - cas = peer->conf.local_as; - break; - default: - cas = f->match.community.as; - break; - } - - switch (f->match.community.type) { - case COMMUNITY_ERROR: - fatalx("rde_filter_match bad community string"); - case COMMUNITY_NEIGHBOR_AS: - type = peer->conf.remote_as; + for (i = 0; asp != NULL && i < MAX_COMM_MATCH; i++) { + switch (f->match.community[i].type) { + case COMMUNITY_TYPE_NONE: + i = MAX_COMM_MATCH; break; - case COMMUNITY_LOCAL_AS: - type = peer->conf.local_as; + case COMMUNITY_TYPE_BASIC: + if (community_match(asp, &f->match.community[i], + peer) == 0) + return (0); break; - default: - type = f->match.community.type; + case COMMUNITY_TYPE_LARGE: + if (community_large_match(asp, &f->match.community[i], + peer) == 0) + return (0); break; } - - if (community_match(asp, cas, type) == 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 (asp != NULL && f->match.large_community.as != COMMUNITY_UNSET) { - switch (f->match.large_community.as) { - case COMMUNITY_ERROR: - fatalx("rde_filter_match bad community string"); - case COMMUNITY_NEIGHBOR_AS: - las = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - las = peer->conf.local_as; - break; - default: - las = f->match.large_community.as; - break; - } - - switch (f->match.large_community.ld1) { - case COMMUNITY_ERROR: - fatalx("rde_filter_match bad community string"); - case COMMUNITY_NEIGHBOR_AS: - ld1 = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - ld1 = peer->conf.local_as; - break; - default: - ld1 = f->match.large_community.ld1; - break; - } - - switch (f->match.large_community.ld2) { - case COMMUNITY_ERROR: - fatalx("rde_filter_match bad community string"); - case COMMUNITY_NEIGHBOR_AS: - ld2 = peer->conf.remote_as; - break; - case COMMUNITY_LOCAL_AS: - ld2 = peer->conf.local_as; - break; - default: - ld2 = f->match.large_community.ld2; - break; - } - - if (community_large_match(asp, las, ld1, ld2) == 0) - return (0); - } if (state != NULL && f->match.nexthop.flags != 0) { struct bgpd_addr *nexthop, *cmpaddr; @@ -744,11 +536,8 @@ filterset_cmp(struct filter_set *a, struct filter_set *b) if (a->type == ACTION_SET_COMMUNITY || a->type == ACTION_DEL_COMMUNITY) { /* a->type == b->type */ - /* compare community */ - if (a->action.community.as - b->action.community.as != 0) - return (a->action.community.as - - b->action.community.as); - return (a->action.community.type - b->action.community.type); + return (memcmp(&a->action.community, &b->action.community, + sizeof(a->action.community))); } if (a->type == ACTION_SET_EXT_COMMUNITY || @@ -757,21 +546,6 @@ filterset_cmp(struct filter_set *a, struct filter_set *b) &b->action.ext_community, sizeof(a->action.ext_community))); } - if (a->type == ACTION_SET_LARGE_COMMUNITY || - a->type == ACTION_DEL_LARGE_COMMUNITY) { /* a->type == b->type */ - /* compare community */ - if (a->action.large_community.as - - b->action.large_community.as != 0) - return (a->action.large_community.as - - b->action.large_community.as); - if (a->action.large_community.ld1 - - b->action.large_community.ld1 != 0) - return (a->action.large_community.ld1 - - b->action.large_community.ld1); - return (a->action.large_community.ld2 - - b->action.large_community.ld2); - } - if (a->type == ACTION_SET_NEXTHOP && b->type == ACTION_SET_NEXTHOP) { /* * This is the only interesting case, all others are considered @@ -845,14 +619,6 @@ filterset_equal(struct filter_set_head *ah, struct filter_set_head *bh) sizeof(a->action.community)) == 0) continue; break; - case ACTION_DEL_LARGE_COMMUNITY: - case ACTION_SET_LARGE_COMMUNITY: - if (a->type == b->type && - memcmp(&a->action.large_community, - &b->action.large_community, - sizeof(a->action.large_community)) == 0) - continue; - break; case ACTION_PFTABLE: case ACTION_PFTABLE_ID: if (b->type == ACTION_PFTABLE) @@ -936,10 +702,6 @@ filterset_name(enum action_types type) return ("community"); case ACTION_DEL_COMMUNITY: return ("community delete"); - case ACTION_SET_LARGE_COMMUNITY: - return ("large-community"); - case ACTION_DEL_LARGE_COMMUNITY: - return ("large-community delete"); case ACTION_PFTABLE: case ACTION_PFTABLE_ID: return ("pftable"); diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c index a20922782b1..8157342058e 100644 --- a/usr.sbin/bgpd/rde_update.c +++ b/usr.sbin/bgpd/rde_update.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_update.c,v 1.103 2018/11/04 12:34:54 claudio Exp $ */ +/* $OpenBSD: rde_update.c,v 1.104 2018/11/28 08:32:27 claudio Exp $ */ /* * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> @@ -66,6 +66,22 @@ RB_GENERATE(uptree_attr, update_attr, entry, up_attr_cmp) SIPHASH_KEY uptree_key; +static struct filter_community comm_no_advertise = { + .type = COMMUNITY_TYPE_BASIC, + .data1 = COMMUNITY_WELLKNOWN, + .data2 = COMMUNITY_NO_ADVERTISE +}; +static struct filter_community comm_no_export = { + .type = COMMUNITY_TYPE_BASIC, + .data1 = COMMUNITY_WELLKNOWN, + .data2 = COMMUNITY_NO_EXPORT +}; +static struct filter_community comm_no_expsubconfed = { + .type = COMMUNITY_TYPE_BASIC, + .data1 = COMMUNITY_WELLKNOWN, + .data2 = COMMUNITY_NO_EXPSUBCONFED +}; + void up_init(struct rde_peer *peer) { @@ -329,14 +345,14 @@ up_test_update(struct rde_peer *peer, struct prefix *p) } /* well known communities */ - if (community_match(asp, COMMUNITY_WELLKNOWN, COMMUNITY_NO_ADVERTISE)) - return (0); - if (peer->conf.ebgp && community_match(asp, COMMUNITY_WELLKNOWN, - COMMUNITY_NO_EXPORT)) - return (0); - if (peer->conf.ebgp && community_match(asp, COMMUNITY_WELLKNOWN, - COMMUNITY_NO_EXPSUBCONFED)) + if (community_match(asp, &comm_no_advertise, NULL)) return (0); + if (peer->conf.ebgp) { + if (community_match(asp, &comm_no_export, NULL)) + return (0); + if (community_match(asp, &comm_no_expsubconfed, NULL)) + return (0); + } /* * Don't send messages back to originator |