]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: add flowspec utilities to decode, convert fs nlri
authorPhilippe Guibert <philippe.guibert@6wind.com>
Wed, 14 Feb 2018 10:13:50 +0000 (11:13 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 30 Mar 2018 12:00:47 +0000 (14:00 +0200)
The FS nlri is depicted so as to be able to be in readable format,
either by human, or by some other ( remote daemon ?).
This work is a derived work from [0]. Initially done for validation
only, this work is extended.
The FS NLRI is able to decode addresses, numbers ( protocols, ports,
tcp values) combined ( or not) with operators. This makes possible
to have a NLRI entry for a set of ports, and/or for an other set of
value of port.
This implementation mainly brings the API visible. The API should be
consistent across the various usages.

[0] https://github.com/chinatelecom-sdn-group/quagga_flowspec/

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
Signed-off-by: jaydom <chinatelecom-sdn-group@github.com>
bgpd/Makefile.am
bgpd/bgp_flowspec_util.c [new file with mode: 0644]
bgpd/bgp_flowspec_util.h [new file with mode: 0644]

index 84b3e0183c567469e633bd115af647f4ad383109..a8e50e0ba78de36007bb123c36740f76ade6844f 100644 (file)
@@ -86,7 +86,7 @@ libbgp_a_SOURCES = \
        bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \
        bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \
        bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c bgp_rd.c \
-       bgp_keepalives.c bgp_io.c bgp_flowspec.c
+       bgp_keepalives.c bgp_io.c bgp_flowspec.c bgp_flowspec_util.c
 
 noinst_HEADERS = \
        bgp_memory.h \
@@ -99,7 +99,7 @@ noinst_HEADERS = \
        bgp_updgrp.h bgp_bfd.h bgp_encap_tlv.h bgp_encap_types.h \
        $(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \
         bgp_vpn.h bgp_label.h bgp_rd.h bgp_evpn_private.h bgp_keepalives.h \
-       bgp_io.h bgp_flowspec.h bgp_flowspec_private.h
+       bgp_io.h bgp_flowspec.h bgp_flowspec_private.h bgp_flowspec_util.h
 
 bgpd_SOURCES = bgp_main.c
 bgpd_LDADD = libbgp.a  $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@
diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c
new file mode 100644 (file)
index 0000000..6b7a3d0
--- /dev/null
@@ -0,0 +1,290 @@
+/* BGP FlowSpec Utilities
+ * Portions:
+ *     Copyright (C) 2017 ChinaTelecom SDN Group
+ *     Copyright (C) 2018 6WIND
+ *
+ * FRRouting is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRRouting is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "zebra.h"
+
+#include "prefix.h"
+#include "bgp_flowspec_util.h"
+
+static void hex2bin(uint8_t *hex, int *bin)
+{
+       int remainder = *hex;
+       int i = 0;
+
+       while (remainder >= 1 && i < 8) {
+               bin[7-i] = remainder % 2;
+               remainder = remainder / 2;
+               i++;
+       }
+       for (; i < 8; i++)
+               bin[7-i] = 0;
+}
+
+static int hexstr2num(uint8_t *hexstr, int len)
+{
+       int i = 0;
+       int num = 0;
+
+       for (i = 0; i < len; i++)
+               num = hexstr[i] + 16*16*num;
+       return num;
+}
+
+
+/*
+ * handle the flowspec address src/dst or generic address NLRI
+ * return number of bytes analysed ( >= 0).
+ */
+int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
+                           uint8_t *nlri_ptr,
+                           uint32_t max_len,
+                           void *result, int *error)
+{
+       char *display = (char *)result; /* for return_string */
+       struct prefix *prefix = (struct prefix *)result;
+       uint32_t offset = 0;
+       struct prefix prefix_local;
+       int psize;
+
+       *error = 0;
+       memset(&prefix_local, 0, sizeof(struct prefix));
+       /* read the prefix length */
+       prefix_local.prefixlen = nlri_ptr[offset];
+       psize = PSIZE(prefix_local.prefixlen);
+       offset++;
+       /* TODO Flowspec IPv6 Support */
+       prefix_local.family = AF_INET;
+       /* Prefix length check. */
+       if (prefix_local.prefixlen > prefix_blen(&prefix_local) * 8)
+               *error = -1;
+       /* When packet overflow occur return immediately. */
+       if (psize + offset > max_len)
+               *error = -1;
+       /* Defensive coding, double-check
+        * the psize fits in a struct prefix
+        */
+       if (psize > (ssize_t)sizeof(prefix_local.u))
+               *error = -1;
+       memcpy(&prefix_local.u.prefix, &nlri_ptr[offset], psize);
+       offset += psize;
+       switch (type) {
+       case BGP_FLOWSPEC_RETURN_STRING:
+               prefix2str(&prefix_local, display,
+                          BGP_FLOWSPEC_STRING_DISPLAY_MAX);
+               break;
+       case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
+               PREFIX_COPY_IPV4(prefix, &prefix_local)
+               break;
+       case BGP_FLOWSPEC_VALIDATE_ONLY:
+       default:
+               break;
+       }
+       return offset;
+}
+
+/*
+ * handle the flowspec operator NLRI
+ * return number of bytes analysed
+ * if there is an error, the passed error param is used to give error:
+ * -1 if decoding error,
+ */
+int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
+                          uint8_t *nlri_ptr,
+                          uint32_t max_len,
+                          void *result, int *error)
+{
+       int op[8];
+       int len, value, value_size;
+       int loop = 0;
+       char *ptr = (char *)result; /* for return_string */
+       uint32_t offset = 0;
+
+       *error = 0;
+       do {
+               hex2bin(&nlri_ptr[offset], op);
+               offset++;
+               len = 2*op[2]+op[3];
+               value_size = 1 << len;
+               value = hexstr2num(&nlri_ptr[offset], value_size);
+               /* can not be < and > at the same time */
+               if (op[5] == 1 && op[6] == 1)
+                       *error = -1;
+               /* if first element, AND bit can not be set */
+               if (op[1] == 1 && loop == 0)
+                       *error = -1;
+               switch (type) {
+               case BGP_FLOWSPEC_RETURN_STRING:
+                       if (loop)
+                               ptr += sprintf(ptr, ", ");
+                       if (op[5] == 1)
+                               ptr += sprintf(ptr, "<");
+                       if (op[6] == 1)
+                               ptr += sprintf(ptr, ">");
+                       if (op[7] == 1)
+                               ptr += sprintf(ptr, "=");
+                       ptr += sprintf(ptr, " %d ", value);
+                       break;
+               case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
+                       /* TODO : FS OPAQUE */
+                       break;
+               case BGP_FLOWSPEC_VALIDATE_ONLY:
+               default:
+                       /* no action */
+                       break;
+               }
+               offset += value_size;
+               loop++;
+       } while (op[0] == 0 && offset < max_len - 1);
+       if (offset > max_len)
+               *error = -1;
+       /* use error parameter to count the number of entries */
+       if (*error == 0)
+               *error = loop;
+       return offset;
+}
+
+
+/*
+ * handle the flowspec tcpflags field
+ * return number of bytes analysed
+ * if there is an error, the passed error param is used to give error:
+ * -1 if decoding error,
+ */
+int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
+                                uint8_t *nlri_ptr,
+                                uint32_t max_len,
+                                void *result, int *error)
+{
+       int op[8];
+       int len, value_size, loop = 0, value;
+       char *ptr = (char *)result; /* for return_string */
+       uint32_t offset = 0;
+
+       *error = 0;
+       do {
+               hex2bin(&nlri_ptr[offset], op);
+               /* if first element, AND bit can not be set */
+               if (op[1] == 1 && loop == 0)
+                       *error = -1;
+               offset++;
+               len = 2 * op[2] + op[3];
+               value_size = 1 << len;
+               value = hexstr2num(&nlri_ptr[offset], value_size);
+               switch (type) {
+               case BGP_FLOWSPEC_RETURN_STRING:
+                       if (op[1] == 1 && loop != 0)
+                               ptr += sprintf(ptr, ", and ");
+                       else if (op[1] == 0 && loop != 0)
+                               ptr += sprintf(ptr, ", or ");
+                       ptr += sprintf(ptr, "tcp flags is ");
+                       if (op[6] == 1)
+                               ptr += sprintf(ptr, "not ");
+                       if (op[7] == 1)
+                               ptr += sprintf(ptr, "exactly match ");
+                       ptr += sprintf(ptr, "%d", value);
+                       break;
+               case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
+                       /* TODO : FS OPAQUE */
+                       break;
+               case BGP_FLOWSPEC_VALIDATE_ONLY:
+               default:
+                       /* no action */
+                       break;
+               }
+               offset += value_size;
+               loop++;
+       } while (op[0] == 0 && offset < max_len - 1);
+       if (offset > max_len)
+               *error = -1;
+       /* use error parameter to count the number of entries */
+       if (*error == 0)
+               *error = loop;
+       return offset;
+}
+
+/*
+ * handle the flowspec fragment type field
+ * return error (returned values are invalid) or number of bytes analysed
+ * -1 if error in decoding
+ * >= 0 : number of bytes analysed (ok).
+ */
+int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
+                                     uint8_t *nlri_ptr,
+                                     uint32_t max_len,
+                                     void *result, int *error)
+{
+       int op[8];
+       int len, value, value_size, loop = 0;
+       char *ptr = (char *)result; /* for return_string */
+       uint32_t offset = 0;
+
+       *error = 0;
+       do {
+               hex2bin(&nlri_ptr[offset], op);
+               offset++;
+               len = 2 * op[2] + op[3];
+               value_size = 1 << len;
+               value = hexstr2num(&nlri_ptr[offset], value_size);
+               if (value != 1 && value != 2 && value != 4 && value != 8)
+                       *error = -1;
+               offset += value_size;
+               /* TODO : as per RFC5574 : first Fragment bits are Reserved
+                * does that mean that it is not possible
+                * to handle multiple occurences ?
+                * as of today, we only grab the first TCP fragment
+                */
+               if (loop) {
+                       *error = -2;
+                       loop++;
+                       continue;
+               }
+               switch (type) {
+               case BGP_FLOWSPEC_RETURN_STRING:
+                       switch (value) {
+                       case 1:
+                               ptr += sprintf(ptr, "dont-fragment");
+                               break;
+                       case 2:
+                               ptr += sprintf(ptr, "is-fragment");
+                               break;
+                       case 4:
+                               ptr += sprintf(ptr, "first-fragment");
+                               break;
+                       case 8:
+                               ptr += sprintf(ptr, "last-fragment");
+                               break;
+                       default:
+                               {}
+                       }
+                       break;
+               case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
+                       /* TODO : FS OPAQUE */
+                       break;
+               case BGP_FLOWSPEC_VALIDATE_ONLY:
+               default:
+                       /* no action */
+                       break;
+               }
+               loop++;
+       } while (op[0] == 0 && offset < max_len - 1);
+       if (offset > max_len)
+               *error = -1;
+       return offset;
+}
diff --git a/bgpd/bgp_flowspec_util.h b/bgpd/bgp_flowspec_util.h
new file mode 100644 (file)
index 0000000..55a464a
--- /dev/null
@@ -0,0 +1,53 @@
+/* BGP Flowspec header for utilities
+ * Copyright (C) 2018 6WIND
+ *
+ * FRRouting is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRRouting is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_BGP_FLOWSPEC_UTIL_H
+#define _FRR_BGP_FLOWSPEC_UTIL_H
+
+#include "zclient.h"
+
+#define BGP_FLOWSPEC_STRING_DISPLAY_MAX 512
+
+enum bgp_flowspec_util_nlri_t {
+       BGP_FLOWSPEC_VALIDATE_ONLY = 0,
+       BGP_FLOWSPEC_RETURN_STRING = 1,
+       BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE = 2
+};
+
+
+extern int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
+                                 uint8_t *nlri_ptr,
+                                 uint32_t max_len,
+                                 void *result, int *error);
+
+extern int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
+                                  uint8_t *nlri_ptr,
+                                  uint32_t max_len,
+                                  void *result, int *error);
+
+extern int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
+                                       uint8_t *nlri_ptr,
+                                       uint32_t max_len,
+                                       void *result, int *error);
+
+extern int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
+                                            uint8_t *nlri_ptr,
+                                            uint32_t max_len,
+                                            void *result, int *error);
+
+#endif /* _FRR_BGP_FLOWSPEC_UTIL_H */