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).
--
: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);