--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 */