Flowspec RFC 8955 and 8956 allows to propegate traffic filtering rules
to other routers. The main use case is to drop DDoS traffic further
upstream and by that reducing the impact of such denial of service
attacks.

This diff only adds the needed plumbing to announce the MP capability for
flowspec. Any flowspec UPDATE received will be silently ignored and there
is no way to send anything. Still this is a first small step and more
changes will follow to send flowspec rules.

The diff includes all the defines needed for flowspec.
On top of this there is a small fix in rde_update_dispatch() to
properly jump over unknown MP attributes (2 hunks).
In rde_get_mp_nexthop() I moved the AID_VPN_IPv6 case around and used the
same error message for lenght check in all cases. This is why the diff is
a bit larger.

I successfully tested this against exabgp.
-- 
:wq Claudio

Index: bgpd.8
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.8,v
retrieving revision 1.77
diff -u -p -r1.77 bgpd.8
--- bgpd.8      2 Mar 2023 17:09:53 -0000       1.77
+++ bgpd.8      3 Apr 2023 08:26:45 -0000
@@ -478,6 +478,26 @@ has been started.
 .Re
 .Pp
 .Rs
+.%A C. Loibl
+.%A S. Hares
+.%A R. Raszuk
+.%A D. McPherson
+.%A M. Bacher
+.%D December 2020
+.%R RFC 8955
+.%T Dissemination of Flow Specification Rules
+.Re
+.Pp
+.Rs
+.%A C. Loibl
+.%A R. Raszuk
+.%A S. Hares
+.%D December 2020
+.%R RFC 8956
+.%T Dissemination of Flow Specification Rules for IPv6
+.Re
+.Pp
+.Rs
 .%A E. Chen
 .%A J. Scudder
 .%D July 2021
Index: bgpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v
retrieving revision 1.233
diff -u -p -r1.233 bgpd.conf.5
--- bgpd.conf.5 13 Mar 2023 18:31:54 -0000      1.233
+++ bgpd.conf.5 3 Apr 2023 08:26:45 -0000
@@ -839,7 +839,7 @@ The neighbor properties are as follows:
 .It Xo
 .Ic announce
 .Pq Ic IPv4 Ns | Ns Ic IPv6
-.Pq Ic none Ns | Ns Ic unicast Ns | Ns Ic vpn
+.Pq Ic none Ns | Ns Ic unicast Ns | Ns Ic vpn | Ns Ic flowspec
 .Xc
 For the given address family, control which
 .Em subsequent address families
@@ -851,9 +851,11 @@ At the moment, only
 .Ic none ,
 which disables the announcement of that address family,
 .Ic unicast ,
-and
 .Ic vpn ,
-which allows the distribution of BGP MPLS VPNs, are supported.
+which allows the distribution of BGP MPLS VPNs, and
+.Ic flowspec ,
+which allows the distribution of Flow Specification Rules,
+are supported.
 .Pp
 The default is
 .Ic unicast
Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.469
diff -u -p -r1.469 bgpd.h
--- bgpd.h      29 Mar 2023 14:35:38 -0000      1.469
+++ bgpd.h      3 Apr 2023 08:26:45 -0000
@@ -152,11 +152,13 @@ enum reconf_action {
 #define        AFI_IPv6        2
 
 /* Subsequent Address Family Identifier as per RFC 4760 */
-#define        SAFI_NONE       0
-#define        SAFI_UNICAST    1
-#define        SAFI_MULTICAST  2
-#define        SAFI_MPLS       4
-#define        SAFI_MPLSVPN    128
+#define        SAFI_NONE               0
+#define        SAFI_UNICAST            1
+#define        SAFI_MULTICAST          2
+#define        SAFI_MPLS               4
+#define        SAFI_MPLSVPN            128
+#define        SAFI_FLOWSPEC           133
+#define        SAFI_VPNFLOWSPEC        134
 
 struct aid {
        uint16_t         afi;
@@ -172,7 +174,9 @@ extern const struct aid aid_vals[];
 #define        AID_INET6       2
 #define        AID_VPN_IPv4    3
 #define        AID_VPN_IPv6    4
-#define        AID_MAX         5
+#define        AID_FLOWSPECv4  5
+#define        AID_FLOWSPECv6  6
+#define        AID_MAX         7
 #define        AID_MIN         1       /* skip AID_UNSPEC since that is a 
dummy */
 
 #define AID_VALS       {                                       \
@@ -181,7 +185,9 @@ extern const struct aid aid_vals[];
        { AFI_IPv4, AF_INET, SAFI_UNICAST, "IPv4 unicast" },    \
        { AFI_IPv6, AF_INET6, SAFI_UNICAST, "IPv6 unicast" },   \
        { AFI_IPv4, AF_INET, SAFI_MPLSVPN, "IPv4 vpn" },        \
-       { AFI_IPv6, AF_INET6, SAFI_MPLSVPN, "IPv6 vpn" }        \
+       { AFI_IPv6, AF_INET6, SAFI_MPLSVPN, "IPv6 vpn" },       \
+       { AFI_IPv4, AF_INET, SAFI_FLOWSPEC, "IPv4 flowspec" },  \
+       { AFI_IPv6, AF_INET6, SAFI_FLOWSPEC, "IPv6 flowspec" }, \
 }
 
 #define BGP_MPLS_BOS   0x01
@@ -1004,18 +1010,22 @@ struct filter_peers {
 #define EXT_COMMUNITY_IANA             0x80
 #define EXT_COMMUNITY_NON_TRANSITIVE   0x40
 #define EXT_COMMUNITY_VALUE            0x3f
-/* extended types transitive */
+/* extended transitive types */
 #define EXT_COMMUNITY_TRANS_TWO_AS     0x00    /* 2 octet AS specific */
 #define EXT_COMMUNITY_TRANS_IPV4       0x01    /* IPv4 specific */
 #define EXT_COMMUNITY_TRANS_FOUR_AS    0x02    /* 4 octet AS specific */
 #define EXT_COMMUNITY_TRANS_OPAQUE     0x03    /* opaque ext community */
 #define EXT_COMMUNITY_TRANS_EVPN       0x06    /* EVPN RFC 7432 */
-/* extended types non-transitive */
+/* extended non-transitive types */
 #define EXT_COMMUNITY_NON_TRANS_TWO_AS 0x40    /* 2 octet AS specific */
 #define EXT_COMMUNITY_NON_TRANS_IPV4   0x41    /* IPv4 specific */
 #define EXT_COMMUNITY_NON_TRANS_FOUR_AS        0x42    /* 4 octet AS specific 
*/
 #define EXT_COMMUNITY_NON_TRANS_OPAQUE 0x43    /* opaque ext community */
 #define EXT_COMMUNITY_UNKNOWN          -1
+/* generic transitive types */
+#define EXT_COMMUNITY_GEN_TWO_AS       0x80    /* 2 octet AS specific */
+#define EXT_COMMUNITY_GEN_IPV4         0x81    /* IPv4 specific */
+#define EXT_COMMUNITY_GEN_FOUR_AS      0x82    /* 4 octet AS specific */
 
 /* BGP Origin Validation State Extended Community RFC 8097 */
 #define EXT_COMMUNITY_SUBTYPE_OVS      0
@@ -1063,10 +1073,47 @@ struct ext_comm_pairs {
        { EXT_COMMUNITY_TRANS_EVPN, 0x01, "esi-lab" },          \
        { EXT_COMMUNITY_TRANS_EVPN, 0x02, "esi-rt" },           \
                                                                \
+       { EXT_COMMUNITY_GEN_TWO_AS, 0x06, "flow-rate" },        \
+       { EXT_COMMUNITY_GEN_TWO_AS, 0x0c, "flow-pps" },         \
+       { EXT_COMMUNITY_GEN_TWO_AS, 0x07, "flow-action" },      \
+       { EXT_COMMUNITY_GEN_TWO_AS, 0x08, "flow-rt-redir" },    \
+       { EXT_COMMUNITY_GEN_IPV4,   0x08, "flow-rt-redir" },    \
+       { EXT_COMMUNITY_GEN_FOUR_AS, 0x08, "flow-rt-redir" },   \
+       { EXT_COMMUNITY_GEN_TWO_AS, 0x09, "flow-dscp" },        \
        { 0 }                                                   \
 }
 
 extern const struct ext_comm_pairs iana_ext_comms[];
+
+/* BGP flowspec defines RFC 8955 */
+#define FLOWSPEC_LEN_LIMIT             0xf0
+#define FLOWSPEC_OP_EOL                        0x80
+#define FLOWSPEC_OP_AND                        0x40
+#define FLOWSPEC_OP_LEN_MASK           0x30
+#define FLOWSPEC_OP_LEN_SHIFT          4
+#define FLOWSPEC_OP_LEN(op)                                    \
+       (1 << (((op) & FLOWSPEC_OP_LEN_MASK) >> FLOWSPEC_OP_LEN_SHIFT))
+#define FLOWSPEC_OP_NUM_LT             0x04
+#define FLOWSPEC_OP_NUM_GT             0x02
+#define FLOWSPEC_OP_NUM_EQ             0x01
+#define FLOWSPEC_OP_BIT_NOT            0x02
+#define FLOWSPEC_OP_BIT_MATCH          0x01
+
+#define FLOWSPEC_TYPE_MIN              1
+#define FLOWSPEC_TYPE_DEST             1
+#define FLOWSPEC_TYPE_SOURCE           2
+#define FLOWSPEC_TYPE_PROTO            3
+#define FLOWSPEC_TYPE_PORT             4
+#define FLOWSPEC_TYPE_DST_PORT         5
+#define FLOWSPEC_TYPE_SRC_PORT         6
+#define FLOWSPEC_TYPE_ICMP_TYPE                7
+#define FLOWSPEC_TYPE_ICMP_CODE                8
+#define FLOWSPEC_TYPE_TCP_FLAGS                9
+#define FLOWSPEC_TYPE_PKT_LEN          10
+#define FLOWSPEC_TYPE_DSCP             11
+#define FLOWSPEC_TYPE_FRAG             12
+#define FLOWSPEC_TYPE_FLOW             13
+#define FLOWSPEC_TYPE_MAX              13
 
 struct filter_prefix {
        struct bgpd_addr        addr;
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.442
diff -u -p -r1.442 parse.y
--- parse.y     9 Mar 2023 13:12:19 -0000       1.442
+++ parse.y     3 Apr 2023 08:26:45 -0000
@@ -213,7 +213,7 @@ typedef struct {
 %}
 
 %token AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE FIBPRIORITY RTABLE
-%token NONE UNICAST VPN RD EXPORT EXPORTTRGT IMPORTTRGT DEFAULTROUTE
+%token NONE UNICAST VPN FLOWSPEC RD EXPORT EXPORTTRGT IMPORTTRGT DEFAULTROUTE
 %token RDE RIB EVALUATE IGNORE COMPARE RTR PORT
 %token GROUP NEIGHBOR NETWORK
 %token EBGP IBGP
@@ -1995,6 +1995,7 @@ family            : IPV4  { $$ = AFI_IPv4; }
 safi           : NONE          { $$ = SAFI_NONE; }
                | UNICAST       { $$ = SAFI_UNICAST; }
                | VPN           { $$ = SAFI_MPLSVPN; }
+               | FLOWSPEC      { $$ = SAFI_FLOWSPEC; }
                ;
 
 nettype                : STATIC { $$ = 1; }
@@ -3200,6 +3201,7 @@ lookup(char *s)
                { "ext-community",      EXTCOMMUNITY},
                { "fib-priority",       FIBPRIORITY},
                { "fib-update",         FIBUPDATE},
+               { "flowspec",           FLOWSPEC},
                { "from",               FROM},
                { "group",              GROUP},
                { "holdtime",           HOLDTIME},
Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.598
diff -u -p -r1.598 rde.c
--- rde.c       28 Mar 2023 08:32:42 -0000      1.598
+++ rde.c       3 Apr 2023 08:26:45 -0000
@@ -1474,9 +1474,14 @@ rde_update_dispatch(struct rde_peer *pee
                                        goto done;
                                }
                                break;
+                       case AID_FLOWSPECv4:
+                       case AID_FLOWSPECv6:
+                               /* ignore flowspec for now */
                        default:
                                /* ignore unsupported multiprotocol AF */
-                               break;
+                               mpp += mplen;
+                               mplen = 0;
+                               continue;
                        }
 
                        mpp += pos;
@@ -1674,9 +1679,14 @@ rde_update_dispatch(struct rde_peer *pee
                                        goto done;
                                }
                                break;
+                       case AID_FLOWSPECv4:
+                       case AID_FLOWSPECv6:
+                               /* ignore flowspec for now */
                        default:
                                /* ignore unsupported multiprotocol AF */
-                               break;
+                               mpp += mplen;
+                               mplen = 0;
+                               continue;
                        }
 
                        mpp += pos;
@@ -2314,7 +2324,6 @@ rde_get_mp_nexthop(u_char *data, uint16_
                return (-1);
 
        memset(&nexthop, 0, sizeof(nexthop));
-       nexthop.aid = aid;
        switch (aid) {
        case AID_INET6:
                /*
@@ -2326,19 +2335,11 @@ rde_get_mp_nexthop(u_char *data, uint16_
                 * traffic.
                 */
                if (nhlen != 16 && nhlen != 32) {
-                       log_warnx("bad multiprotocol nexthop, bad size");
-                       return (-1);
-               }
-               memcpy(&nexthop.v6.s6_addr, data, 16);
-               break;
-       case AID_VPN_IPv6:
-               if (nhlen != 24) {
-                       log_warnx("bad multiprotocol nexthop, bad size %d",
+                       log_warnx("bad %s nexthop, bad size %d", aid2str(aid),
                            nhlen);
                        return (-1);
                }
-               memcpy(&nexthop.v6, data + sizeof(uint64_t),
-                   sizeof(nexthop.v6));
+               memcpy(&nexthop.v6.s6_addr, data, 16);
                nexthop.aid = AID_INET6;
                break;
        case AID_VPN_IPv4:
@@ -2356,24 +2357,43 @@ rde_get_mp_nexthop(u_char *data, uint16_
                 * AID_VPN_IPv4 in nexthop and kroute.
                 */
                if (nhlen != 12) {
-                       log_warnx("bad multiprotocol nexthop, bad size");
+                       log_warnx("bad %s nexthop, bad size %d", aid2str(aid),
+                           nhlen);
                        return (-1);
                }
                nexthop.aid = AID_INET;
                memcpy(&nexthop.v4, data + sizeof(uint64_t),
                    sizeof(nexthop.v4));
                break;
+       case AID_VPN_IPv6:
+               if (nhlen != 24) {
+                       log_warnx("bad %s nexthop, bad size %d", aid2str(aid),
+                           nhlen);
+                       return (-1);
+               }
+               memcpy(&nexthop.v6, data + sizeof(uint64_t),
+                   sizeof(nexthop.v6));
+               nexthop.aid = AID_INET6;
+               break;
+       case AID_FLOWSPECv4:
+       case AID_FLOWSPECv6:
+               /* nexthop must be 0 and ignored for flowspec */
+               if (nhlen != 0) {
+                       log_warnx("bad %s nexthop, bad size %d", aid2str(aid),
+                           nhlen);
+                       return (-1);
+               }
+               totlen += nhlen + 1;
+               return (totlen);
        default:
                log_warnx("bad multiprotocol nexthop, bad AID");
                return (-1);
        }
 
-       nexthop_unref(state->nexthop);  /* just to be sure */
        state->nexthop = nexthop_get(&nexthop);
 
        /* ignore reserved (old SNPA) field as per RFC4760 */
        totlen += nhlen + 1;
-       data += nhlen + 1;
 
        return (totlen);
 }
Index: util.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/util.c,v
retrieving revision 1.75
diff -u -p -r1.75 util.c
--- util.c      30 Mar 2023 14:47:25 -0000      1.75
+++ util.c      3 Apr 2023 08:26:45 -0000
@@ -918,6 +918,9 @@ addr2sa(const struct bgpd_addr *addr, ui
                sa_in6->sin6_scope_id = addr->scope_id;
                *len = sizeof(struct sockaddr_in6);
                break;
+       case AID_FLOWSPECv4:
+       case AID_FLOWSPECv6:
+               return (NULL);
        }
 
        return ((struct sockaddr *)&ss);

Reply via email to