On Thu, Feb 07, 2019 at 11:41:39AM +0100, Claudio Jeker wrote: > At a2k19 David (dlg@) and I sat down and looked at BGP L3 MPLS VPN > support. Now David wants to use this in production and realized that > in his case it would be great to have more than one mpe(4) interface per > rdomain. This way it is possible to write good firewall rules using > interface names or groups. > > The definition of VPNs in bgpd was never super elegant. The 'depend on > mpeX' config was a bit redundant and so after some discussions we decided > to rework this part. > > L3 MPLS VPN are now configured like this: > > vpn "staff" on mpe1 { > rd $ASN:1 > import-target rt $ASN:100 > export-target rt $ASN:101 > network 0/0 > } > > vpn "users" on mpe2 { > rd $ASN:2 > import-target rt $ASN:200 > export-target rt $ASN:201 > network 0/0 > } > > Now in this example mpe1 and mpe2 can be in the same rdomain. The rdomain > is now selected based on the rdomain of the mpe(4) interface. There are > probably still some gotchas around this which can be tackled in a 2nd > round. > > This diff does a lot of shuffling of code and especially affect network > statements (since those are now per VPN and no longer per rdomain). > The rewrite of the network code fixed also some other behaviour bugs which > do not only affect VPN setups. In short conficts between 'network A.B.C.D/N' > and 'network static' are now properly handled (with 'network A.B.C.D/N' > having preference). > > Since this is a major change please test (or suffer later).
Reads good, works fine. OK denis@ While testing, I noticed that import-target/export-target are not updated on reload (problem not introduced by this diff though) > -- > :wq Claudio > > Index: usr.sbin/bgpctl/bgpctl.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v > retrieving revision 1.228 > diff -u -p -r1.228 bgpctl.c > --- usr.sbin/bgpctl/bgpctl.c 20 Jan 2019 23:30:15 -0000 1.228 > +++ usr.sbin/bgpctl/bgpctl.c 7 Feb 2019 10:11:19 -0000 > @@ -346,7 +346,7 @@ main(int argc, char *argv[]) > bzero(&net, sizeof(net)); > net.prefix = res->addr; > net.prefixlen = res->prefixlen; > - net.rtableid = tableid; > + net.rd = res->rd; > /* attribute sets are not supported */ > if (res->action == NETWORK_ADD) { > imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1, > @@ -927,7 +927,7 @@ show_fib_head(void) > printf("flags: " > "* = valid, B = BGP, C = Connected, S = Static, D = Dynamic\n"); > printf(" " > - "N = BGP Nexthop reachable via this route R = redistributed\n"); > + "N = BGP Nexthop reachable via this route\n"); > printf(" r = reject route, b = blackhole route\n\n"); > printf("flags prio destination gateway\n"); > } > @@ -969,11 +969,6 @@ show_fib_flags(u_int16_t flags) > else > printf(" "); > > - if (flags & F_REDISTRIBUTED) > - printf("R"); > - else > - printf(" "); > - > if (flags & F_REJECT && flags & F_BLACKHOLE) > printf("f"); > else if (flags & F_REJECT) > @@ -1983,7 +1978,7 @@ network_bulk(struct parse_result *res) > errx(1, "bad prefix: %s", b); > net.prefix = h; > net.prefixlen = len; > - net.rtableid = tableid; > + net.rd = res->rd; > > if (res->action == NETWORK_BULK_ADD) { > imsg_compose(ibuf, IMSG_NETWORK_ADD, > @@ -2128,7 +2123,7 @@ network_mrt_dump(struct mrt_rib *mr, str > net.prefix = ctl.prefix; > net.prefixlen = ctl.prefixlen; > net.type = NETWORK_MRTCLONE; > - /* XXX rtableid */ > + /* XXX rd can't be set and will be 0 */ > > imsg_compose(ibuf, IMSG_NETWORK_ADD, 0, 0, -1, > &net, sizeof(net)); > Index: usr.sbin/bgpctl/parser.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpctl/parser.c,v > retrieving revision 1.89 > diff -u -p -r1.89 parser.c > --- usr.sbin/bgpctl/parser.c 20 Jan 2019 23:30:15 -0000 1.89 > +++ usr.sbin/bgpctl/parser.c 7 Feb 2019 10:11:19 -0000 > @@ -58,6 +58,7 @@ enum token_type { > PREPNBR, > PREPSELF, > WEIGHT, > + RD, > FAMILY, > GETOPT, > RTABLE, > @@ -374,6 +375,11 @@ static const struct token t_network_show > { ENDTOKEN, "", NONE, NULL} > }; > > +static const struct token t_rd[] = { > + { RD, "", NONE, t_set}, > + { ENDTOKEN, "", NONE, NULL} > +}; > + > static const struct token t_set[] = { > { NOTOKEN, "", NONE, NULL}, > { KEYWORD, "community", NONE, t_community}, > @@ -386,6 +392,7 @@ static const struct token t_set[] = { > { KEYWORD, "pftable", NONE, t_pftable}, > { KEYWORD, "prepend-neighbor", NONE, t_prepnbr}, > { KEYWORD, "prepend-self", NONE, t_prepself}, > + { KEYWORD, "rd", NONE, t_rd}, > { KEYWORD, "weight", NONE, t_weight}, > { KEYWORD, "add", NETWORK_BULK_ADD, NULL}, > { KEYWORD, "delete", NETWORK_BULK_REMOVE, NULL}, > @@ -493,18 +500,14 @@ static struct parse_result res; > const struct token *match_token(int *argc, char **argv[], > const struct token []); > void show_valid_args(const struct token []); > -int parse_addr(const char *, struct bgpd_addr *); > -int parse_asnum(const char *, size_t, u_int32_t *); > -int parse_number(const char *, struct parse_result *, > - enum token_type); > -int parse_community(const char *, struct parse_result *); > -int parsesubtype(const char *, u_int8_t *, u_int8_t *); > -int parseextvalue(const char *, u_int32_t *); > -u_int parseextcommunity(const char *, struct > parse_result *); > -int parse_largecommunity(const char *, > - struct parse_result *); > -int parse_nexthop(const char *, struct parse_result *); > -int bgpctl_getopt(int *, char **[], int); > + > +int parse_addr(const char *, struct bgpd_addr *); > +int parse_asnum(const char *, size_t, u_int32_t *); > +int parse_number(const char *, struct parse_result *, enum token_type); > +void parsecommunity(struct filter_community *c, int type, char *s); > +int parseextcommunity(struct filter_community *c, const char *t, char *s); > +int parse_nexthop(const char *, struct parse_result *); > +int bgpctl_getopt(int *, char **[], int); > > struct parse_result * > parse(int argc, char *argv[]) > @@ -675,8 +678,25 @@ match_token(int *argc, char **argv[], co > } > break; > case COMMUNITY: > - if (word != NULL && wordlen > 0 && > - parse_community(word, &res)) { > + case LARGE_COMMUNITY: > + if (word != NULL && wordlen > 0) { > + int type = COMMUNITY_TYPE_BASIC; > + char *p = strdup(word); > + > + if (p == NULL) > + err(1, NULL); > + if (table[i].type == LARGE_COMMUNITY) > + type = COMMUNITY_TYPE_LARGE; > + parsecommunity(&res.community, > + COMMUNITY_TYPE_BASIC, p); > + free(p); > + > + if ((fs = calloc(1, sizeof(*fs))) == NULL) > + err(1, NULL); > + fs->type = ACTION_SET_COMMUNITY; > + fs->action.community = res.community; > + TAILQ_INSERT_TAIL(&res.set, fs, entry); > + > match++; > t = &table[i]; > } > @@ -684,24 +704,62 @@ match_token(int *argc, char **argv[], co > case EXTCOM_SUBTYPE: > if (word != NULL && strncmp(word, table[i].keyword, > wordlen) == 0) { > - if (parsesubtype(word, &res.community.c.e.type, > - &res.community.c.e.subtype) == 0) > - errx(1, "Bad ext-community unknown " > - "type"); > + res.ext_comm_subtype = table[i].keyword; > match++; > t = &table[i]; > } > break; > case EXTCOMMUNITY: > - if (word != NULL && wordlen > 0 && > - parseextcommunity(word, &res)) { > + if (word != NULL && wordlen > 0) { > + char *p = strdup(word); > + > + if (p == NULL) > + err(1, NULL); > + parseextcommunity(&res.community, > + res.ext_comm_subtype, p); > + free(p); > + > + if ((fs = calloc(1, sizeof(*fs))) == NULL) > + err(1, NULL); > + fs->type = ACTION_SET_COMMUNITY; > + fs->action.community = res.community; > + TAILQ_INSERT_TAIL(&res.set, fs, entry); > + > match++; > t = &table[i]; > } > break; > - case LARGE_COMMUNITY: > - if (word != NULL && wordlen > 0 && > - parse_largecommunity(word, &res)) { > + case RD: > + if (word != NULL && wordlen > 0) { > + char *p = strdup(word); > + struct filter_community ext; > + u_int64_t rd; > + > + if (p == NULL) > + err(1, NULL); > + parseextcommunity(&ext, "rt", p); > + free(p); > + > + switch (ext.c.e.type) { > + case EXT_COMMUNITY_TRANS_TWO_AS: > + rd = (0ULL << 48); > + rd |= (u_int64_t)ext.c.e.data1 << 32; > + rd |= ext.c.e.data2 & 0xffffffff; > + break; > + case EXT_COMMUNITY_TRANS_IPV4: > + rd = (1ULL << 48); > + rd |= (u_int64_t)ext.c.e.data1 << 16; > + rd |= ext.c.e.data2 & 0xffff; > + break; > + case EXT_COMMUNITY_TRANS_FOUR_AS: > + rd = (2ULL << 48); > + rd |= (u_int64_t)ext.c.e.data1 << 16; > + rd |= ext.c.e.data2 & 0xffff; > + break; > + default: > + errx(1, "bad encoding of rd"); > + } > + res.rd = htobe64(rd); > match++; > t = &table[i]; > } > @@ -823,11 +881,14 @@ show_valid_args(const struct token table > case COMMUNITY: > fprintf(stderr, " <community>\n"); > break; > + case LARGE_COMMUNITY: > + fprintf(stderr, " <large-community>\n"); > + break; > case EXTCOMMUNITY: > fprintf(stderr, " <extended-community>\n"); > break; > - case LARGE_COMMUNITY: > - fprintf(stderr, " <large-community>\n"); > + case RD: > + fprintf(stderr, " <route-distinguisher>\n"); > break; > case LOCALPREF: > case MED: > @@ -1035,95 +1096,118 @@ parse_number(const char *word, struct pa > return (1); > } > > -static u_int32_t > -getcommunity(const char *s, int large, u_int8_t *flag) > +static void > +getcommunity(char *s, int large, u_int32_t *val, u_int8_t *flag) > { > int64_t max = USHRT_MAX; > const char *errstr; > - u_int32_t uval; > > + *flag = 0; > + *val = 0; > if (strcmp(s, "*") == 0) { > *flag = COMMUNITY_ANY; > - return (0); > + return; > + } else if (strcmp(s, "neighbor-as") == 0) { > + *flag = COMMUNITY_NEIGHBOR_AS; > + return; > + } else if (strcmp(s, "local-as") == 0) { > + *flag = COMMUNITY_LOCAL_AS; > + return; > } > - > if (large) > max = UINT_MAX; > - > - uval = strtonum(s, 0, max, &errstr); > + *val = strtonum(s, 0, max, &errstr); > if (errstr) > - errx(1, "Community is %s: %s", errstr, s); > - > - *flag = 0; > - return (uval); > + errx(1, "Community %s is %s (max: %llu)", s, errstr, max); > } > > -int > -parse_community(const char *word, struct parse_result *r) > +static void > +setcommunity(struct filter_community *c, u_int32_t as, u_int32_t data, > + u_int8_t asflag, u_int8_t dataflag) > { > - struct filter_set *fs; > - char *p; > - u_int32_t as, type; > - u_int8_t asflag, tflag; > + memset(c, 0, sizeof(*c)); > + c->type = COMMUNITY_TYPE_BASIC; > + c->dflag1 = asflag; > + c->dflag2 = dataflag; > + c->c.b.data1 = as; > + c->c.b.data2 = data; > +} > > - /* Well-known communities */ > - if (strcasecmp(word, "GRACEFUL_SHUTDOWN") == 0) { > - as = COMMUNITY_WELLKNOWN; > - type = COMMUNITY_GRACEFUL_SHUTDOWN; > - goto done; > - } else if (strcasecmp(word, "NO_EXPORT") == 0) { > - as = COMMUNITY_WELLKNOWN; > - type = COMMUNITY_NO_EXPORT; > - goto done; > - } else if (strcasecmp(word, "NO_ADVERTISE") == 0) { > - as = COMMUNITY_WELLKNOWN; > - type = COMMUNITY_NO_ADVERTISE; > - goto done; > - } else if (strcasecmp(word, "NO_EXPORT_SUBCONFED") == 0) { > - as = COMMUNITY_WELLKNOWN; > - type = COMMUNITY_NO_EXPSUBCONFED; > - goto done; > - } else if (strcasecmp(word, "NO_PEER") == 0) { > - as = COMMUNITY_WELLKNOWN; > - type = COMMUNITY_NO_PEER; > - goto done; > - } else if (strcasecmp(word, "BLACKHOLE") == 0) { > - as = COMMUNITY_WELLKNOWN; > - type = COMMUNITY_BLACKHOLE; > - goto done; > - } > +static void > +parselargecommunity(struct filter_community *c, char *s) > +{ > + char *p, *q; > > - if ((p = strchr(word, ':')) == NULL) { > - fprintf(stderr, "Bad community syntax\n"); > - return (0); > - } > + if ((p = strchr(s, ':')) == NULL) > + errx(1, "Bad community syntax"); > *p++ = 0; > > - as = getcommunity(word, 0, &asflag); > - type = getcommunity(p, 0, &tflag); > + if ((q = strchr(p, ':')) == NULL) > + errx(1, "Bad community syntax"); > + *q++ = 0; > + > + getcommunity(s, 1, &c->c.l.data1, &c->dflag1); > + getcommunity(p, 1, &c->c.l.data2, &c->dflag2); > + getcommunity(q, 1, &c->c.l.data3, &c->dflag3); > > -done: > - if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) > - err(1, NULL); > - fs->type = ACTION_SET_COMMUNITY; > - fs->action.community.type = COMMUNITY_TYPE_BASIC; > - fs->action.community.c.b.data1 = as; > - fs->action.community.c.b.data2 = type; > - fs->action.community.dflag1 = asflag; > - fs->action.community.dflag2 = tflag; > + c->type = COMMUNITY_TYPE_LARGE; > +} > > - r->community = fs->action.community; > +void > +parsecommunity(struct filter_community *c, int type, char *s) > +{ > + char *p; > + u_int32_t as, data; > + u_int8_t asflag, dataflag; > + > + if (type == COMMUNITY_TYPE_LARGE) { > + parselargecommunity(c, s); > + return; > + } > > - TAILQ_INSERT_TAIL(&r->set, fs, entry); > - return (1); > + /* Well-known communities */ > + if (strcasecmp(s, "GRACEFUL_SHUTDOWN") == 0) { > + setcommunity(c, COMMUNITY_WELLKNOWN, > + COMMUNITY_GRACEFUL_SHUTDOWN, 0, 0); > + return; > + } else if (strcasecmp(s, "NO_EXPORT") == 0) { > + setcommunity(c, COMMUNITY_WELLKNOWN, > + COMMUNITY_NO_EXPORT, 0, 0); > + return; > + } else if (strcasecmp(s, "NO_ADVERTISE") == 0) { > + setcommunity(c, COMMUNITY_WELLKNOWN, > + COMMUNITY_NO_ADVERTISE, 0, 0); > + return; > + } else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) { > + setcommunity(c, COMMUNITY_WELLKNOWN, > + COMMUNITY_NO_EXPSUBCONFED, 0, 0); > + return; > + } else if (strcasecmp(s, "NO_PEER") == 0) { > + setcommunity(c, COMMUNITY_WELLKNOWN, > + COMMUNITY_NO_PEER, 0, 0); > + return; > + } else if (strcasecmp(s, "BLACKHOLE") == 0) { > + setcommunity(c, COMMUNITY_WELLKNOWN, > + COMMUNITY_BLACKHOLE, 0, 0); > + return; > + } > + > + if ((p = strchr(s, ':')) == NULL) > + errx(1, "Bad community syntax"); > + *p++ = 0; > + > + getcommunity(s, 0, &as, &asflag); > + getcommunity(p, 0, &data, &dataflag); > + setcommunity(c, as, data, asflag, dataflag); > } > > -int > -parsesubtype(const char *name, u_int8_t *type, u_int8_t *subtype) > +static int > +parsesubtype(const char *name, int *type, int *subtype) > { > const struct ext_comm_pairs *cp; > int found = 0; > > +printf("%s: looking for %s\n", __func__, name); > for (cp = iana_ext_comms; cp->subname != NULL; cp++) { > if (strcmp(name, cp->subname) == 0) { > if (found == 0) { > @@ -1138,79 +1222,89 @@ parsesubtype(const char *name, u_int8_t > return (found); > } > > -int > -parseextvalue(const char *s, u_int32_t *v) > +static int > +parseextvalue(int type, char *s, u_int32_t *v) > { > - const char *errstr; > + 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); > - if (errstr) { > - fprintf(stderr, "Bad ext-community: %s is %s\n", s, > - errstr); > - return (-1); > - } > - *v = uval; > - if (uval <= USHRT_MAX) > - return (EXT_COMMUNITY_TRANS_TWO_AS); > + strtonum(s, 0, USHRT_MAX, &errstr); > + if (errstr == NULL) > + type = EXT_COMMUNITY_TRANS_TWO_AS; > else > - return (EXT_COMMUNITY_TRANS_FOUR_AS); > + 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) > + errx(1, "Bad ext-community %s is %s", s, errstr); > + *v = uval; > + break; > + case EXT_COMMUNITY_TRANS_FOUR_AS: > + if ((p = strchr(s, '.')) == NULL) { > + uval = strtonum(s, 0, UINT_MAX, &errstr); > + if (errstr) > + errx(1, "Bad ext-community %s is %s", s, > + errstr); > + *v = uval; > + break; > + } > *p++ = '\0'; > uvalh = strtonum(s, 0, USHRT_MAX, &errstr); > - if (errstr) { > - fprintf(stderr, "Bad ext-community: %s is %s\n", s, > - errstr); > - return (-1); > - } > + if (errstr) > + errx(1, "Bad ext-community %s is %s", s, errstr); > uval = strtonum(p, 0, USHRT_MAX, &errstr); > - if (errstr) { > - fprintf(stderr, "Bad ext-community: %s is %s\n", p, > - errstr); > - return (-1); > - } > + if (errstr) > + errx(1, "Bad ext-community %s is %s", p, errstr); > *v = uval | (uvalh << 16); > - return (EXT_COMMUNITY_TRANS_FOUR_AS); > - } else { > - /* more than one dot -> IP address */ > - if (inet_aton(s, &ip) == 0) { > - fprintf(stderr, "Bad ext-community: %s not parseable\n", > - s); > - return (-1); > - } > + break; > + case EXT_COMMUNITY_TRANS_IPV4: > + if (inet_aton(s, &ip) == 0) > + errx(1, "Bad ext-community %s not parseable", s); > *v = ntohl(ip.s_addr); > - return (EXT_COMMUNITY_TRANS_IPV4); > + break; > + default: > + errx(1, "%s: unexpected type %d", __func__, type); > } > - return (-1); > + return (type); > } > > -u_int > -parseextcommunity(const char *word, struct parse_result *r) > +int > +parseextcommunity(struct filter_community *c, const char *t, char *s) > { > - struct filter_set *fs; > - const struct ext_comm_pairs *cp; > - const char *errstr; > - u_int64_t ullval; > - u_int32_t uval; > - char *p, *ep; > - int type; > + const struct ext_comm_pairs *cp; > + const char *errstr; > + u_int64_t ullval; > + u_int32_t uval; > + char *p, *ep; > + int type, subtype; > > - type = r->community.c.e.type; > + if (parsesubtype(t, &type, &subtype) == 0) > + errx(1, "Bad ext-community unknown type"); > > switch (type) { > - case 0xff: > - if ((p = strchr(word, ':')) == NULL) { > - fprintf(stderr, "Bad ext-community: %s\n", word); > - return (0); > - } > + case EXT_COMMUNITY_TRANS_TWO_AS: > + case EXT_COMMUNITY_TRANS_FOUR_AS: > + case EXT_COMMUNITY_TRANS_IPV4: > + case -1: > + if ((p = strchr(s, ':')) == NULL) > + errx(1, "Bad ext-community %s", s); > *p++ = '\0'; > - if ((type = parseextvalue(word, &uval)) == -1) > - return (0); > + type = parseextvalue(type, s, &uval); > switch (type) { > case EXT_COMMUNITY_TRANS_TWO_AS: > ullval = strtonum(p, 0, UINT_MAX, &errstr); > @@ -1220,118 +1314,46 @@ parseextcommunity(const char *word, stru > ullval = strtonum(p, 0, USHRT_MAX, &errstr); > break; > default: > - fprintf(stderr, "parseextcommunity: unexpected " > - "result\n"); > - return (0); > - } > - if (errstr) { > - fprintf(stderr, "Bad ext-community: %s is %s\n", p, > - errstr); > - return (0); > - } > - switch (type) { > - case EXT_COMMUNITY_TRANS_TWO_AS: > - r->community.c.e.data1 = uval; > - r->community.c.e.data2 = ullval; > - break; > - case EXT_COMMUNITY_TRANS_IPV4: > - case EXT_COMMUNITY_TRANS_FOUR_AS: > - r->community.c.e.data1 = uval; > - r->community.c.e.data2 = ullval; > - break; > + errx(1, "parseextcommunity: unexpected result"); > } > + if (errstr) > + errx(1, "Bad ext-community %s is %s", p, errstr); > + c->c.e.data1 = uval; > + c->c.e.data2 = ullval; > break; > case EXT_COMMUNITY_TRANS_OPAQUE: > case EXT_COMMUNITY_TRANS_EVPN: > errno = 0; > - ullval = strtoull(word, &ep, 0); > - if (word[0] == '\0' || *ep != '\0') { > - fprintf(stderr, "Bad ext-community: bad value\n"); > - return (0); > - } > - if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) { > - fprintf(stderr, "Bad ext-community: too big\n"); > - return (0); > - } > - r->community.c.e.data2 = ullval; > + ullval = strtoull(s, &ep, 0); > + if (s[0] == '\0' || *ep != '\0') > + errx(1, "Bad ext-community bad value"); > + if (errno == ERANGE && ullval > EXT_COMMUNITY_OPAQUE_MAX) > + errx(1, "Bad ext-community value too big"); > + c->c.e.data2 = ullval; > break; > case EXT_COMMUNITY_NON_TRANS_OPAQUE: > - if (strcmp(word, "valid") == 0) > - r->community.c.e.data2 = EXT_COMMUNITY_OVS_VALID; > - else if (strcmp(word, "invalid") == 0) > - r->community.c.e.data2 = EXT_COMMUNITY_OVS_INVALID; > - else if (strcmp(word, "not-found") == 0) > - r->community.c.e.data2 = EXT_COMMUNITY_OVS_NOTFOUND; > - else { > - fprintf(stderr, "Bad ext-community value: %s\n", word); > - return (0); > - } > + if (strcmp(s, "valid") == 0) > + c->c.e.data2 = EXT_COMMUNITY_OVS_VALID; > + else if (strcmp(s, "invalid") == 0) > + c->c.e.data2 = EXT_COMMUNITY_OVS_INVALID; > + else if (strcmp(s, "not-found") == 0) > + c->c.e.data2 = EXT_COMMUNITY_OVS_NOTFOUND; > + else > + errx(1, "Bad ext-community %s", s); > break; > } > - r->community.c.e.type = type; > + 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 == 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_COMMUNITY; > - memcpy(&fs->action.community, &r->community, > - sizeof(struct filter_community)); > - > - TAILQ_INSERT_TAIL(&r->set, fs, entry); > - return (1); > + if (cp->type == type && cp->subtype == subtype) { > + c->type = COMMUNITY_TYPE_EXT; > + return (0); > } > } > > - fprintf(stderr, "Bad ext-community: bad format for type\n"); > - return (0); > -} > - > -int > -parse_largecommunity(const char *word, struct parse_result *r) > -{ > - struct filter_set *fs; > - char *p, *po = strdup(word); > - char *array[3] = { NULL, NULL, NULL }; > - char *val; > - u_int32_t as, ld1, ld2; > - u_int8_t asflag, ld1flag, ld2flag; > - int i = 0; > - > - p = po; > - while ((p != NULL) && (i < 3)) { > - val = strsep(&p, ":"); > - array[i++] = val; > - } > - > - if ((p != NULL) || !(array[0] && array[1] && array[2])) > - errx(1, "Invalid Large-Community syntax"); > - > - as = getcommunity(array[0], 1, &asflag); > - ld1 = getcommunity(array[1], 1, &ld1flag); > - ld2 = getcommunity(array[2], 1, &ld2flag); > - > - free(po); > - > - if ((fs = calloc(1, sizeof(struct filter_set))) == NULL) > - err(1, NULL); > - fs->type = ACTION_SET_COMMUNITY; > - fs->action.community.type = COMMUNITY_TYPE_LARGE; > - 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; > - > - r->community = fs->action.community; > - > - TAILQ_INSERT_TAIL(&r->set, fs, entry); > - return (1); > + errx(1, "Bad ext-community bad format for type"); > } > > int > Index: usr.sbin/bgpctl/parser.h > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpctl/parser.h,v > retrieving revision 1.34 > diff -u -p -r1.34 parser.h > --- usr.sbin/bgpctl/parser.h 20 Jan 2019 23:30:15 -0000 1.34 > +++ usr.sbin/bgpctl/parser.h 7 Feb 2019 10:11:19 -0000 > @@ -67,6 +67,8 @@ struct parse_result { > char rib[PEER_DESCR_LEN]; > char shutcomm[SHUT_COMM_LEN]; > char *irr_outdir; > + const char *ext_comm_subtype; > + u_int64_t rd; > int flags; > int is_group; > u_int8_t validation_state; > Index: usr.sbin/bgpd/bgpd.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/bgpd.c,v > retrieving revision 1.207 > diff -u -p -r1.207 bgpd.c > --- usr.sbin/bgpd/bgpd.c 20 Jan 2019 06:13:40 -0000 1.207 > +++ usr.sbin/bgpd/bgpd.c 7 Feb 2019 10:11:19 -0000 > @@ -173,7 +173,7 @@ main(int argc, char *argv[]) > > if (cmd_opts & BGPD_OPT_VERBOSE) > print_config(conf, &ribnames, &conf->networks, peer_l, > - conf->filters, conf->mrt, &conf->rdomains); > + conf->filters, conf->mrt, &conf->l3vpns); > else > fprintf(stderr, "configuration OK\n"); > exit(0); > @@ -438,7 +438,7 @@ reconfigure(char *conffile, struct bgpd_ > struct filter_rule *r; > struct listen_addr *la; > struct rde_rib *rr; > - struct rdomain *rd; > + struct l3vpn *vpn; > struct as_set *aset; > struct prefixset *ps; > struct prefixset_item *psi, *npsi; > @@ -512,8 +512,7 @@ reconfigure(char *conffile, struct bgpd_ > } > > /* networks go via kroute to the RDE */ > - if (kr_net_reload(conf->default_tableid, &conf->networks)) > - return (-1); > + kr_net_reload(conf->default_tableid, 0, &conf->networks); > > /* prefixsets for filters in the RDE */ > while ((ps = SIMPLEQ_FIRST(&conf->prefixsets)) != NULL) { > @@ -627,43 +626,42 @@ reconfigure(char *conffile, struct bgpd_ > free(r); > } > > - while ((rd = SIMPLEQ_FIRST(&conf->rdomains)) != NULL) { > - SIMPLEQ_REMOVE_HEAD(&conf->rdomains, entry); > - if (ktable_update(rd->rtableid, rd->descr, rd->flags, > + while ((vpn = SIMPLEQ_FIRST(&conf->l3vpns)) != NULL) { > + SIMPLEQ_REMOVE_HEAD(&conf->l3vpns, entry); > + if (ktable_update(vpn->rtableid, vpn->descr, vpn->flags, > conf->fib_priority) == -1) { > log_warnx("failed to load rdomain %d", > - rd->rtableid); > + vpn->rtableid); > return (-1); > } > /* networks go via kroute to the RDE */ > - if (kr_net_reload(rd->rtableid, &rd->net_l)) > - return (-1); > + kr_net_reload(vpn->rtableid, vpn->rd, &vpn->net_l); > > - if (imsg_compose(ibuf_rde, IMSG_RECONF_RDOMAIN, 0, 0, -1, > - rd, sizeof(*rd)) == -1) > + if (imsg_compose(ibuf_rde, IMSG_RECONF_VPN, 0, 0, -1, > + vpn, sizeof(*vpn)) == -1) > return (-1); > > /* export targets */ > - if (imsg_compose(ibuf_rde, IMSG_RECONF_RDOMAIN_EXPORT, 0, 0, > + if (imsg_compose(ibuf_rde, IMSG_RECONF_VPN_EXPORT, 0, 0, > -1, NULL, 0) == -1) > return (-1); > - if (send_filterset(ibuf_rde, &rd->export) == -1) > + if (send_filterset(ibuf_rde, &vpn->export) == -1) > return (-1); > - filterset_free(&rd->export); > + filterset_free(&vpn->export); > > /* import targets */ > - if (imsg_compose(ibuf_rde, IMSG_RECONF_RDOMAIN_IMPORT, 0, 0, > + if (imsg_compose(ibuf_rde, IMSG_RECONF_VPN_IMPORT, 0, 0, > -1, NULL, 0) == -1) > return (-1); > - if (send_filterset(ibuf_rde, &rd->import) == -1) > + if (send_filterset(ibuf_rde, &vpn->import) == -1) > return (-1); > - filterset_free(&rd->import); > + filterset_free(&vpn->import); > > - if (imsg_compose(ibuf_rde, IMSG_RECONF_RDOMAIN_DONE, 0, 0, > + if (imsg_compose(ibuf_rde, IMSG_RECONF_VPN_DONE, 0, 0, > -1, NULL, 0) == -1) > return (-1); > > - free(rd); > + free(vpn); > } > > /* send a drain message to know when all messages where processed */ > Index: usr.sbin/bgpd/bgpd.conf.5 > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v > retrieving revision 1.183 > diff -u -p -r1.183 bgpd.conf.5 > --- usr.sbin/bgpd/bgpd.conf.5 4 Feb 2019 20:32:23 -0000 1.183 > +++ usr.sbin/bgpd/bgpd.conf.5 7 Feb 2019 10:11:19 -0000 > @@ -558,37 +558,56 @@ See also the > section. > .Sh MPLS VPN CONFIGURATION > .Xr bgpd 8 > -supports the setup and distribution of Virtual Private Networks. > -It is possible to import and export prefixes between routing domains. > -Each routing domain is specified by an > -.Ic rdomain > -section, which allows properties to be set specifically for that rdomain: > +supports the setup and distribution of MPLS Virtual Private Networks. > +A router can be configured to participate in a VPN by specifying a > +.Ic vpn > +section with a description for the VPN and an > +.Xr mpe 4 > +interface. > +.Pp > +The vpn configuraion section allows properties to be set specifically > +for that VPN: > .Bd -literal -offset indent > -rdomain 1 { > - descr "a rdomain" > - rd 65002:1 > +vpn "description" on mpe1 { > + rd 65002:1 > import-target rt 65002:42 > export-target rt 65002:42 > network 192.168.1/24 > - depend on mpe0 > } > .Ed > .Pp > -There are several routing domain properties: > -.Pp > -.Bl -tag -width Ds -compact > -.It Ic depend on Ar interface > -Routes added to the rdomain will use this interface as the outgoing > interface. > -Normally this will be an MPLS Provider Edge, > -.Xr mpe 4 , > -interface that is part of the rdomain. > -Local networks will be announced with the MPLS label specified on the > interface. > -.Pp > -.It Ic descr Ar description > -Add a description. > The description is used when logging but has no further meaning to > .Xr bgpd 8 . > .Pp > +The > +.Xr mpe 4 > +interface will be used as the outgoing interface for routes to > +the VPN, and local networks will be annouced with the MPLS label > +specified on the interface. > +The interface can provide VPN connectivity for another rdomain by > +being configured in that rdomain. > +The required rdomain must be configured on the interface before > +.Xr bgpd 8 > +uses it. > +Multiple VPNs may be connected to a single rdomain, including the rdomain > that > +.Xr bgpd 8 > +is running in. > +.Pp > +An example > +.Xr hostname.if 8 > +configuration for an > +.Xr mpe 4 > +interface providing connectivity to rdomain 1: > +.Bd -literal -offset indent > +rdomain 1 > +mplslabel 2000 > +inet 192.198.0.1 255.255.255.255 > +up > +.Ed > +.Pp > +There are several VPN properties: > +.Pp > +.Bl -tag -width Ds -compact > .It Ic export-target Ar subtype Ar as-number : Ns Ar local > .It Ic export-target Ar subtype Ar IP : Ns Ar local > Specify an extended community which will be attached to announced networks. > Index: usr.sbin/bgpd/bgpd.h > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v > retrieving revision 1.364 > diff -u -p -r1.364 bgpd.h > --- usr.sbin/bgpd/bgpd.h 4 Feb 2019 18:53:10 -0000 1.364 > +++ usr.sbin/bgpd/bgpd.h 7 Feb 2019 10:11:19 -0000 > @@ -81,7 +81,6 @@ > #define F_BLACKHOLE 0x0100 > #define F_LONGER 0x0200 > #define F_MPLS 0x0400 > -#define F_REDISTRIBUTED 0x0800 > #define F_CTL_DETAIL 0x1000 /* only used by bgpctl */ > #define F_CTL_ADJ_IN 0x2000 > #define F_CTL_ADJ_OUT 0x4000 > @@ -231,8 +230,8 @@ struct listen_addr { > TAILQ_HEAD(listen_addrs, listen_addr); > TAILQ_HEAD(filter_set_head, filter_set); > > -struct rdomain; > -SIMPLEQ_HEAD(rdomain_head, rdomain); > +struct l3vpn; > +SIMPLEQ_HEAD(l3vpn_head, l3vpn); > > struct network; > TAILQ_HEAD(network_head, network); > @@ -267,7 +266,7 @@ struct filter_rule; > TAILQ_HEAD(filter_head, filter_rule); > > struct bgpd_config { > - struct rdomain_head rdomains; > + struct l3vpn_head l3vpns; > struct network_head networks; > struct filter_head *filters; > struct listen_addrs *listen_addrs; > @@ -411,7 +410,7 @@ struct network_config { > struct filter_set_head attrset; > struct rde_aspath *asp; > char psname[SET_NAME_LEN]; > - u_int rtableid; > + u_int64_t rd; > u_int16_t rtlabel; > enum network_type type; > u_int8_t prefixlen; > @@ -467,10 +466,10 @@ enum imsg_type { > IMSG_RECONF_FILTER, > IMSG_RECONF_LISTENER, > IMSG_RECONF_CTRL, > - IMSG_RECONF_RDOMAIN, > - IMSG_RECONF_RDOMAIN_EXPORT, > - IMSG_RECONF_RDOMAIN_IMPORT, > - IMSG_RECONF_RDOMAIN_DONE, > + IMSG_RECONF_VPN, > + IMSG_RECONF_VPN_EXPORT, > + IMSG_RECONF_VPN_IMPORT, > + IMSG_RECONF_VPN_DONE, > IMSG_RECONF_PREFIX_SET, > IMSG_RECONF_PREFIX_SET_ITEM, > IMSG_RECONF_AS_SET, > @@ -567,15 +566,18 @@ enum suberr_cease { > struct kroute_node; > struct kroute6_node; > struct knexthop_node; > +struct kredist_node; > RB_HEAD(kroute_tree, kroute_node); > RB_HEAD(kroute6_tree, kroute6_node); > RB_HEAD(knexthop_tree, knexthop_node); > +RB_HEAD(kredist_tree, kredist_node); > > struct ktable { > char descr[PEER_DESCR_LEN]; > struct kroute_tree krt; > struct kroute6_tree krt6; > struct knexthop_tree knt; > + struct kredist_tree kredist; > struct network_head krn; > u_int rtableid; > u_int nhtableid; /* rdomain id for nexthop lookup */ > @@ -1024,8 +1026,8 @@ struct as_set { > int dirty; > }; > > -struct rdomain { > - SIMPLEQ_ENTRY(rdomain) entry; > +struct l3vpn { > + SIMPLEQ_ENTRY(l3vpn) entry; > char descr[PEER_DESCR_LEN]; > char ifmpe[IFNAMSIZ]; > struct filter_set_head import; > @@ -1176,7 +1178,7 @@ void kr_nexthop_delete(u_int32_t, stru > struct bgpd_config *); > void kr_show_route(struct imsg *); > void kr_ifinfo(char *); > -int kr_net_reload(u_int, struct network_head *); > +void kr_net_reload(u_int, u_int64_t, struct network_head *); > int kr_reload(void); > struct in6_addr *prefixlen2mask6(u_int8_t prefixlen); > > Index: usr.sbin/bgpd/config.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/config.c,v > retrieving revision 1.79 > diff -u -p -r1.79 config.c > --- usr.sbin/bgpd/config.c 27 Dec 2018 20:23:24 -0000 1.79 > +++ usr.sbin/bgpd/config.c 7 Feb 2019 10:11:19 -0000 > @@ -39,7 +39,7 @@ > u_int32_t get_bgpid(void); > int host_ip(const char *, struct bgpd_addr *, u_int8_t *); > void free_networks(struct network_head *); > -void free_rdomains(struct rdomain_head *); > +void free_l3vpns(struct l3vpn_head *); > > struct bgpd_config * > new_config(void) > @@ -75,7 +75,7 @@ new_config(void) > > /* init the various list for later */ > TAILQ_INIT(&conf->networks); > - SIMPLEQ_INIT(&conf->rdomains); > + SIMPLEQ_INIT(&conf->l3vpns); > SIMPLEQ_INIT(&conf->prefixsets); > SIMPLEQ_INIT(&conf->originsets); > RB_INIT(&conf->roa); > @@ -101,16 +101,16 @@ free_networks(struct network_head *netwo > } > > void > -free_rdomains(struct rdomain_head *rdomains) > +free_l3vpns(struct l3vpn_head *l3vpns) > { > - struct rdomain *rd; > + struct l3vpn *vpn; > > - while ((rd = SIMPLEQ_FIRST(rdomains)) != NULL) { > - SIMPLEQ_REMOVE_HEAD(rdomains, entry); > - filterset_free(&rd->export); > - filterset_free(&rd->import); > - free_networks(&rd->net_l); > - free(rd); > + while ((vpn = SIMPLEQ_FIRST(l3vpns)) != NULL) { > + SIMPLEQ_REMOVE_HEAD(l3vpns, entry); > + filterset_free(&vpn->export); > + filterset_free(&vpn->import); > + free_networks(&vpn->net_l); > + free(vpn); > } > } > > @@ -145,7 +145,7 @@ free_config(struct bgpd_config *conf) > struct listen_addr *la; > struct mrt *m; > > - free_rdomains(&conf->rdomains); > + free_l3vpns(&conf->l3vpns); > free_networks(&conf->networks); > filterlist_free(conf->filters); > free_prefixsets(&conf->prefixsets); > @@ -250,9 +250,9 @@ merge_config(struct bgpd_config *xconf, > TAILQ_INSERT_TAIL(&xconf->networks, n, entry); > } > > - /* switch the rdomain configs, first remove the old ones */ > - free_rdomains(&xconf->rdomains); > - SIMPLEQ_CONCAT(&xconf->rdomains, &conf->rdomains); > + /* switch the l3vpn configs, first remove the old ones */ > + free_l3vpns(&xconf->l3vpns); > + SIMPLEQ_CONCAT(&xconf->l3vpns, &conf->l3vpns); > > /* > * merge new listeners: > @@ -469,27 +469,42 @@ prepare_listeners(struct bgpd_config *co > } > > int > -get_mpe_label(struct rdomain *r) > +get_mpe_config(const char *name, u_int *rdomain, u_int *label) > { > struct ifreq ifr; > struct shim_hdr shim; > int s; > > + *label = 0; > + *rdomain = 0; > + > s = socket(AF_INET, SOCK_DGRAM, 0); > if (s == -1) > return (-1); > > bzero(&shim, sizeof(shim)); > bzero(&ifr, sizeof(ifr)); > - strlcpy(ifr.ifr_name, r->ifmpe, sizeof(ifr.ifr_name)); > + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); > ifr.ifr_data = (caddr_t)&shim; > > if (ioctl(s, SIOCGETLABEL, (caddr_t)&ifr) == -1) { > close(s); > return (-1); > } > + > + ifr.ifr_data = NULL; > + if (ioctl(s, SIOCGIFRDOMAIN, (caddr_t)&ifr) == -1) { > + close(s); > + return (-1); > + } > + > close(s); > - r->label = shim.shim_label; > + > + *rdomain = ifr.ifr_rdomainid; > + *label = shim.shim_label; > + > + log_debug("%s: rdomain %u label %u", __func__, *rdomain, *label); > + > return (0); > } > > Index: usr.sbin/bgpd/kroute.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v > retrieving revision 1.229 > diff -u -p -r1.229 kroute.c > --- usr.sbin/bgpd/kroute.c 18 Jan 2019 23:30:45 -0000 1.229 > +++ usr.sbin/bgpd/kroute.c 7 Feb 2019 10:11:19 -0000 > @@ -65,6 +65,14 @@ struct knexthop_node { > void *kroute; > }; > > +struct kredist_node { > + RB_ENTRY(kredist_node) entry; > + struct bgpd_addr prefix; > + u_int64_t rd; > + u_int8_t prefixlen; > + u_int8_t dynamic; > +}; > + > struct kif_kr { > LIST_ENTRY(kif_kr) entry; > struct kroute_node *kr; > @@ -99,16 +107,16 @@ int kr6_delete(struct ktable *, struct k > int krVPN4_delete(struct ktable *, struct kroute_full *, u_int8_t); > int krVPN6_delete(struct ktable *, struct kroute_full *, u_int8_t); > void kr_net_delete(struct network *); > -struct network *kr_net_match(struct ktable *, struct kroute *); > -struct network *kr_net_match6(struct ktable *, struct kroute6 *); > +int kr_net_match(struct ktable *, struct network_config *, u_int16_t); > struct network *kr_net_find(struct ktable *, struct network *); > -int kr_redistribute(int, struct ktable *, struct kroute *); > -int kr_redistribute6(int, struct ktable *, struct kroute6 *); > +void kr_redistribute(int, struct ktable *, struct kroute *); > +void kr_redistribute6(int, struct ktable *, struct kroute6 *); > struct kroute_full *kr_tofull(struct kroute *); > struct kroute_full *kr6_tofull(struct kroute6 *); > int kroute_compare(struct kroute_node *, struct kroute_node *); > int kroute6_compare(struct kroute6_node *, struct kroute6_node *); > int knexthop_compare(struct knexthop_node *, struct knexthop_node *); > +int kredist_compare(struct kredist_node *, struct kredist_node *); > int kif_compare(struct kif_node *, struct kif_node *); > void kr_fib_update_prio(u_int, u_int8_t); > > @@ -185,6 +193,9 @@ RB_GENERATE(kroute6_tree, kroute6_node, > RB_PROTOTYPE(knexthop_tree, knexthop_node, entry, knexthop_compare) > RB_GENERATE(knexthop_tree, knexthop_node, entry, knexthop_compare) > > +RB_PROTOTYPE(kredist_tree, kredist_node, entry, kredist_compare) > +RB_GENERATE(kredist_tree, kredist_node, entry, kredist_compare) > + > RB_HEAD(kif_tree, kif_node) kit; > RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare) > RB_GENERATE(kif_tree, kif_node, entry, kif_compare) > @@ -399,35 +410,6 @@ ktable_update(u_int rtableid, char *name > return (0); > } > > -void > -ktable_preload(void) > -{ > - struct ktable *kt; > - u_int i; > - > - for (i = 0; i < krt_size; i++) { > - if ((kt = ktable_get(i)) == NULL) > - continue; > - kt->state = RECONF_DELETE; > - } > -} > - > -void > -ktable_postload(u_int8_t fib_prio) > -{ > - struct ktable *kt; > - u_int i; > - > - for (i = krt_size; i > 0; i--) { > - if ((kt = ktable_get(i - 1)) == NULL) > - continue; > - if (kt->state == RECONF_DELETE) > - ktable_free(i - 1, fib_prio); > - else if (kt->state == RECONF_REINIT) > - kt->fib_sync = kt->fib_conf; > - } > -} > - > int > ktable_exists(u_int rtableid, u_int *rdomid) > { > @@ -1199,93 +1181,105 @@ kr_net_delete(struct network *n) > free(n); > } > > -struct network * > -kr_net_match(struct ktable *kt, struct kroute *kr) > +static int > +kr_net_redist_add(struct ktable *kt, struct network_config *net, > + struct filter_set_head *attr, int dynamic) > +{ > + struct kredist_node *r, *xr; > + > + if ((r = calloc(1, sizeof(*r))) == NULL) > + fatal("%s", __func__); > + r->prefix = net->prefix; > + r->prefixlen = net->prefixlen; > + r->rd = net->rd; > + r->dynamic = dynamic; > + > + xr = RB_INSERT(kredist_tree, &kt->kredist, r); > + if (xr != NULL && dynamic != xr->dynamic) { > + if (dynamic) { > + /* > + * ignore update, a non-dynamic announcement > + * is already present. > + */ > + free(r); > + return 0; > + } > + /* non-dynamic announcments are preferred */ > + xr->dynamic = dynamic; > + } > + > + if (send_network(IMSG_NETWORK_ADD, net, attr) == -1) > + log_warnx("%s: faild to send network update", __func__); > + return 1; > +} > + > +static void > +kr_net_redist_del(struct ktable *kt, struct network_config *net, int dynamic) > { > - struct network *xn; > + struct kredist_node *r, node; > > - TAILQ_FOREACH(xn, &kt->krn, entry) { > - if (xn->net.prefix.aid != AID_INET) > - continue; > - switch (xn->net.type) { > - case NETWORK_DEFAULT: > - if (xn->net.prefixlen == kr->prefixlen && > - xn->net.prefix.v4.s_addr == kr->prefix.s_addr) > - /* static match already redistributed */ > - return (NULL); > - break; > - case NETWORK_STATIC: > - if (kr->flags & F_STATIC) > - return (xn); > - break; > - case NETWORK_CONNECTED: > - if (kr->flags & F_CONNECTED) > - return (xn); > - break; > - case NETWORK_RTLABEL: > - if (kr->labelid == xn->net.rtlabel) > - return (xn); > - break; > - case NETWORK_MRTCLONE: > - /* can not happen */ > - break; > - case NETWORK_PRIORITY: > - if (kr->priority == xn->net.priority) > - return (xn); > - break; > - case NETWORK_PREFIXSET: > - /* must not happen */ > - log_warnx("%s: found a NETWORK_PREFIXSET, " > - "please send a bug report", __func__); > - break; > - } > + bzero(&node, sizeof(node)); > + node.prefix = net->prefix; > + node.prefixlen = net->prefixlen; > + node.rd = net->rd; > + > + r = RB_FIND(kredist_tree, &kt->kredist, &node); > + if (r == NULL || dynamic != r->dynamic) > + return; > + > + if (RB_REMOVE(kredist_tree, &kt->kredist, r) == NULL) { > + log_warnx("%s: failed to remove network %s/%u", __func__, > + log_addr(&node.prefix), node.prefixlen); > + return; > } > - return (NULL); > + free(r); > + > + if (send_network(IMSG_NETWORK_REMOVE, net, NULL) == -1) > + log_warnx("%s: faild to send network update", __func__); > } > > -struct network * > -kr_net_match6(struct ktable *kt, struct kroute6 *kr6) > +int > +kr_net_match(struct ktable *kt, struct network_config *net, u_int16_t flags) > { > struct network *xn; > + int matched = 0; > > TAILQ_FOREACH(xn, &kt->krn, entry) { > - if (xn->net.prefix.aid != AID_INET6) > + if (xn->net.prefix.aid != net->prefix.aid) > continue; > switch (xn->net.type) { > case NETWORK_DEFAULT: > - if (xn->net.prefixlen == kr6->prefixlen && > - memcmp(&xn->net.prefix.v6, &kr6->prefix, > - sizeof(struct in6_addr)) == 0) > - /* static match already redistributed */ > - return (NULL); > - break; > + /* static match already redistributed */ > + continue; > case NETWORK_STATIC: > - if (kr6->flags & F_STATIC) > - return (xn); > - break; > + if (flags & F_STATIC) > + break; > + continue; > case NETWORK_CONNECTED: > - if (kr6->flags & F_CONNECTED) > - return (xn); > - break; > + if (flags & F_CONNECTED) > + break; > + continue; > case NETWORK_RTLABEL: > - if (kr6->labelid == xn->net.rtlabel) > - return (xn); > - break; > - case NETWORK_MRTCLONE: > - /* can not happen */ > - break; > + if (net->rtlabel == xn->net.rtlabel) > + break; > + continue; > case NETWORK_PRIORITY: > - if (kr6->priority == xn->net.priority) > - return (xn); > - break; > + if (net->priority == xn->net.priority) > + break; > + continue; > + case NETWORK_MRTCLONE: > case NETWORK_PREFIXSET: > /* must not happen */ > log_warnx("%s: found a NETWORK_PREFIXSET, " > "please send a bug report", __func__); > - break; > + continue; > } > + > + net->rd = xn->net.rd; > + if (kr_net_redist_add(kt, net, &xn->net.attrset, 1)) > + matched = 1; > } > - return (NULL); > + return matched; > } > > struct network * > @@ -1296,7 +1290,7 @@ kr_net_find(struct ktable *kt, struct ne > TAILQ_FOREACH(xn, &kt->krn, entry) { > if (n->net.type != xn->net.type || > n->net.prefixlen != xn->net.prefixlen || > - n->net.rtableid != xn->net.rtableid) > + n->net.rd != xn->net.rd) > continue; > if (memcmp(&n->net.prefix, &xn->net.prefix, > sizeof(n->net.prefix)) == 0) > @@ -1305,26 +1299,21 @@ kr_net_find(struct ktable *kt, struct ne > return (NULL); > } > > -int > -kr_net_reload(u_int rtableid, struct network_head *nh) > +void > +kr_net_reload(u_int rtableid, u_int64_t rd, struct network_head *nh) > { > struct network *n, *xn; > struct ktable *kt; > > - if ((kt = ktable_get(rtableid)) == NULL) { > - log_warnx("%s: non-existent rtableid %d", __func__, rtableid); > - return (-1); > - } > - > - TAILQ_FOREACH(n, &kt->krn, entry) > - n->net.old = 1; > + if ((kt = ktable_get(rtableid)) == NULL) > + fatalx("%s: non-existent rtableid %d", __func__, rtableid); > > while ((n = TAILQ_FIRST(nh)) != NULL) { > log_debug("%s: processing %s/%u", __func__, > log_addr(&n->net.prefix), n->net.prefixlen); > TAILQ_REMOVE(nh, n, entry); > n->net.old = 0; > - n->net.rtableid = rtableid; > + n->net.rd = rd; > xn = kr_net_find(kt, n); > if (xn) { > xn->net.old = 0; > @@ -1334,44 +1323,33 @@ kr_net_reload(u_int rtableid, struct net > } else > TAILQ_INSERT_TAIL(&kt->krn, n, entry); > } > - > - for (n = TAILQ_FIRST(&kt->krn); n != NULL; n = xn) { > - xn = TAILQ_NEXT(n, entry); > - if (n->net.old) { > - if (n->net.type == NETWORK_DEFAULT) > - if (send_network(IMSG_NETWORK_REMOVE, &n->net, > - NULL)) > - return (-1); > - TAILQ_REMOVE(&kt->krn, n, entry); > - kr_net_delete(n); > - } > - } > - > - return (0); > } > > -int > +void > kr_redistribute(int type, struct ktable *kt, struct kroute *kr) > { > - struct network *match; > struct network_config net; > u_int32_t a; > > + bzero(&net, sizeof(net)); > + net.prefix.aid = AID_INET; > + net.prefix.v4.s_addr = kr->prefix.s_addr; > + net.prefixlen = kr->prefixlen; > + net.rtlabel = kr->labelid; > + net.priority = kr->priority; > + > /* shortcut for removals */ > if (type == IMSG_NETWORK_REMOVE) { > - if (!(kr->flags & F_REDISTRIBUTED)) > - return (0); /* no match, don't redistribute */ > - kr->flags &= ~F_REDISTRIBUTED; > - match = NULL; > - goto sendit; > + kr_net_redist_del(kt, &net, 1); > + return; > } > > if (!(kr->flags & F_KERNEL)) > - return (0); > + return; > > /* Dynamic routes are not redistributable. */ > if (kr->flags & F_DYNAMIC) > - return (0); > + return; > > /* > * We consider the loopback net, multicast and experimental addresses > @@ -1380,61 +1358,48 @@ kr_redistribute(int type, struct ktable > a = ntohl(kr->prefix.s_addr); > if (IN_MULTICAST(a) || IN_BADCLASS(a) || > (a >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) > - return (0); > + return; > > /* Consider networks with nexthop loopback as not redistributable. */ > if (kr->nexthop.s_addr == htonl(INADDR_LOOPBACK)) > - return (0); > + return; > > /* > * never allow 0.0.0.0/0 the default route can only be redistributed > * with announce default. > */ > if (kr->prefix.s_addr == INADDR_ANY && kr->prefixlen == 0) > - return (0); > - > - match = kr_net_match(kt, kr); > - if (match == NULL) { > - if (!(kr->flags & F_REDISTRIBUTED)) > - return (0); /* no match, don't redistribute */ > - /* route no longer matches but is redistributed, so remove */ > - kr->flags &= ~F_REDISTRIBUTED; > - type = IMSG_NETWORK_REMOVE; > - } else > - kr->flags |= F_REDISTRIBUTED; > - > -sendit: > - bzero(&net, sizeof(net)); > - net.prefix.aid = AID_INET; > - net.prefix.v4.s_addr = kr->prefix.s_addr; > - net.prefixlen = kr->prefixlen; > - net.rtlabel = kr->labelid; > - net.rtableid = kt->rtableid; > + return; > > - return (send_network(type, &net, match ? &match->net.attrset : NULL)); > + if (kr_net_match(kt, &net, kr->flags) == 0) > + /* no longer matches, if still present remove it */ > + kr_net_redist_del(kt, &net, 1); > } > > -int > +void > kr_redistribute6(int type, struct ktable *kt, struct kroute6 *kr6) > { > - struct network *match; > struct network_config net; > > + bzero(&net, sizeof(net)); > + net.prefix.aid = AID_INET6; > + memcpy(&net.prefix.v6, &kr6->prefix, sizeof(struct in6_addr)); > + net.prefixlen = kr6->prefixlen; > + net.rtlabel = kr6->labelid; > + net.priority = kr6->priority; > + > /* shortcut for removals */ > if (type == IMSG_NETWORK_REMOVE) { > - if (!(kr6->flags & F_REDISTRIBUTED)) > - return (0); /* no match, don't redistribute */ > - kr6->flags &= ~F_REDISTRIBUTED; > - match = NULL; > - goto sendit; > + kr_net_redist_del(kt, &net, 1); > + return; > } > > if (!(kr6->flags & F_KERNEL)) > - return (0); > + return; > > /* Dynamic routes are not redistributable. */ > if (kr6->flags & F_DYNAMIC) > - return (0); > + return; > > /* > * We consider unspecified, loopback, multicast, link- and site-local, > @@ -1447,13 +1412,13 @@ kr_redistribute6(int type, struct ktable > IN6_IS_ADDR_SITELOCAL(&kr6->prefix) || > IN6_IS_ADDR_V4MAPPED(&kr6->prefix) || > IN6_IS_ADDR_V4COMPAT(&kr6->prefix)) > - return (0); > + return; > > /* > * Consider networks with nexthop loopback as not redistributable. > */ > if (IN6_IS_ADDR_LOOPBACK(&kr6->nexthop)) > - return (0); > + return; > > /* > * never allow ::/0 the default route can only be redistributed > @@ -1461,26 +1426,57 @@ kr_redistribute6(int type, struct ktable > */ > if (kr6->prefixlen == 0 && > memcmp(&kr6->prefix, &in6addr_any, sizeof(struct in6_addr)) == 0) > - return (0); > + return; > > - match = kr_net_match6(kt, kr6); > - if (match == NULL) { > - if (!(kr6->flags & F_REDISTRIBUTED)) > - return (0); /* no match, don't redistribute */ > - /* route no longer matches but is redistributed, so remove */ > - kr6->flags &= ~F_REDISTRIBUTED; > - type = IMSG_NETWORK_REMOVE; > - } else > - kr6->flags |= F_REDISTRIBUTED; > -sendit: > - bzero(&net, sizeof(net)); > - net.prefix.aid = AID_INET6; > - memcpy(&net.prefix.v6, &kr6->prefix, sizeof(struct in6_addr)); > - net.prefixlen = kr6->prefixlen; > - net.rtlabel = kr6->labelid; > - net.rtableid = kt->rtableid; > + if (kr_net_match(kt, &net, kr6->flags) == 0) > + /* no longer matches, if still present remove it */ > + kr_net_redist_del(kt, &net, 1); > +} > + > +void > +ktable_preload(void) > +{ > + struct ktable *kt; > + struct network *n; > + u_int i; > + > + for (i = 0; i < krt_size; i++) { > + if ((kt = ktable_get(i)) == NULL) > + continue; > + kt->state = RECONF_DELETE; > + > + /* mark all networks as old */ > + TAILQ_FOREACH(n, &kt->krn, entry) > + n->net.old = 1; > + } > +} > + > +void > +ktable_postload(u_int8_t fib_prio) > +{ > + struct ktable *kt; > + struct network *n, *xn; > + u_int i; > + > + for (i = krt_size; i > 0; i--) { > + if ((kt = ktable_get(i - 1)) == NULL) > + continue; > + if (kt->state == RECONF_DELETE) { > + ktable_free(i - 1, fib_prio); > + continue; > + } else if (kt->state == RECONF_REINIT) > + kt->fib_sync = kt->fib_conf; > > - return (send_network(type, &net, match ? &match->net.attrset : NULL)); > + /* cleanup old networks */ > + TAILQ_FOREACH_SAFE(n, &kt->krn, entry, xn) { > + if (n->net.old) { > + TAILQ_REMOVE(&kt->krn, n, entry); > + if (n->net.type == NETWORK_DEFAULT) > + kr_net_redist_del(kt, &n->net, 0); > + kr_net_delete(n); > + } > + } > + } > } > > int > @@ -1503,9 +1499,8 @@ kr_reload(void) > > TAILQ_FOREACH(n, &kt->krn, entry) > if (n->net.type == NETWORK_DEFAULT) { > - if (send_network(IMSG_NETWORK_ADD, &n->net, > - &n->net.attrset)) > - return (-1); > + kr_net_redist_add(kt, &n->net, > + &n->net.attrset, 0); > } else > hasdyn = 1; > > @@ -1640,13 +1635,53 @@ knexthop_compare(struct knexthop_node *a > } > break; > default: > - fatalx("knexthop_compare: unknown AF"); > + fatalx("%s: unknown AF", __func__); > } > > return (0); > } > > int > +kredist_compare(struct kredist_node *a, struct kredist_node *b) > +{ > + int i; > + > + if (a->prefix.aid != b->prefix.aid) > + return (b->prefix.aid - a->prefix.aid); > + > + if (a->prefixlen < b->prefixlen) > + return (-1); > + if (a->prefixlen > b->prefixlen) > + return (1); > + > + switch (a->prefix.aid) { > + case AID_INET: > + if (ntohl(a->prefix.v4.s_addr) < ntohl(b->prefix.v4.s_addr)) > + return (-1); > + if (ntohl(a->prefix.v4.s_addr) > ntohl(b->prefix.v4.s_addr)) > + return (1); > + break; > + case AID_INET6: > + for (i = 0; i < 16; i++) { > + if (a->prefix.v6.s6_addr[i] < b->prefix.v6.s6_addr[i]) > + return (-1); > + if (a->prefix.v6.s6_addr[i] > b->prefix.v6.s6_addr[i]) > + return (1); > + } > + break; > + default: > + fatalx("%s: unknown AF", __func__); > + } > + > + if (a->rd < b->rd) > + return (-1); > + if (a->rd > b->rd) > + return (1); > + > + return (0); > +} > + > +int > kif_compare(struct kif_node *a, struct kif_node *b) > { > return (b->k.ifindex - a->k.ifindex); > @@ -3506,21 +3541,14 @@ dispatch_rtmsg_addr(struct rt_msghdr *rt > changed = 1; > kr->r.flags = flags; > > - if (rtlabel_changed) { > - if (oflags & F_REDISTRIBUTED) { > - kr->r.flags |= F_REDISTRIBUTED; > - kr_redistribute( > - IMSG_NETWORK_REMOVE, kt, > - &kr->r); > - } > + if (rtlabel_changed) > kr_redistribute(IMSG_NETWORK_ADD, > kt, &kr->r); > - } > > if ((oflags & F_CONNECTED) && > !(flags & F_CONNECTED)) { > kif_kr_remove(kr); > - kr_redistribute(IMSG_NETWORK_REMOVE, > + kr_redistribute(IMSG_NETWORK_ADD, > kt, &kr->r); > } > if ((flags & F_CONNECTED) && > @@ -3619,21 +3647,14 @@ add4: > changed = 1; > kr6->r.flags = flags; > > - if (rtlabel_changed) { > - if (oflags & F_REDISTRIBUTED) { > - kr6->r.flags |= F_REDISTRIBUTED; > - kr_redistribute6( > - IMSG_NETWORK_REMOVE, kt, > - &kr6->r); > - } > + if (rtlabel_changed) > kr_redistribute6(IMSG_NETWORK_ADD, > kt, &kr6->r); > - } > > if ((oflags & F_CONNECTED) && > !(flags & F_CONNECTED)) { > kif_kr6_remove(kr6); > - kr_redistribute6(IMSG_NETWORK_REMOVE, > + kr_redistribute6(IMSG_NETWORK_ADD, > kt, &kr6->r); > } > if ((flags & F_CONNECTED) && > Index: usr.sbin/bgpd/parse.y > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v > retrieving revision 1.369 > diff -u -p -r1.369 parse.y > --- usr.sbin/bgpd/parse.y 4 Feb 2019 18:53:10 -0000 1.369 > +++ usr.sbin/bgpd/parse.y 7 Feb 2019 10:11:19 -0000 > @@ -91,7 +91,7 @@ static struct network_head *netconf; > static struct peer *peer_l, *peer_l_old; > static struct peer *curpeer; > static struct peer *curgroup; > -static struct rdomain *currdom; > +static struct l3vpn *curvpn; > static struct prefixset *curpset, *curoset; > static struct prefixset_tree *curpsitree; > static struct filter_head *filter_l; > @@ -154,7 +154,6 @@ void optimize_filters(struct filter_he > struct filter_rule *get_rule(enum action_types); > > int parsecommunity(struct filter_community *, int, char *); > -int parsesubtype(char *, int *, int *); > int parseextcommunity(struct filter_community *, char *, > char *); > static int new_as_set(char *); > @@ -195,7 +194,7 @@ typedef struct { > %} > > %token AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE FIBPRIORITY RTABLE > -%token RDOMAIN RD EXPORT EXPORTTRGT IMPORTTRGT > +%token NONE UNICAST VPN RD EXPORT EXPORTTRGT IMPORTTRGT > %token RDE RIB EVALUATE IGNORE COMPARE > %token GROUP NEIGHBOR NETWORK > %token EBGP IBGP > @@ -223,7 +222,7 @@ typedef struct { > %token <v.string> STRING > %token <v.number> NUMBER > %type <v.number> asnumber as4number as4number_any > optnumber > -%type <v.number> espah family restart origincode nettype > +%type <v.number> espah family safi restart origincode > nettype > %type <v.number> yesno inout restricted validity > %type <v.string> string > %type <v.addr> address > @@ -253,7 +252,7 @@ grammar : /* empty */ > | grammar roa_set '\n' > | grammar origin_set '\n' > | grammar conf_main '\n' > - | grammar rdomain '\n' > + | grammar l3vpn '\n' > | grammar neighbor '\n' > | grammar group '\n' > | grammar filterrule '\n' > @@ -1044,39 +1043,57 @@ optnumber : /* empty */ { $$ = 0; } > | NUMBER > ; > > -rdomain : RDOMAIN NUMBER { > - if ($2 > RT_TABLEID_MAX) { > - yyerror("rtable %llu too big: max %u", $2, > - RT_TABLEID_MAX); > - YYERROR; > +l3vpn : VPN STRING ON STRING { > + u_int rdomain, label; > + > + if (get_mpe_config($4, &rdomain, &label) == -1) { > + yyerror("troubles getting config of %s", $4); > + if ((cmd_opts & BGPD_OPT_NOACTION) == 0) { > + free($4); > + free($2); > + YYERROR; > + } > } > - if ((cmd_opts & BGPD_OPT_NOACTION) == 0 && > - ktable_exists($2, NULL) != 1) { > - yyerror("rdomain %lld does not exist", $2); > + > + if (!(curvpn = calloc(1, sizeof(struct l3vpn)))) > + fatal(NULL); > + strlcpy(curvpn->ifmpe, $4, IFNAMSIZ); > + > + if (strlcpy(curvpn->descr, $2, > + sizeof(curvpn->descr)) >= > + sizeof(curvpn->descr)) { > + yyerror("descr \"%s\" too long: max %zu", > + $2, sizeof(curvpn->descr) - 1); > + free($2); > + free($4); > + free(curvpn); > + curvpn = NULL; > YYERROR; > } > - if (!(currdom = calloc(1, sizeof(struct rdomain)))) > - fatal(NULL); > - currdom->rtableid = $2; > - TAILQ_INIT(&currdom->import); > - TAILQ_INIT(&currdom->export); > - TAILQ_INIT(&currdom->net_l); > - netconf = &currdom->net_l; > - } '{' rdomainopts_l '}' { > + free($2); > + free($4); > + > + TAILQ_INIT(&curvpn->import); > + TAILQ_INIT(&curvpn->export); > + TAILQ_INIT(&curvpn->net_l); > + curvpn->label = label; > + curvpn->rtableid = rdomain; > + netconf = &curvpn->net_l; > + } '{' l3vpnopts_l '}' { > /* insert into list */ > - SIMPLEQ_INSERT_TAIL(&conf->rdomains, currdom, entry); > - currdom = NULL; > + SIMPLEQ_INSERT_TAIL(&conf->l3vpns, curvpn, entry); > + curvpn = NULL; > netconf = &conf->networks; > } > ; > > -rdomainopts_l : /* empty */ > - | rdomainopts_l '\n' > - | rdomainopts_l rdomainopts '\n' > - | rdomainopts_l error '\n' > +l3vpnopts_l : /* empty */ > + | l3vpnopts_l '\n' > + | l3vpnopts_l l3vpnopts '\n' > + | l3vpnopts_l error '\n' > ; > > -rdomainopts : RD STRING { > +l3vpnopts : RD STRING { > struct filter_community ext; > u_int64_t rd; > > @@ -1108,7 +1125,7 @@ rdomainopts : RD STRING { > yyerror("bad encoding of rd"); > YYERROR; > } > - currdom->rd = htobe64(rd); > + curvpn->rd = htobe64(rd); > } > | EXPORTTRGT STRING STRING { > struct filter_set *set; > @@ -1126,7 +1143,7 @@ rdomainopts : RD STRING { > } > free($3); > free($2); > - TAILQ_INSERT_TAIL(&currdom->export, set, entry); > + TAILQ_INSERT_TAIL(&curvpn->export, set, entry); > } > | IMPORTTRGT STRING STRING { > struct filter_set *set; > @@ -1144,44 +1161,15 @@ rdomainopts : RD STRING { > } > free($3); > free($2); > - TAILQ_INSERT_TAIL(&currdom->import, set, entry); > - } > - | DESCR string { > - if (strlcpy(currdom->descr, $2, > - sizeof(currdom->descr)) >= > - sizeof(currdom->descr)) { > - yyerror("descr \"%s\" too long: max %zu", > - $2, sizeof(currdom->descr) - 1); > - free($2); > - YYERROR; > - } > - free($2); > + TAILQ_INSERT_TAIL(&curvpn->import, set, entry); > } > | FIBUPDATE yesno { > if ($2 == 0) > - currdom->flags |= F_RIB_NOFIBSYNC; > + curvpn->flags |= F_RIB_NOFIBSYNC; > else > - currdom->flags &= ~F_RIB_NOFIBSYNC; > + curvpn->flags &= ~F_RIB_NOFIBSYNC; > } > | network > - | DEPEND ON STRING { > - /* XXX this is a hack */ > - if ((cmd_opts & BGPD_OPT_NOACTION) == 0 && > - if_nametoindex($3) == 0) { > - yyerror("interface %s does not exist", $3); > - free($3); > - YYERROR; > - } > - strlcpy(currdom->ifmpe, $3, IFNAMSIZ); > - free($3); > - /* XXX this is in the wrong place */ > - if ((cmd_opts & BGPD_OPT_NOACTION) == 0 && > - get_mpe_label(currdom)) { > - yyerror("failed to get mpls label from %s", > - currdom->ifmpe); > - YYERROR; > - } > - } > ; > > neighbor : { curpeer = new_peer(); } > @@ -1350,30 +1338,23 @@ peeropts : REMOTEAS as4number { > } > curpeer->conf.min_holdtime = $3; > } > - | ANNOUNCE family STRING { > + | ANNOUNCE family safi { > u_int8_t aid, safi; > - int8_t val = 1; > + u_int16_t afi; > > - if (!strcmp($3, "none")) { > - safi = SAFI_UNICAST; > - val = 0; > - } else if (!strcmp($3, "unicast")) { > - safi = SAFI_UNICAST; > - } else if (!strcmp($3, "vpn")) { > - safi = SAFI_MPLSVPN; > + if ($3 == SAFI_NONE) { > + for (aid = 0; aid < AID_MAX; aid++) { > + if (aid2afi(aid, &afi, &safi) == -1) > + continue; > + curpeer->conf.capabilities.mp[aid] = 0; > + } > } else { > - yyerror("unknown/unsupported SAFI \"%s\"", > - $3); > - free($3); > - YYERROR; > - } > - free($3); > - > - if (afi2aid($2, safi, &aid) == -1) { > - yyerror("unknown AFI/SAFI pair"); > - YYERROR; > + if (afi2aid($2, $3, &aid) == -1) { > + yyerror("unknown AFI/SAFI pair"); > + YYERROR; > + } > + curpeer->conf.capabilities.mp[aid] = 1; > } > - curpeer->conf.capabilities.mp[aid] = val; > } > | ANNOUNCE CAPABILITIES yesno { > curpeer->conf.announce_capa = $3; > @@ -1717,6 +1698,11 @@ family : IPV4 { $$ = AFI_IPv4; } > | IPV6 { $$ = AFI_IPv6; } > ; > > +safi : NONE { $$ = SAFI_NONE; } > + | UNICAST { $$ = SAFI_UNICAST; } > + | VPN { $$ = SAFI_MPLSVPN; } > + ; > + > nettype : STATIC { $$ = 1; }, > | CONNECTED { $$ = 0; } > ; > @@ -2880,6 +2866,7 @@ lookup(char *s) > { "network", NETWORK}, > { "nexthop", NEXTHOP}, > { "no-modify", NOMODIFY}, > + { "none", NONE}, > { "on", ON}, > { "or-longer", LONGER}, > { "origin", ORIGIN}, > @@ -2900,7 +2887,6 @@ lookup(char *s) > { "quick", QUICK}, > { "rd", RD}, > { "rde", RDE}, > - { "rdomain", RDOMAIN}, > { "refresh", REFRESH }, > { "reject", REJECT}, > { "remote-as", REMOTEAS}, > @@ -2924,7 +2910,9 @@ lookup(char *s) > { "transit-as", TRANSITAS}, > { "transparent-as", TRANSPARENT}, > { "ttl-security", TTLSECURITY}, > + { "unicast", UNICAST}, > { "via", VIA}, > + { "vpn", VPN}, > { "weight", WEIGHT} > }; > const struct keywords *p; > @@ -3586,7 +3574,7 @@ parsecommunity(struct filter_community * > return (0); > } > > -int > +static int > parsesubtype(char *name, int *type, int *subtype) > { > const struct ext_comm_pairs *cp; > Index: usr.sbin/bgpd/printconf.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v > retrieving revision 1.127 > diff -u -p -r1.127 printconf.c > --- usr.sbin/bgpd/printconf.c 4 Feb 2019 18:53:10 -0000 1.127 > +++ usr.sbin/bgpd/printconf.c 7 Feb 2019 10:11:19 -0000 > @@ -35,8 +35,8 @@ void print_community(struct filter_com > void print_origin(u_int8_t); > void print_set(struct filter_set_head *); > void print_mainconf(struct bgpd_config *); > -void print_rdomain_targets(struct filter_set_head *, const char *); > -void print_rdomain(struct rdomain *); > +void print_l3vpn_targets(struct filter_set_head *, const char *); > +void print_l3vpn(struct l3vpn *); > const char *print_af(u_int8_t); > void print_network(struct network_config *, const char *); > void print_as_sets(struct as_set_head *); > @@ -378,7 +378,7 @@ print_mainconf(struct bgpd_config *conf) > } > > void > -print_rdomain_targets(struct filter_set_head *set, const char *tgt) > +print_l3vpn_targets(struct filter_set_head *set, const char *tgt) > { > struct filter_set *s; > TAILQ_FOREACH(s, set, entry) { > @@ -389,27 +389,24 @@ print_rdomain_targets(struct filter_set_ > } > > void > -print_rdomain(struct rdomain *r) > +print_l3vpn(struct l3vpn *vpn) > { > struct network *n; > > - printf("rdomain %u {\n", r->rtableid); > - if (*r->descr) > - printf("\tdescr \"%s\"\n", r->descr); > - if (r->flags & F_RIB_NOFIBSYNC) > + printf("vpn \"%s\" on %s {\n", vpn->descr, vpn->ifmpe); > + printf("\n\t%s\n", log_rd(vpn->rd)); > + > + print_l3vpn_targets(&vpn->export, "export-target"); > + print_l3vpn_targets(&vpn->import, "import-target"); > + > + if (vpn->flags & F_RIB_NOFIBSYNC) > printf("\tfib-update no\n"); > else > printf("\tfib-update yes\n"); > - printf("\tdepend on %s\n", r->ifmpe); > > - TAILQ_FOREACH(n, &r->net_l, entry) > + TAILQ_FOREACH(n, &vpn->net_l, entry) > print_network(&n->net, "\t"); > > - printf("\n\t%s\n", log_rd(r->rd)); > - > - print_rdomain_targets(&r->export, "export-target"); > - print_rdomain_targets(&r->import, "import-target"); > - > printf("}\n"); > } > > @@ -958,12 +955,12 @@ void > print_config(struct bgpd_config *conf, struct rib_names *rib_l, > struct network_head *net_l, struct peer *peer_l, > struct filter_head *rules_l, struct mrt_head *mrt_l, > - struct rdomain_head *rdom_l) > + struct l3vpn_head *vpns_l) > { > struct filter_rule *r; > struct network *n; > struct rde_rib *rr; > - struct rdomain *rd; > + struct l3vpn *vpn; > > print_mainconf(conf); > print_roa(&conf->roa); > @@ -972,10 +969,10 @@ print_config(struct bgpd_config *conf, s > print_originsets(&conf->originsets); > TAILQ_FOREACH(n, net_l, entry) > print_network(&n->net, ""); > - if (!SIMPLEQ_EMPTY(rdom_l)) > + if (!SIMPLEQ_EMPTY(vpns_l)) > printf("\n"); > - SIMPLEQ_FOREACH(rd, rdom_l, entry) > - print_rdomain(rd); > + SIMPLEQ_FOREACH(vpn, vpns_l, entry) > + print_l3vpn(vpn); > printf("\n"); > SIMPLEQ_FOREACH(rr, rib_l, entry) { > if (rr->flags & F_RIB_NOEVALUATE) > Index: usr.sbin/bgpd/rde.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v > retrieving revision 1.461 > diff -u -p -r1.461 rde.c > --- usr.sbin/bgpd/rde.c 21 Jan 2019 02:07:56 -0000 1.461 > +++ usr.sbin/bgpd/rde.c 7 Feb 2019 10:11:19 -0000 > @@ -75,7 +75,7 @@ void rde_dump_ctx_throttle(pid_t, int) > void rde_dump_ctx_terminate(pid_t); > void rde_dump_mrt_new(struct mrt *, pid_t, int); > > -int rde_rdomain_import(struct rde_aspath *, struct rdomain *); > +int rde_l3vpn_import(struct rde_aspath *, struct l3vpn *); > void rde_reload_done(void); > static void rde_softreconfig_in_done(void *, u_int8_t); > static void rde_softreconfig_out_done(void *, u_int8_t); > @@ -124,7 +124,7 @@ struct rde_prefixset_head originsets_old > struct rde_prefixset roa_old; > struct as_set_head *as_sets_tmp, *as_sets_old; > struct filter_head *out_rules, *out_rules_tmp; > -struct rdomain_head *rdomains_l, *newdomains; > +struct l3vpn_head *l3vpns_l, *newdomains; > struct imsgbuf *ibuf_se; > struct imsgbuf *ibuf_se_ctl; > struct imsgbuf *ibuf_main; > @@ -227,10 +227,10 @@ rde_main(int debug, int verbose) > fatal(NULL); > TAILQ_INIT(out_rules); > > - rdomains_l = calloc(1, sizeof(struct rdomain_head)); > - if (rdomains_l == NULL) > + l3vpns_l = calloc(1, sizeof(struct l3vpn_head)); > + if (l3vpns_l == NULL) > fatal(NULL); > - SIMPLEQ_INIT(rdomains_l); > + SIMPLEQ_INIT(l3vpns_l); > > if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL) > fatal(NULL); > @@ -675,7 +675,7 @@ rde_dispatch_imsg_parent(struct imsgbuf > static struct rde_prefixset *last_prefixset; > static struct as_set *last_as_set; > static struct set_table *last_set; > - static struct rdomain *rd; > + static struct l3vpn *vpn; > struct imsg imsg; > struct mrt xmrt; > struct rde_rib rn; > @@ -764,7 +764,7 @@ rde_dispatch_imsg_parent(struct imsgbuf > if (out_rules_tmp == NULL) > fatal(NULL); > TAILQ_INIT(out_rules_tmp); > - newdomains = calloc(1, sizeof(struct rdomain_head)); > + newdomains = calloc(1, sizeof(struct l3vpn_head)); > if (newdomains == NULL) > fatal(NULL); > SIMPLEQ_INIT(newdomains); > @@ -948,34 +948,34 @@ rde_dispatch_imsg_parent(struct imsgbuf > set_prep(last_as_set->set); > last_as_set = NULL; > break; > - case IMSG_RECONF_RDOMAIN: > + case IMSG_RECONF_VPN: > if (imsg.hdr.len - IMSG_HEADER_SIZE != > - sizeof(struct rdomain)) > - fatalx("IMSG_RECONF_RDOMAIN bad len"); > - if ((rd = malloc(sizeof(struct rdomain))) == NULL) > + sizeof(struct l3vpn)) > + fatalx("IMSG_RECONF_VPN bad len"); > + if ((vpn = malloc(sizeof(struct l3vpn))) == NULL) > fatal(NULL); > - memcpy(rd, imsg.data, sizeof(struct rdomain)); > - TAILQ_INIT(&rd->import); > - TAILQ_INIT(&rd->export); > - SIMPLEQ_INSERT_TAIL(newdomains, rd, entry); > + memcpy(vpn, imsg.data, sizeof(struct l3vpn)); > + TAILQ_INIT(&vpn->import); > + TAILQ_INIT(&vpn->export); > + SIMPLEQ_INSERT_TAIL(newdomains, vpn, entry); > break; > - case IMSG_RECONF_RDOMAIN_EXPORT: > - if (rd == NULL) { > + case IMSG_RECONF_VPN_EXPORT: > + if (vpn == NULL) { > log_warnx("rde_dispatch_imsg_parent: " > - "IMSG_RECONF_RDOMAIN_EXPORT unexpected"); > + "IMSG_RECONF_VPN_EXPORT unexpected"); > break; > } > - parent_set = &rd->export; > + parent_set = &vpn->export; > break; > - case IMSG_RECONF_RDOMAIN_IMPORT: > - if (rd == NULL) { > + case IMSG_RECONF_VPN_IMPORT: > + if (vpn == NULL) { > log_warnx("rde_dispatch_imsg_parent: " > - "IMSG_RECONF_RDOMAIN_IMPORT unexpected"); > + "IMSG_RECONF_VPN_IMPORT unexpected"); > break; > } > - parent_set = &rd->import; > + parent_set = &vpn->import; > break; > - case IMSG_RECONF_RDOMAIN_DONE: > + case IMSG_RECONF_VPN_DONE: > parent_set = NULL; > break; > case IMSG_RECONF_DRAIN: > @@ -2530,7 +2530,7 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t > * kroute specific functions > */ > int > -rde_rdomain_import(struct rde_aspath *asp, struct rdomain *rd) > +rde_l3vpn_import(struct rde_aspath *asp, struct l3vpn *rd) > { > struct filter_set *s; > > @@ -2548,7 +2548,7 @@ rde_send_kroute(struct rib *rib, struct > struct bgpd_addr addr; > struct prefix *p; > struct rde_aspath *asp; > - struct rdomain *rd; > + struct l3vpn *vpn; > enum imsg_type type; > > /* > @@ -2588,8 +2588,8 @@ rde_send_kroute(struct rib *rib, struct > /* not Loc-RIB, no update for VPNs */ > break; > > - SIMPLEQ_FOREACH(rd, rdomains_l, entry) { > - if (!rde_rdomain_import(asp, rd)) > + SIMPLEQ_FOREACH(vpn, l3vpns_l, entry) { > + if (!rde_l3vpn_import(asp, vpn)) > continue; > /* must send exit_nexthop so that correct MPLS tunnel > * is chosen > @@ -2599,8 +2599,8 @@ rde_send_kroute(struct rib *rib, struct > &prefix_nexthop(p)->exit_nexthop, > sizeof(kr.nexthop)); > /* XXX not ideal but this will change */ > - kr.ifindex = if_nametoindex(rd->ifmpe); > - if (imsg_compose(ibuf_main, type, rd->rtableid, 0, -1, > + kr.ifindex = if_nametoindex(vpn->ifmpe); > + if (imsg_compose(ibuf_main, type, vpn->rtableid, 0, -1, > &kr, sizeof(kr)) == -1) > fatal("%s %d imsg_compose error", __func__, > __LINE__); > @@ -2881,7 +2881,7 @@ rde_send_nexthop(struct bgpd_addr *next, > void > rde_reload_done(void) > { > - struct rdomain *rd; > + struct l3vpn *vpn; > struct rde_peer *peer; > struct filter_head *fh; > u_int16_t rid; > @@ -2923,15 +2923,15 @@ rde_reload_done(void) > peerself->conf.remote_masklen = 32; > peerself->short_as = conf->short_as; > > - /* apply new set of rdomain, sync will be done later */ > - while ((rd = SIMPLEQ_FIRST(rdomains_l)) != NULL) { > - SIMPLEQ_REMOVE_HEAD(rdomains_l, entry); > - filterset_free(&rd->import); > - filterset_free(&rd->export); > - free(rd); > + /* apply new set of l3vpn, sync will be done later */ > + while ((vpn = SIMPLEQ_FIRST(l3vpns_l)) != NULL) { > + SIMPLEQ_REMOVE_HEAD(l3vpns_l, entry); > + filterset_free(&vpn->import); > + filterset_free(&vpn->export); > + free(vpn); > } > - free(rdomains_l); > - rdomains_l = newdomains; > + free(l3vpns_l); > + l3vpns_l = newdomains; > /* XXX WHERE IS THE SYNC ??? */ > > /* check if roa changed */ > @@ -3687,7 +3687,7 @@ void > network_add(struct network_config *nc, int flagstatic) > { > struct filterstate state; > - struct rdomain *rd; > + struct l3vpn *vpn; > struct rde_aspath *asp; > struct filter_set_head *vpnset = NULL; > in_addr_t prefix4; > @@ -3695,44 +3695,44 @@ network_add(struct network_config *nc, i > u_int8_t vstate; > u_int16_t i; > > - if (nc->rtableid != conf->default_tableid) { > - SIMPLEQ_FOREACH(rd, rdomains_l, entry) { > - if (rd->rtableid != nc->rtableid) > + if (nc->rd != 0) { > + SIMPLEQ_FOREACH(vpn, l3vpns_l, entry) { > + if (vpn->rd != nc->rd) > continue; > switch (nc->prefix.aid) { > case AID_INET: > prefix4 = nc->prefix.v4.s_addr; > bzero(&nc->prefix, sizeof(nc->prefix)); > nc->prefix.aid = AID_VPN_IPv4; > - nc->prefix.vpn4.rd = rd->rd; > + nc->prefix.vpn4.rd = vpn->rd; > nc->prefix.vpn4.addr.s_addr = prefix4; > nc->prefix.vpn4.labellen = 3; > nc->prefix.vpn4.labelstack[0] = > - (rd->label >> 12) & 0xff; > + (vpn->label >> 12) & 0xff; > nc->prefix.vpn4.labelstack[1] = > - (rd->label >> 4) & 0xff; > + (vpn->label >> 4) & 0xff; > nc->prefix.vpn4.labelstack[2] = > - (rd->label << 4) & 0xf0; > + (vpn->label << 4) & 0xf0; > nc->prefix.vpn4.labelstack[2] |= BGP_MPLS_BOS; > - vpnset = &rd->export; > + vpnset = &vpn->export; > break; > case AID_INET6: > memcpy(&prefix6, &nc->prefix.v6.s6_addr, > sizeof(struct in6_addr)); > memset(&nc->prefix, 0, sizeof(nc->prefix)); > nc->prefix.aid = AID_VPN_IPv6; > - nc->prefix.vpn6.rd = rd->rd; > + nc->prefix.vpn6.rd = vpn->rd; > memcpy(&nc->prefix.vpn6.addr.s6_addr, &prefix6, > sizeof(struct in6_addr)); > nc->prefix.vpn6.labellen = 3; > nc->prefix.vpn6.labelstack[0] = > - (rd->label >> 12) & 0xff; > + (vpn->label >> 12) & 0xff; > nc->prefix.vpn6.labelstack[1] = > - (rd->label >> 4) & 0xff; > + (vpn->label >> 4) & 0xff; > nc->prefix.vpn6.labelstack[2] = > - (rd->label << 4) & 0xf0; > + (vpn->label << 4) & 0xf0; > nc->prefix.vpn6.labelstack[2] |= BGP_MPLS_BOS; > - vpnset = &rd->export; > + vpnset = &vpn->export; > break; > default: > log_warnx("unable to VPNize prefix"); > @@ -3741,10 +3741,11 @@ network_add(struct network_config *nc, i > } > break; > } > - if (rd == NULL) { > + if (vpn == NULL) { > log_warnx("network_add: " > - "prefix %s/%u in non-existing rdomain %u", > - log_addr(&nc->prefix), nc->prefixlen, nc->rtableid); > + "prefix %s/%u in non-existing l3vpn %s", > + log_addr(&nc->prefix), nc->prefixlen, > + log_rd(nc->rd)); > return; > } > } > @@ -3789,29 +3790,29 @@ network_add(struct network_config *nc, i > void > network_delete(struct network_config *nc) > { > - struct rdomain *rd; > + struct l3vpn *vpn; > in_addr_t prefix4; > struct in6_addr prefix6; > u_int32_t i; > > - if (nc->rtableid) { > - SIMPLEQ_FOREACH(rd, rdomains_l, entry) { > - if (rd->rtableid != nc->rtableid) > + if (nc->rd) { > + SIMPLEQ_FOREACH(vpn, l3vpns_l, entry) { > + if (vpn->rd != nc->rd) > continue; > switch (nc->prefix.aid) { > case AID_INET: > prefix4 = nc->prefix.v4.s_addr; > bzero(&nc->prefix, sizeof(nc->prefix)); > nc->prefix.aid = AID_VPN_IPv4; > - nc->prefix.vpn4.rd = rd->rd; > + nc->prefix.vpn4.rd = vpn->rd; > nc->prefix.vpn4.addr.s_addr = prefix4; > nc->prefix.vpn4.labellen = 3; > nc->prefix.vpn4.labelstack[0] = > - (rd->label >> 12) & 0xff; > + (vpn->label >> 12) & 0xff; > nc->prefix.vpn4.labelstack[1] = > - (rd->label >> 4) & 0xff; > + (vpn->label >> 4) & 0xff; > nc->prefix.vpn4.labelstack[2] = > - (rd->label << 4) & 0xf0; > + (vpn->label << 4) & 0xf0; > nc->prefix.vpn4.labelstack[2] |= BGP_MPLS_BOS; > break; > case AID_INET6: > @@ -3819,16 +3820,16 @@ network_delete(struct network_config *nc > sizeof(struct in6_addr)); > memset(&nc->prefix, 0, sizeof(nc->prefix)); > nc->prefix.aid = AID_VPN_IPv6; > - nc->prefix.vpn6.rd = rd->rd; > + nc->prefix.vpn6.rd = vpn->rd; > memcpy(&nc->prefix.vpn6.addr.s6_addr, &prefix6, > sizeof(struct in6_addr)); > nc->prefix.vpn6.labellen = 3; > nc->prefix.vpn6.labelstack[0] = > - (rd->label >> 12) & 0xff; > + (vpn->label >> 12) & 0xff; > nc->prefix.vpn6.labelstack[1] = > - (rd->label >> 4) & 0xff; > + (vpn->label >> 4) & 0xff; > nc->prefix.vpn6.labelstack[2] = > - (rd->label << 4) & 0xf0; > + (vpn->label << 4) & 0xf0; > nc->prefix.vpn6.labelstack[2] |= BGP_MPLS_BOS; > break; > default: > Index: usr.sbin/bgpd/session.h > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/session.h,v > retrieving revision 1.128 > diff -u -p -r1.128 session.h > --- usr.sbin/bgpd/session.h 20 Jan 2019 23:27:48 -0000 1.128 > +++ usr.sbin/bgpd/session.h 7 Feb 2019 10:11:19 -0000 > @@ -248,7 +248,7 @@ int carp_demote_set(char *, int); > int merge_config(struct bgpd_config *, struct bgpd_config *, > struct peer *); > int prepare_listeners(struct bgpd_config *); > -int get_mpe_label(struct rdomain *); > +int get_mpe_config(const char *, u_int *, u_int *); > > /* control.c */ > int control_check(char *); > @@ -285,7 +285,7 @@ int pfkey_init(struct bgpd_sysdep *); > /* printconf.c */ > void print_config(struct bgpd_config *, struct rib_names *, > struct network_head *, struct peer *, struct filter_head *, > - struct mrt_head *, struct rdomain_head *); > + struct mrt_head *, struct l3vpn_head *); > > /* rde.c */ > void rde_main(int, int); >