]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_flowspec_util.c
Merge pull request #2372 from gromit1811/pim-comment-fix
[mirror_frr.git] / bgpd / bgp_flowspec_util.c
index 7391a7b80aeb60bf0db06f84765c8e838d353239..956cf28c211dfc2df74f0a0bada96ccaac4acad3 100644 (file)
@@ -25,6 +25,7 @@
 #include "bgp_table.h"
 #include "bgp_flowspec_util.h"
 #include "bgp_flowspec_private.h"
+#include "bgp_pbr.h"
 
 static void hex2bin(uint8_t *hex, int *bin)
 {
@@ -50,6 +51,109 @@ static int hexstr2num(uint8_t *hexstr, int len)
        return num;
 }
 
+/* call bgp_flowspec_op_decode
+ * returns offset
+ */
+static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content, int len,
+                                              struct bgp_pbr_match_val *mval,
+                                              uint8_t *match_num, int *error)
+{
+       int ret;
+
+       ret = bgp_flowspec_op_decode(
+                            BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
+                            nlri_content,
+                            len,
+                            mval, error);
+       if (*error < 0)
+               zlog_err("%s: flowspec_op_decode error %d",
+                        __func__, *error);
+       else
+               *match_num = *error;
+       return ret;
+}
+
+static bool bgp_flowspec_contains_prefix(struct prefix *pfs,
+                                        struct prefix *input,
+                                        int prefix_check)
+{
+       uint32_t offset = 0;
+       int type;
+       int ret = 0, error = 0;
+       uint8_t *nlri_content = (uint8_t *)pfs->u.prefix_flowspec.ptr;
+       size_t len = pfs->u.prefix_flowspec.prefixlen;
+       struct prefix compare;
+
+       error = 0;
+       while (offset < len-1 && error >= 0) {
+               type = nlri_content[offset];
+               offset++;
+               switch (type) {
+               case FLOWSPEC_DEST_PREFIX:
+               case FLOWSPEC_SRC_PREFIX:
+                       memset(&compare, 0, sizeof(struct prefix));
+                       ret = bgp_flowspec_ip_address(
+                                       BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
+                                       nlri_content+offset,
+                                       len - offset,
+                                       &compare, &error);
+                       if (ret <= 0)
+                               break;
+                       if (prefix_check &&
+                           compare.prefixlen != input->prefixlen)
+                               break;
+                       if (compare.family != input->family)
+                               break;
+                       if ((input->family == AF_INET) &&
+                           IPV4_ADDR_SAME(&input->u.prefix4,
+                                          &compare.u.prefix4))
+                               return true;
+                       if ((input->family == AF_INET6) &&
+                           IPV6_ADDR_SAME(&input->u.prefix6.s6_addr,
+                                          &compare.u.prefix6.s6_addr))
+                               return true;
+                       break;
+               case FLOWSPEC_IP_PROTOCOL:
+               case FLOWSPEC_PORT:
+               case FLOWSPEC_DEST_PORT:
+               case FLOWSPEC_SRC_PORT:
+               case FLOWSPEC_ICMP_TYPE:
+               case FLOWSPEC_ICMP_CODE:
+                       ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY,
+                                                    nlri_content+offset,
+                                                    len - offset,
+                                                    NULL, &error);
+                       break;
+               case FLOWSPEC_TCP_FLAGS:
+                       ret = bgp_flowspec_tcpflags_decode(
+                                               BGP_FLOWSPEC_VALIDATE_ONLY,
+                                               nlri_content+offset,
+                                               len - offset,
+                                               NULL, &error);
+                       break;
+               case FLOWSPEC_PKT_LEN:
+               case FLOWSPEC_DSCP:
+                       ret = bgp_flowspec_op_decode(
+                                               BGP_FLOWSPEC_VALIDATE_ONLY,
+                                               nlri_content + offset,
+                                               len - offset, NULL,
+                                               &error);
+                       break;
+               case FLOWSPEC_FRAGMENT:
+                       ret = bgp_flowspec_fragment_type_decode(
+                                               BGP_FLOWSPEC_VALIDATE_ONLY,
+                                               nlri_content + offset,
+                                               len - offset, NULL,
+                                               &error);
+                       break;
+               default:
+                       error = -1;
+                       break;
+               }
+               offset += ret;
+       }
+       return false;
+}
 
 /*
  * handle the flowspec address src/dst or generic address NLRI
@@ -107,6 +211,8 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
  * return number of bytes analysed
  * if there is an error, the passed error param is used to give error:
  * -1 if decoding error,
+ * if result is a string, its assumed length
+ *  is BGP_FLOWSPEC_STRING_DISPLAY_MAX
  */
 int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
                           uint8_t *nlri_ptr,
@@ -118,9 +224,14 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
        int loop = 0;
        char *ptr = (char *)result; /* for return_string */
        uint32_t offset = 0;
+       int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
+       int len_written;
+       struct bgp_pbr_match_val *mval = (struct bgp_pbr_match_val *)result;
 
        *error = 0;
        do {
+               if (loop > BGP_PBR_MATCH_VAL_MAX)
+                       *error = -2;
                hex2bin(&nlri_ptr[offset], op);
                offset++;
                len = 2*op[2]+op[3];
@@ -134,18 +245,54 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
                        *error = -1;
                switch (type) {
                case BGP_FLOWSPEC_RETURN_STRING:
-                       if (loop)
-                               ptr += sprintf(ptr, ", ");
+                       if (loop) {
+                               len_written = snprintf(ptr, len_string,
+                                                     ", ");
+                               len_string -= len_written;
+                               ptr += len_written;
+                       }
+                       if (op[5] == 1) {
+                               len_written = snprintf(ptr, len_string,
+                                                      "<");
+                               len_string -= len_written;
+                               ptr += len_written;
+                       }
+                       if (op[6] == 1) {
+                               len_written = snprintf(ptr, len_string,
+                                                     ">");
+                               len_string -= len_written;
+                               ptr += len_written;
+                       }
+                       if (op[7] == 1) {
+                               len_written = snprintf(ptr, len_string,
+                                                      "=");
+                               len_string -= len_written;
+                               ptr += len_written;
+                       }
+                       len_written = snprintf(ptr, len_string,
+                                              " %d ", value);
+                       len_string -= len_written;
+                       ptr += len_written;
+                       break;
+               case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
+                       /* limitation: stop converting */
+                       if (*error == -2)
+                               break;
+                       mval->value = value;
                        if (op[5] == 1)
-                               ptr += sprintf(ptr, "<");
+                               mval->compare_operator |=
+                                       OPERATOR_COMPARE_LESS_THAN;
                        if (op[6] == 1)
-                               ptr += sprintf(ptr, ">");
+                               mval->compare_operator |=
+                                       OPERATOR_COMPARE_GREATER_THAN;
                        if (op[7] == 1)
-                               ptr += sprintf(ptr, "=");
-                       ptr += sprintf(ptr, " %d ", value);
-                       break;
-               case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
-                       /* TODO : FS OPAQUE */
+                               mval->compare_operator |=
+                                       OPERATOR_COMPARE_EQUAL_TO;
+                       if (op[1] == 1)
+                               mval->unary_operator = OPERATOR_UNARY_AND;
+                       else
+                               mval->unary_operator = OPERATOR_UNARY_OR;
+                       mval++;
                        break;
                case BGP_FLOWSPEC_VALIDATE_ONLY:
                default:
@@ -169,6 +316,8 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
  * return number of bytes analysed
  * if there is an error, the passed error param is used to give error:
  * -1 if decoding error,
+ * if result is a string, its assumed length
+ *  is BGP_FLOWSPEC_STRING_DISPLAY_MAX
  */
 int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
                                 uint8_t *nlri_ptr,
@@ -178,10 +327,15 @@ int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
        int op[8];
        int len, value_size, loop = 0, value;
        char *ptr = (char *)result; /* for return_string */
+       struct bgp_pbr_match_val *mval = (struct bgp_pbr_match_val *)result;
        uint32_t offset = 0;
+       int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
+       int len_written;
 
        *error = 0;
        do {
+               if (loop > BGP_PBR_MATCH_VAL_MAX)
+                       *error = -2;
                hex2bin(&nlri_ptr[offset], op);
                /* if first element, AND bit can not be set */
                if (op[1] == 1 && loop == 0)
@@ -192,19 +346,62 @@ int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
                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);
+                       if (op[1] == 1 && loop != 0) {
+                               len_written = snprintf(ptr, len_string,
+                                                      ", and ");
+                               len_string -= len_written;
+                               ptr += len_written;
+                       } else if (op[1] == 0 && loop != 0) {
+                               len_written = snprintf(ptr, len_string,
+                                                     ", or ");
+                               len_string -= len_written;
+                               ptr += len_written;
+                       }
+                       len_written = snprintf(ptr, len_string,
+                                              "tcp flags is ");
+                       len_string -= len_written;
+                       ptr += len_written;
+                       if (op[6] == 1) {
+                               ptr += snprintf(ptr, len_string,
+                                              "not ");
+                               len_string -= len_written;
+                               ptr += len_written;
+                       }
+                       if (op[7] == 1) {
+                               ptr += snprintf(ptr, len_string,
+                                              "exactly match ");
+                               len_string -= len_written;
+                               ptr += len_written;
+                       }
+                       ptr += snprintf(ptr, len_string,
+                                      "%d", value);
+                       len_string -= len_written;
+                       ptr += len_written;
                        break;
                case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
-                       /* TODO : FS OPAQUE */
+                       /* limitation: stop converting */
+                       if (*error == -2)
+                               break;
+                       mval->value = value;
+                       if (op[6] == 1) {
+                               /* different from */
+                               mval->compare_operator |=
+                                       OPERATOR_COMPARE_LESS_THAN;
+                               mval->compare_operator |=
+                                       OPERATOR_COMPARE_GREATER_THAN;
+                       } else
+                               mval->compare_operator |=
+                                       OPERATOR_COMPARE_EQUAL_TO;
+                       if (op[7] == 1)
+                               mval->compare_operator |=
+                                       OPERATOR_COMPARE_EXACT_MATCH;
+                       if (op[1] == 1)
+                               mval->unary_operator =
+                                       OPERATOR_UNARY_AND;
+                       else
+                               mval->unary_operator =
+                                       OPERATOR_UNARY_OR;
+                       mval++;
                        break;
                case BGP_FLOWSPEC_VALIDATE_ONLY:
                default:
@@ -236,7 +433,11 @@ int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
        int op[8];
        int len, value, value_size, loop = 0;
        char *ptr = (char *)result; /* for return_string */
+       struct bgp_pbr_fragment_val *mval =
+               (struct bgp_pbr_fragment_val *)result;
        uint32_t offset = 0;
+       int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
+       int len_written;
 
        *error = 0;
        do {
@@ -262,23 +463,35 @@ int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
                case BGP_FLOWSPEC_RETURN_STRING:
                        switch (value) {
                        case 1:
-                               ptr += sprintf(ptr, "dont-fragment");
+                               len_written = snprintf(ptr, len_string,
+                                                      "dont-fragment");
+                               len_string -= len_written;
+                               ptr += len_written;
                                break;
                        case 2:
-                               ptr += sprintf(ptr, "is-fragment");
+                               len_written = snprintf(ptr, len_string,
+                                                     "is-fragment");
+                               len_string -= len_written;
+                               ptr += len_written;
                                break;
                        case 4:
-                               ptr += sprintf(ptr, "first-fragment");
+                               len_written = snprintf(ptr, len_string,
+                                                      "first-fragment");
+                               len_string -= len_written;
+                               ptr += len_written;
                                break;
                        case 8:
-                               ptr += sprintf(ptr, "last-fragment");
+                               len_written = snprintf(ptr, len_string,
+                                                      "last-fragment");
+                               len_string -= len_written;
+                               ptr += len_written;
                                break;
                        default:
                                {}
                        }
                        break;
                case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
-                       /* TODO : FS OPAQUE */
+                       mval->bitmask = (uint8_t)value;
                        break;
                case BGP_FLOWSPEC_VALIDATE_ONLY:
                default:
@@ -292,89 +505,158 @@ int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
        return offset;
 }
 
-
-static bool bgp_flowspec_contains_prefix(struct prefix *pfs,
-                                        struct prefix *input,
-                                        int prefix_check)
+int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
+                                 struct bgp_pbr_entry_main *bpem)
 {
-       uint32_t offset = 0;
-       int type;
-       int ret = 0, error = 0;
-       uint8_t *nlri_content = (uint8_t *)pfs->u.prefix_flowspec.ptr;
-       size_t len = pfs->u.prefix_flowspec.prefixlen;
-       struct prefix compare;
+       int offset = 0, error = 0;
+       struct prefix *prefix;
+       struct bgp_pbr_match_val *mval;
+       uint8_t *match_num;
+       uint8_t bitmask = 0;
+       int ret = 0, type;
 
-       error = 0;
-       while (offset < len-1 && error >= 0) {
+       while (offset < len - 1 && error >= 0) {
                type = nlri_content[offset];
                offset++;
                switch (type) {
                case FLOWSPEC_DEST_PREFIX:
                case FLOWSPEC_SRC_PREFIX:
-                       memset(&compare, 0, sizeof(struct prefix));
+                       bitmask = 0;
+                       if (type == FLOWSPEC_DEST_PREFIX) {
+                               bitmask |= PREFIX_DST_PRESENT;
+                               prefix = &bpem->dst_prefix;
+                       } else {
+                               bitmask |= PREFIX_SRC_PRESENT;
+                               prefix = &bpem->src_prefix;
+                       }
                        ret = bgp_flowspec_ip_address(
                                        BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
-                                       nlri_content+offset,
+                                       nlri_content + offset,
                                        len - offset,
-                                       &compare, &error);
-                       if (ret <= 0)
-                               break;
-                       if (prefix_check &&
-                           compare.prefixlen != input->prefixlen)
-                               break;
-                       if (compare.family != input->family)
-                               break;
-                       if ((input->family == AF_INET) &&
-                           IPV4_ADDR_SAME(&input->u.prefix4,
-                                          &compare.u.prefix4))
-                               return true;
-                       if ((input->family == AF_INET6) &&
-                           IPV6_ADDR_SAME(&input->u.prefix6.s6_addr,
-                                          &compare.u.prefix6.s6_addr))
-                               return true;
+                                       prefix, &error);
+                       if (error < 0)
+                               zlog_err("%s: flowspec_ip_address error %d",
+                                        __func__, error);
+                       else
+                               bpem->match_bitmask |= bitmask;
+                       offset += ret;
                        break;
                case FLOWSPEC_IP_PROTOCOL:
+                       match_num = &(bpem->match_protocol_num);
+                       mval = (struct bgp_pbr_match_val *)
+                               &(bpem->protocol);
+                       offset += bgp_flowspec_call_non_opaque_decode(
+                                                       nlri_content + offset,
+                                                       len - offset,
+                                                       mval, match_num,
+                                                       &error);
+                       break;
                case FLOWSPEC_PORT:
+                       match_num = &(bpem->match_port_num);
+                       mval = (struct bgp_pbr_match_val *)
+                               &(bpem->port);
+                       offset += bgp_flowspec_call_non_opaque_decode(
+                                                       nlri_content + offset,
+                                                       len - offset,
+                                                       mval, match_num,
+                                                       &error);
+                       break;
                case FLOWSPEC_DEST_PORT:
+                       match_num = &(bpem->match_dst_port_num);
+                       mval = (struct bgp_pbr_match_val *)
+                               &(bpem->dst_port);
+                       offset += bgp_flowspec_call_non_opaque_decode(
+                                                       nlri_content + offset,
+                                                       len - offset,
+                                                       mval, match_num,
+                                                       &error);
+                       break;
                case FLOWSPEC_SRC_PORT:
+                       match_num = &(bpem->match_src_port_num);
+                       mval = (struct bgp_pbr_match_val *)
+                               &(bpem->src_port);
+                       offset += bgp_flowspec_call_non_opaque_decode(
+                                                       nlri_content + offset,
+                                                       len - offset,
+                                                       mval, match_num,
+                                                       &error);
+                       break;
                case FLOWSPEC_ICMP_TYPE:
-               case FLOWSPEC_ICMP_CODE:
-                       ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY,
-                                                    nlri_content+offset,
-                                                    len - offset,
-                                                    NULL, &error);
+                       match_num = &(bpem->match_icmp_type_num);
+                       mval = (struct bgp_pbr_match_val *)
+                               &(bpem->icmp_type);
+                       offset += bgp_flowspec_call_non_opaque_decode(
+                                                       nlri_content + offset,
+                                                       len - offset,
+                                                       mval, match_num,
+                                                       &error);
                        break;
-               case FLOWSPEC_TCP_FLAGS:
-                       ret = bgp_flowspec_tcpflags_decode(
-                                               BGP_FLOWSPEC_VALIDATE_ONLY,
-                                               nlri_content+offset,
-                                               len - offset,
-                                               NULL, &error);
+               case FLOWSPEC_ICMP_CODE:
+                       match_num = &(bpem->match_icmp_code_num);
+                       mval = (struct bgp_pbr_match_val *)
+                               &(bpem->icmp_code);
+                       offset += bgp_flowspec_call_non_opaque_decode(
+                                                       nlri_content + offset,
+                                                       len - offset,
+                                                       mval, match_num,
+                                                       &error);
                        break;
                case FLOWSPEC_PKT_LEN:
+                       match_num =
+                               &(bpem->match_packet_length_num);
+                       mval = (struct bgp_pbr_match_val *)
+                               &(bpem->packet_length);
+                       offset += bgp_flowspec_call_non_opaque_decode(
+                                                       nlri_content + offset,
+                                                       len - offset,
+                                                       mval, match_num,
+                                                       &error);
+                       break;
                case FLOWSPEC_DSCP:
-                       ret = bgp_flowspec_op_decode(
-                                               BGP_FLOWSPEC_VALIDATE_ONLY,
-                                               nlri_content + offset,
-                                               len - offset, NULL,
-                                               &error);
+                       match_num = &(bpem->match_dscp_num);
+                       mval = (struct bgp_pbr_match_val *)
+                               &(bpem->dscp);
+                       offset += bgp_flowspec_call_non_opaque_decode(
+                                                       nlri_content + offset,
+                                                       len - offset,
+                                                       mval, match_num,
+                                                       &error);
+                       break;
+               case FLOWSPEC_TCP_FLAGS:
+                       ret = bgp_flowspec_tcpflags_decode(
+                                       BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
+                                       nlri_content + offset,
+                                       len - offset,
+                                       &bpem->tcpflags, &error);
+                       if (error < 0)
+                               zlog_err("%s: flowspec_tcpflags_decode error %d",
+                                        __func__, error);
+                       else
+                               bpem->match_tcpflags_num = error;
+                       /* contains the number of slots used */
+                       offset += ret;
                        break;
                case FLOWSPEC_FRAGMENT:
                        ret = bgp_flowspec_fragment_type_decode(
-                                               BGP_FLOWSPEC_VALIDATE_ONLY,
-                                               nlri_content + offset,
-                                               len - offset, NULL,
-                                               &error);
+                                       BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
+                                       nlri_content + offset,
+                                       len - offset, &bpem->fragment,
+                                       &error);
+                       if (error < 0)
+                               zlog_err("%s: flowspec_fragment_type_decode error %d",
+                                        __func__, error);
+                       else
+                               bpem->match_bitmask |= FRAGMENT_PRESENT;
+                       offset += ret;
                        break;
                default:
-                       error = -1;
-                       break;
+                       zlog_err("%s: unknown type %d\n", __func__, type);
                }
-               offset += ret;
        }
-       return false;
+       return error;
 }
 
+
 struct bgp_node *bgp_flowspec_get_match_per_ip(afi_t afi,
                                               struct bgp_table *rib,
                                               struct prefix *match,