Dear all,

BGP Origin Validation State communities are non-transitive opaque
extended communities to carry the origination Autonomous System
validation state inside an autonomous system. IBGP speakers that
receive this validation state can configure local policies that allow it
to influence their decision process. https://tools.ietf.org/html/rfc8097

This patch allows to configurations such as the below. This
configuration was generated based on an external validation source (in
this case RPKI) and allows manipulation through well-known identifiers.

    match from any \
        set { ext-community bovs not-found \
              ext-community delete bovs invalid \
              ext-community delete bovs valid }
    match from any \
        prefix 2a02:898::/32 or-longer \
        set { ext-community bovs invalid }
    match from any \
        prefix 2a02:898::/32 source-as 8283 \
        set { ext-community bovs valid }
    match from any ext-community bovs valid \
        set { ext-community delete bovs invalid \
              ext-community delete bovs not-found }
    match from any ext-community bovs invalid \
        set { ext-community delete bovs not-found }

The following new mapping exists between keywords and Extended BGP
Communities:

        keywords        | ext type | subtype | value
        ----------------+----------+---------+-------
        bovs valid      |   0x2b   |   0x0   |  0x0
        bovs not-found  |   0x2b   |   0x0   |  0x1
        bovs invalid    |   0x2b   |   0x0   |  0x2

[job@kiera ~]$ bgpctl show rib detail 2a02:898::/32 longer-prefixes

BGP routing table entry for 2a02:898::/32
    2914 8283
    Nexthop 2001:728:0:1000::2 (via ???) from AS15562_scarlett_IPv6 
(165.254.255.1)
    Origin IGP, metric 0, localpref 100, weight 0, internal
    Last update: 00:00:49 ago
    Communities: 2914:420 2914:1206 2914:2203 2914:3200 65504:8283
    Ext. communities: bovs valid

[job@kiera ~]$

Index: bgpctl/bgpctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
retrieving revision 1.193
diff -u -p -r1.193 bgpctl.c
--- bgpctl/bgpctl.c     23 Jan 2017 23:38:51 -0000      1.193
+++ bgpctl/bgpctl.c     28 Mar 2017 19:01:33 -0000
@@ -1585,7 +1585,7 @@ show_ext_community(u_char *data, u_int16
        struct in_addr  ip;
        u_int32_t       as4, u32;
        u_int16_t       i, as2, u16;
-       u_int8_t        type, subtype;
+       u_int8_t        type, subtype, state;
 
        if (len & 0x7)
                return;
@@ -1618,6 +1618,13 @@ show_ext_community(u_char *data, u_int16
                        ext = betoh64(ext) & 0xffffffffffffLL;
                        printf("%s 0x%llx", log_ext_subtype(subtype), ext);
                        break;
+               case EXT_COMMUNITY_NON_TRANS_OPAQUE:
+                       if (subtype == EXT_COMMUNITY_VALIDATION_STATE) {
+                               state = data[i + 7];
+                               printf("%s %s", log_ext_subtype(subtype),
+                                   log_ext_bovs_value(state));
+                               break;
+                       }
                default:
                        memcpy(&ext, data + i, sizeof(ext));
                        printf("0x%llx", betoh64(ext));
Index: bgpd/bgpd.8
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.8,v
retrieving revision 1.52
diff -u -p -r1.52 bgpd.8
--- bgpd/bgpd.8 19 Feb 2017 11:38:24 -0000      1.52
+++ bgpd/bgpd.8 28 Mar 2017 19:01:33 -0000
@@ -390,6 +390,17 @@ control socket
 .%R draft-ietf-idr-shutdown
 .%T BGP Administrative Shutdown Communication
 .Re
+.Pp
+.Rs
+.%A P. Mohapatra
+.%A K. Patel
+.%A J. Scudder
+.%A D. Ward
+.%A R. Bush
+.%D March 2017
+.%R RFC 8097
+.%T BGP Prefix Origin Validation State Extended Community
+.Re
 .Sh HISTORY
 The
 .Nm
Index: bgpd/bgpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v
retrieving revision 1.152
diff -u -p -r1.152 bgpd.conf.5
--- bgpd/bgpd.conf.5    13 Jan 2017 18:59:12 -0000      1.152
+++ bgpd/bgpd.conf.5    28 Mar 2017 19:01:33 -0000
@@ -1195,6 +1195,11 @@ which is expanded to the current neighbo
 .Ic ext-community
 .Ar subtype Ar numvalue
 .Xc
+.It Xo
+.Ic ext-community
+.Ar bovs
+.Pq Ic valid | not-found | invalid
+.Xc
 This rule applies only to
 .Em UPDATES
 where the
@@ -1456,6 +1461,11 @@ to do wildcard matching.
 .Ic ext-community Op Ar delete
 .Ar subtype Ar numvalue
 .Xc
+.It Xo
+.Ic ext-community Op Ar delete
+.Ar bovs
+.Pq Ic valid | not-found | invalid
+.Xc
 Set or delete the
 .Em Extended Community
 AS path attribute.
@@ -1481,6 +1491,7 @@ odi      OSPF Domain Identifier
 ort      OSPF Route Type
 ori      OSPF Router ID
 bdc      BGP Data Collection
+bovs     BGP Origin Validation State
 .Ed
 .Pp
 Not all type and subtype value pairs are allowed by IANA and the parser
Index: bgpd/bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.300
diff -u -p -r1.300 bgpd.h
--- bgpd/bgpd.h 25 Jan 2017 00:11:07 -0000      1.300
+++ bgpd/bgpd.h 28 Mar 2017 19:01:33 -0000
@@ -755,7 +755,8 @@ struct filter_peers {
 #define EXT_COMMUNITY_TWO_AS           0       /* 2 octet AS specific */
 #define EXT_COMMUNITY_IPV4             1       /* IPv4 specific */
 #define EXT_COMMUNITY_FOUR_AS          2       /* 4 octet AS specific */
-#define EXT_COMMUNITY_OPAQUE           3       /* opaque ext community */
+#define EXT_COMMUNITY_OPAQUE           3       /* transitive opaque ext */
+#define EXT_COMMUNITY_NON_TRANS_OPAQUE 43      /* non-transitive opaque ext */
 /* sub types */
 #define EXT_COMMUNITY_ROUTE_TGT                2       /* RFC 4360 & RFC4364 */
 #define EXT_COMMUNITY_ROUTE_ORIG       3       /* RFC 4360 & RFC4364 */
@@ -763,6 +764,11 @@ struct filter_peers {
 #define EXT_COMMUNITY_OSPF_RTR_TYPE    6       /* RFC 4577 */
 #define EXT_COMMUNITY_OSPF_RTR_ID      7       /* RFC 4577 */
 #define EXT_COMMUNITY_BGP_COLLECT      8       /* RFC 4384 */
+#define EXT_COMMUNITY_VALIDATION_STATE 0       /* RFC 8097 */
+/* RFC 8097 validation states */
+#define EXT_COMMUNITY_VALIDATION_STATE_VALID   0
+#define EXT_COMMUNITY_VALIDATION_STATE_NOTFOUND        1
+#define EXT_COMMUNITY_VALIDATION_STATE_INVALID 2
 /* other handy defines */
 #define EXT_COMMUNITY_OPAQUE_MAX       0xffffffffffffULL
 #define EXT_COMMUNITY_FLAG_VALID       0x01
@@ -783,7 +789,8 @@ struct ext_comm_pairs {
        { EXT_COMMUNITY_IPV4, EXT_COMMUNITY_ROUTE_TGT, 0 },             \
        { EXT_COMMUNITY_IPV4, EXT_COMMUNITY_ROUTE_ORIG, 0 },            \
        { EXT_COMMUNITY_IPV4, EXT_COMMUNITY_OSPF_RTR_ID, 0 },           \
-       { EXT_COMMUNITY_OPAQUE, EXT_COMMUNITY_OSPF_RTR_TYPE, 0 }        \
+       { EXT_COMMUNITY_OPAQUE, EXT_COMMUNITY_OSPF_RTR_TYPE, 0 },       \
+       { EXT_COMMUNITY_NON_TRANS_OPAQUE, EXT_COMMUNITY_VALIDATION_STATE, 0 }   
\
 }
 
 
@@ -1067,6 +1074,7 @@ const char        *log_sockaddr(struct sockaddr
 const char     *log_as(u_int32_t);
 const char     *log_rd(u_int64_t);
 const char     *log_ext_subtype(u_int8_t);
+const char     *log_ext_bovs_value(u_int8_t);
 const char     *log_shutcomm(const char *);
 int             aspath_snprint(char *, size_t, void *, u_int16_t);
 int             aspath_asprint(char **, void *, u_int16_t);
Index: bgpd/parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.298
diff -u -p -r1.298 parse.y
--- bgpd/parse.y        22 Feb 2017 13:55:14 -0000      1.298
+++ bgpd/parse.y        28 Mar 2017 19:01:33 -0000
@@ -145,6 +145,7 @@ int          parsecommunity(struct filter_commu
 int64_t         getlargecommunity(char *);
 int             parselargecommunity(struct filter_largecommunity *, char *);
 int             parsesubtype(char *);
+int             parse_bgp_validation_state(char *);
 int             parseextvalue(char *, u_int32_t *);
 int             parseextcommunity(struct filter_extcommunity *, char *,
                    char *);
@@ -3022,11 +3023,31 @@ parselargecommunity(struct filter_largec
 }
 
 int
+parse_bgp_validation_state(char *state)
+{
+       /* this has to be sorted always */
+       static const struct keywords keywords[] = {
+               { "invalid",    EXT_COMMUNITY_VALIDATION_STATE_INVALID },
+               { "not-found",  EXT_COMMUNITY_VALIDATION_STATE_NOTFOUND },
+               { "valid",      EXT_COMMUNITY_VALIDATION_STATE_VALID }
+       };
+       const struct keywords   *p;
+       p = bsearch(state, keywords, sizeof(keywords)/sizeof(keywords[0]),
+               sizeof(keywords[0]), kw_cmp);
+
+       if (p)
+               return (p->k_val);
+       else
+               return (-1);
+}
+
+int
 parsesubtype(char *type)
 {
        /* this has to be sorted always */
        static const struct keywords keywords[] = {
                { "bdc",        EXT_COMMUNITY_BGP_COLLECT },
+               { "bovs",       EXT_COMMUNITY_VALIDATION_STATE },
                { "odi",        EXT_COMMUNITY_OSPF_DOM_ID },
                { "ori",        EXT_COMMUNITY_OSPF_RTR_ID },
                { "ort",        EXT_COMMUNITY_OSPF_RTR_TYPE },
@@ -3100,15 +3121,22 @@ parseextcommunity(struct filter_extcommu
        u_int32_t        uval;
        char            *p, *ep;
        unsigned int     i;
-       int              type, subtype;
+       int              type, state, subtype;
 
        if ((subtype = parsesubtype(t)) == -1) {
                yyerror("Bad ext-community unknown type");
                return (-1);
        }
 
-       if ((p = strchr(s, ':')) == NULL) {
-               type = EXT_COMMUNITY_OPAQUE,
+       if (subtype == EXT_COMMUNITY_VALIDATION_STATE) {
+               if ((state = parse_bgp_validation_state(s)) == -1) {
+                       yyerror("Invalid BGP Origin Validation State 
Community");
+                       return(-1);
+               }
+               type = EXT_COMMUNITY_NON_TRANS_OPAQUE;
+               c->data.ext_opaq = state;
+       } else if ((p = strchr(s, ':')) == NULL) {
+               type = EXT_COMMUNITY_OPAQUE;
                errno = 0;
                ullval = strtoull(s, &ep, 0);
                if (s[0] == '\0' || *ep != '\0') {
Index: bgpd/printconf.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
retrieving revision 1.100
diff -u -p -r1.100 printconf.c
--- bgpd/printconf.c    24 Jan 2017 04:22:42 -0000      1.100
+++ bgpd/printconf.c    28 Mar 2017 19:01:34 -0000
@@ -149,6 +149,7 @@ print_extcommunity(struct filter_extcomm
                    log_as(c->data.ext_as4.as4), c->data.ext_as.val);
                break;
        case EXT_COMMUNITY_OPAQUE:
+       case EXT_COMMUNITY_NON_TRANS_OPAQUE:
                printf("%s 0x%llx ", log_ext_subtype(c->subtype),
                    c->data.ext_opaq);
                break;
Index: bgpd/util.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/util.c,v
retrieving revision 1.24
diff -u -p -r1.24 util.c
--- bgpd/util.c 24 Jan 2017 04:22:42 -0000      1.24
+++ bgpd/util.c 28 Mar 2017 19:01:34 -0000
@@ -154,11 +154,32 @@ log_ext_subtype(u_int8_t subtype)
                return ("ori"); /* ospf router id */
        case EXT_COMMUNITY_BGP_COLLECT:
                return ("bdc"); /* bgp data collection */
+       case EXT_COMMUNITY_VALIDATION_STATE:
+               return ("bovs"); /* RFC 8097 */
        default:
                snprintf(etype, sizeof(etype), "[%u]", subtype);
                return (etype);
        }
 }
+
+const char *
+log_ext_bovs_value(u_int8_t value)
+{
+       static char s[6];
+
+       switch (value) {
+       case EXT_COMMUNITY_VALIDATION_STATE_VALID:
+               return ("valid");
+       case EXT_COMMUNITY_VALIDATION_STATE_NOTFOUND:
+               return ("not-found");
+       case EXT_COMMUNITY_VALIDATION_STATE_INVALID:
+               return ("invalid");
+       default:
+               snprintf(s, sizeof(s), "[%u?]", value);
+               return (s);
+       }
+}
+
 
 const char *
 log_shutcomm(const char *communication) {

Reply via email to