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.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 11:25:00 -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 11:25:00 -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 11:25:00 -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 11:25:00 -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 11:25:00 -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 11:25:00 -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;

Reply via email to