(forgot to add the manual bit in the previous patch)
Hello,
Here is a patch to allow usage of extended communities with bgpctl :
bgpctl show ip bgp ext-community rt 10:10
bgpctl netw add 2001:db8:1::/64 ext soo 10:50
Denis
Index: bgpctl/bgpctl.8
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.8,v
retrieving revision 1.77
diff -u -p -r1.77 bgpctl.8
--- bgpctl/bgpctl.8 29 May 2017 21:27:36 -0000 1.77
+++ bgpctl/bgpctl.8 3 Jun 2017 14:30:51 -0000
@@ -326,6 +326,9 @@ anywhere in the AS path.
.It Cm community Ar community
Show all entries with community
.Ar community .
+.It Cm ext-community Ar ext-community
+Show all entries with extended-community
+.Ar ext-community .
.It Cm large-community Ar large-community
Show all entries with large-community
.Ar large-community .
Index: bgpctl/bgpctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
retrieving revision 1.195
diff -u -p -r1.195 bgpctl.c
--- bgpctl/bgpctl.c 31 May 2017 10:48:06 -0000 1.195
+++ bgpctl/bgpctl.c 3 Jun 2017 14:30:51 -0000
@@ -261,6 +261,11 @@ main(int argc, char *argv[])
sizeof(res->community));
type = IMSG_CTL_SHOW_RIB_COMMUNITY;
}
+ if (res->extcommunity.flags == EXT_COMMUNITY_FLAG_VALID) {
+ memcpy(&ribreq.extcommunity, &res->extcommunity,
+ sizeof(res->extcommunity));
+ type = IMSG_CTL_SHOW_RIB_EXTCOMMUNITY;
+ }
if (res->large_community.as != COMMUNITY_UNSET &&
res->large_community.ld1 != COMMUNITY_UNSET &&
res->large_community.ld2 != COMMUNITY_UNSET) {
Index: bgpctl/parser.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/parser.c,v
retrieving revision 1.77
diff -u -p -r1.77 parser.c
--- bgpctl/parser.c 14 Feb 2017 13:13:23 -0000 1.77
+++ bgpctl/parser.c 3 Jun 2017 14:30:51 -0000
@@ -47,6 +47,8 @@ enum token_type {
RIBNAME,
SHUTDOWN_COMMUNICATION,
COMMUNITY,
+ EXTCOMMUNITY,
+ EXTCOM_SUBTYPE,
LARGE_COMMUNITY,
LOCALPREF,
MED,
@@ -94,12 +96,16 @@ static const struct token t_show_mrt_as[
static const struct token t_show_prefix[];
static const struct token t_show_ip[];
static const struct token t_show_community[];
+static const struct token t_show_extcommunity[];
+static const struct token t_show_ext_subtype[];
static const struct token t_show_largecommunity[];
static const struct token t_network[];
static const struct token t_network_show[];
static const struct token t_prefix[];
static const struct token t_set[];
static const struct token t_community[];
+static const struct token t_extcommunity[];
+static const struct token t_ext_subtype[];
static const struct token t_largecommunity[];
static const struct token t_localpref[];
static const struct token t_med[];
@@ -166,6 +172,7 @@ static const struct token t_show_rib[] =
{ ASTYPE, "peer-as", AS_PEER, t_show_rib_as},
{ ASTYPE, "empty-as", AS_EMPTY, t_show_rib},
{ KEYWORD, "community", NONE, t_show_community},
+ { KEYWORD, "ext-community", NONE, t_show_extcommunity},
{ KEYWORD, "large-community", NONE, t_show_largecommunity},
{ FLAG, "best", F_CTL_ACTIVE, t_show_rib},
{ FLAG, "selected", F_CTL_ACTIVE, t_show_rib},
@@ -288,6 +295,29 @@ static const struct token t_show_communi
{ ENDTOKEN, "", NONE, NULL}
};
+static const struct token t_show_extcommunity[] = {
+ { EXTCOM_SUBTYPE, "bdc", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "defgw", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "esi-lab", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "esi-rt", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "l2vid", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "mac-mob", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "odi", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "ort", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "ori", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "ovs", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "rt", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "soo", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "srcas", NONE, t_show_ext_subtype},
+ { EXTCOM_SUBTYPE, "vrfri", NONE, t_show_ext_subtype},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_show_ext_subtype[] = {
+ { EXTCOMMUNITY, "", NONE, t_show_rib},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
static const struct token t_show_largecommunity[] = {
{ LARGE_COMMUNITY, "", NONE, t_show_rib},
{ ENDTOKEN, "", NONE, NULL}
@@ -317,6 +347,7 @@ static const struct token t_network_show
static const struct token t_set[] = {
{ NOTOKEN, "", NONE, NULL},
{ KEYWORD, "community", NONE, t_community},
+ { KEYWORD, "ext-community", NONE, t_extcommunity},
{ KEYWORD, "large-community", NONE, t_largecommunity},
{ KEYWORD, "localpref", NONE, t_localpref},
{ KEYWORD, "med", NONE, t_med},
@@ -336,6 +367,29 @@ static const struct token t_community[]
{ ENDTOKEN, "", NONE, NULL}
};
+static const struct token t_extcommunity[] = {
+ { EXTCOM_SUBTYPE, "bdc", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "defgw", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "esi-lab", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "esi-rt", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "l2vid", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "mac-mob", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "odi", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "ort", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "ori", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "ovs", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "rt", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "soo", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "srcas", NONE, t_ext_subtype},
+ { EXTCOM_SUBTYPE, "vrfri", NONE, t_ext_subtype},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
+static const struct token t_ext_subtype[] = {
+ { EXTCOMMUNITY, "", NONE, t_set},
+ { ENDTOKEN, "", NONE, NULL}
+};
+
static const struct token t_largecommunity[] = {
{ LARGE_COMMUNITY, "", NONE, t_set},
{ ENDTOKEN, "", NONE, NULL}
@@ -415,6 +469,9 @@ int parse_number(const char *, struct
enum token_type);
int getcommunity(const char *);
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 *);
u_int getlargecommunity(const char *);
int parse_largecommunity(const char *, struct parse_result
*);
int parse_nexthop(const char *, struct parse_result *);
@@ -595,6 +652,24 @@ match_token(int *argc, char **argv[], co
t = &table[i];
}
break;
+ case EXTCOM_SUBTYPE:
+ if (word != NULL && strncmp(word, table[i].keyword,
+ wordlen) == 0) {
+ if (parsesubtype(word, &res.extcommunity.type,
+ &res.extcommunity.subtype) == 0)
+ errx(1, "Bad ext-community unknown
type");
+
+ match++;
+ t = &table[i];
+ }
+ break;
+ case EXTCOMMUNITY:
+ if (word != NULL && wordlen > 0 &&
+ parseextcommunity(word, &res)) {
+ match++;
+ t = &table[i];
+ }
+ break;
case LARGE_COMMUNITY:
if (word != NULL && wordlen > 0 &&
parse_largecommunity(word, &res)) {
@@ -693,6 +768,7 @@ show_valid_args(const struct token table
case KEYWORD:
case FLAG:
case ASTYPE:
+ case EXTCOM_SUBTYPE:
fprintf(stderr, " %s\n", table[i].keyword);
break;
case ADDRESS:
@@ -717,6 +793,9 @@ show_valid_args(const struct token table
case COMMUNITY:
fprintf(stderr, " <community>\n");
break;
+ case EXTCOMMUNITY:
+ fprintf(stderr, " <extended-community>\n");
+ break;
case LARGE_COMMUNITY:
fprintf(stderr, " <large-community>\n");
break;
@@ -1011,6 +1090,180 @@ done:
TAILQ_INSERT_TAIL(&r->set, fs, entry);
return (1);
+}
+
+int
+parsesubtype(const char *name, u_int8_t *type, u_int8_t *subtype)
+{
+ const struct ext_comm_pairs *cp;
+ int found = 0;
+
+ for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
+ if (strcmp(name, cp->subname) == 0) {
+ if (found == 0) {
+ *type = cp->type;
+ *subtype = cp->subtype;
+ }
+ found++;
+ }
+ }
+ if (found > 1)
+ *type = -1;
+ return (found);
+}
+
+int
+parseextvalue(const char *s, u_int32_t *v)
+{
+ const char *errstr;
+ char *p;
+ struct in_addr ip;
+ u_int32_t uvalh = 0, uval;
+
+ if ((p = strchr(s, '.')) == NULL) {
+ /* 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);
+ else
+ return (EXT_COMMUNITY_TRANS_FOUR_AS);
+ } else if (strchr(p + 1, '.') == NULL) {
+ /* AS_DOT number (4-byte) */
+ *p++ = '\0';
+ uvalh = strtonum(s, 0, USHRT_MAX, &errstr);
+ if (errstr) {
+ fprintf(stderr, "Bad ext-community: %s is %s\n", s,
+ errstr);
+ return (-1);
+ }
+ uval = strtonum(p, 0, USHRT_MAX, &errstr);
+ if (errstr) {
+ fprintf(stderr, "Bad ext-community: %s is %s\n", p,
+ errstr);
+ return (-1);
+ }
+ *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);
+ }
+ *v = ip.s_addr;
+ return (EXT_COMMUNITY_TRANS_IPV4);
+ }
+ return (-1);
+}
+
+u_int
+parseextcommunity(const char *word, struct parse_result *r)
+{
+ 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;
+
+ type = r->extcommunity.type;
+
+ switch (type) {
+ case 0xff:
+ if ((p = strchr(word, ':')) == NULL) {
+ fprintf(stderr, "Bad ext-community: %s\n", word);
+ return (0);
+ }
+ *p++ = '\0';
+ if ((type = parseextvalue(word, &uval)) == -1)
+ return (0);
+ switch (type) {
+ case EXT_COMMUNITY_TRANS_TWO_AS:
+ ullval = strtonum(p, 0, UINT_MAX, &errstr);
+ break;
+ case EXT_COMMUNITY_TRANS_IPV4:
+ case EXT_COMMUNITY_TRANS_FOUR_AS:
+ 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->extcommunity.data.ext_as.as = uval;
+ r->extcommunity.data.ext_as.val = ullval;
+ break;
+ case EXT_COMMUNITY_TRANS_IPV4:
+ r->extcommunity.data.ext_ip.addr.s_addr = uval;
+ r->extcommunity.data.ext_ip.val = ullval;
+ break;
+ case EXT_COMMUNITY_TRANS_FOUR_AS:
+ r->extcommunity.data.ext_as4.as4 = uval;
+ r->extcommunity.data.ext_as4.val = ullval;
+ break;
+ }
+ 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->extcommunity.data.ext_opaq = ullval;
+ break;
+ case EXT_COMMUNITY_NON_TRANS_OPAQUE:
+ if (strcmp(word, "valid") == 0)
+ r->extcommunity.data.ext_opaq = EXT_COMMUNITY_OVS_VALID;
+ else if (strcmp(word, "invalid") == 0)
+ r->extcommunity.data.ext_opaq =
EXT_COMMUNITY_OVS_INVALID;
+ else if (strcmp(word, "not-found") == 0)
+ r->extcommunity.data.ext_opaq =
EXT_COMMUNITY_OVS_NOTFOUND;
+ else {
+ fprintf(stderr, "Bad ext-community value: %s\n", word);
+ return (0);
+ }
+ break;
+ }
+ r->extcommunity.type = type;
+
+ /* verify type/subtype combo */
+ for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
+ if (cp->type == r->extcommunity.type &&
+ cp->subtype == r->extcommunity.subtype) {
+ r->extcommunity.flags |= EXT_COMMUNITY_FLAG_VALID;
+ if ((fs = calloc(1, sizeof(struct filter_set))) == NULL)
+ err(1, NULL);
+
+ fs->type = ACTION_SET_EXT_COMMUNITY;
+ memcpy(&fs->action.ext_community, &r->extcommunity,
+ sizeof(struct filter_extcommunity));
+
+ TAILQ_INSERT_TAIL(&r->set, fs, entry);
+ return (1);
+ }
+ }
+
+ fprintf(stderr, "Bad ext-community: bad format for type\n");
+ return (0);
}
u_int
Index: bgpctl/parser.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/parser.h,v
retrieving revision 1.29
diff -u -p -r1.29 parser.h
--- bgpctl/parser.h 13 Jan 2017 18:59:12 -0000 1.29
+++ bgpctl/parser.h 3 Jun 2017 14:30:51 -0000
@@ -63,6 +63,7 @@ struct parse_result {
struct filter_as as;
struct filter_set_head set;
struct filter_community community;
+ struct filter_extcommunity extcommunity;
struct filter_largecommunity large_community;
char peerdesc[PEER_DESCR_LEN];
char rib[PEER_DESCR_LEN];
Index: bgpd/bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.308
diff -u -p -r1.308 bgpd.h
--- bgpd/bgpd.h 31 May 2017 10:44:00 -0000 1.308
+++ bgpd/bgpd.h 3 Jun 2017 14:30:51 -0000
@@ -383,6 +383,7 @@ enum imsg_type {
IMSG_CTL_SHOW_RIB_PREFIX,
IMSG_CTL_SHOW_RIB_ATTR,
IMSG_CTL_SHOW_RIB_COMMUNITY,
+ IMSG_CTL_SHOW_RIB_EXTCOMMUNITY,
IMSG_CTL_SHOW_RIB_LARGECOMMUNITY,
IMSG_CTL_SHOW_NETWORK,
IMSG_CTL_SHOW_RIB_MEM,
@@ -697,6 +698,7 @@ struct ctl_show_rib_request {
struct bgpd_addr prefix;
struct filter_as as;
struct filter_community community;
+ struct filter_extcommunity extcommunity;
struct filter_largecommunity large_community;
u_int32_t peerid;
pid_t pid;
Index: bgpd/control.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/control.c,v
retrieving revision 1.88
diff -u -p -r1.88 control.c
--- bgpd/control.c 28 May 2017 12:21:36 -0000 1.88
+++ bgpd/control.c 3 Jun 2017 14:30:51 -0000
@@ -252,6 +252,7 @@ control_dispatch_msg(struct pollfd *pfd,
case IMSG_CTL_SHOW_RIB_PREFIX:
case IMSG_CTL_SHOW_RIB_MEM:
case IMSG_CTL_SHOW_RIB_COMMUNITY:
+ case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY:
case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY:
case IMSG_CTL_SHOW_NETWORK:
case IMSG_CTL_SHOW_TERSE:
@@ -480,6 +481,7 @@ control_dispatch_msg(struct pollfd *pfd,
break;
case IMSG_CTL_SHOW_RIB_MEM:
case IMSG_CTL_SHOW_RIB_COMMUNITY:
+ case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY:
case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY:
case IMSG_CTL_SHOW_NETWORK:
c->ibuf.pid = imsg.hdr.pid;
Index: bgpd/rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.368
diff -u -p -r1.368 rde.c
--- bgpd/rde.c 29 May 2017 13:10:40 -0000 1.368
+++ bgpd/rde.c 3 Jun 2017 14:30:51 -0000
@@ -571,6 +571,7 @@ badnet:
case IMSG_CTL_SHOW_RIB:
case IMSG_CTL_SHOW_RIB_AS:
case IMSG_CTL_SHOW_RIB_COMMUNITY:
+ case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY:
case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY:
case IMSG_CTL_SHOW_RIB_PREFIX:
if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) {
@@ -2308,6 +2309,9 @@ rde_dump_filter(struct prefix *p, struct
!community_match(p->aspath, req->community.as,
req->community.type))
return;
+ if (req->type == IMSG_CTL_SHOW_RIB_EXTCOMMUNITY &&
+ !community_ext_match(p->aspath, &req->extcommunity, 0))
+ return;
if (req->type == IMSG_CTL_SHOW_RIB_LARGECOMMUNITY &&
!community_large_match(p->aspath, req->large_community.as,
req->large_community.ld1, req->large_community.ld2))
@@ -2394,6 +2398,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req
case IMSG_CTL_SHOW_RIB:
case IMSG_CTL_SHOW_RIB_AS:
case IMSG_CTL_SHOW_RIB_COMMUNITY:
+ case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY:
case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY:
ctx->ribctx.ctx_upcall = rde_dump_upcall;
break;