]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_flowspec_util.c
Merge pull request #3502 from donaldsharp/socket_to_me_baby
[mirror_frr.git] / bgpd / bgp_flowspec_util.c
index 007b27f17ea3caa4330b47d039d89ddccc1b86e8..c6386dcdb56df55dab52f963dbfe97d9b565b28f 100644 (file)
 #include "zebra.h"
 
 #include "prefix.h"
+#include "lib_errors.h"
 
 #include "bgp_table.h"
 #include "bgp_flowspec_util.h"
 #include "bgp_flowspec_private.h"
+#include "bgp_pbr.h"
+#include "bgp_errors.h"
 
 static void hex2bin(uint8_t *hex, int *bin)
 {
@@ -50,6 +53,103 @@ 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)
+               flog_err(EC_BGP_FLOWSPEC_PACKET,
+                        "%s: flowspec_op_decode error %d", __func__, *error);
+       else
+               *match_num = *error;
+       return ret;
+}
+
+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_FRAGMENT:
+               case FLOWSPEC_TCP_FLAGS:
+                       ret = bgp_flowspec_bitmask_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;
+               default:
+                       error = -1;
+                       break;
+               }
+               offset += ret;
+       }
+       return false;
+}
 
 /*
  * handle the flowspec address src/dst or generic address NLRI
@@ -122,9 +222,12 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
        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];
@@ -168,7 +271,24 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
                        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[5] == 1)
+                               mval->compare_operator |=
+                                       OPERATOR_COMPARE_LESS_THAN;
+                       if (op[6] == 1)
+                               mval->compare_operator |=
+                                       OPERATOR_COMPARE_GREATER_THAN;
+                       if (op[7] == 1)
+                               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:
@@ -188,14 +308,14 @@ int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
 
 
 /*
- * handle the flowspec tcpflags field
+ * handle the flowspec tcpflags or fragment field
  * 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,
+int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
                                 uint8_t *nlri_ptr,
                                 uint32_t max_len,
                                 void *result, int *error)
@@ -203,12 +323,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)
@@ -221,38 +344,61 @@ int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
                case BGP_FLOWSPEC_RETURN_STRING:
                        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 ");
+                       if (op[7] == 1) {
+                               len_written = snprintf(ptr, len_string,
+                                              "= ");
+                               len_string -= len_written;
+                               ptr += len_written;
+                       } else {
+                               len_written = snprintf(ptr, len_string,
+                                                      "∋ ");
                                len_string -= len_written;
                                ptr += len_written;
                        }
-                       if (op[7] == 1) {
-                               ptr += snprintf(ptr, len_string,
-                                              "exactly match ");
+                       if (op[6] == 1) {
+                               len_written = snprintf(ptr, len_string,
+                                              "! ");
                                len_string -= len_written;
                                ptr += len_written;
                        }
-                       ptr += snprintf(ptr, len_string,
+                       len_written = 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:
@@ -270,189 +416,168 @@ int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
        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;
-       int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
-       int len_written;
-
-       *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:
-                               len_written = snprintf(ptr, len_string,
-                                                      "dont-fragment");
-                               len_string -= len_written;
-                               ptr += len_written;
-                               break;
-                       case 2:
-                               len_written = snprintf(ptr, len_string,
-                                                     "is-fragment");
-                               len_string -= len_written;
-                               ptr += len_written;
-                               break;
-                       case 4:
-                               len_written = snprintf(ptr, len_string,
-                                                      "first-fragment");
-                               len_string -= len_written;
-                               ptr += len_written;
-                               break;
-                       case 8:
-                               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 */
-                       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;
-}
-
-
-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)
+                               flog_err(EC_BGP_FLOWSPEC_PACKET,
+                                        "%s: flowspec_ip_address error %d",
+                                        __func__, error);
+                       else {
+                               /* if src or dst address is 0.0.0.0,
+                                * ignore that rule
+                                */
+                               if (prefix->family == AF_INET
+                                   && prefix->u.prefix4.s_addr == 0)
+                                       memset(prefix, 0,
+                                              sizeof(struct prefix));
+                               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_bitmask_decode(
+                                       BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
+                                       nlri_content + offset,
+                                       len - offset,
+                                       &bpem->tcpflags, &error);
+                       if (error < 0)
+                               flog_err(
+                                       EC_BGP_FLOWSPEC_PACKET,
+                                       "%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);
+                       ret = bgp_flowspec_bitmask_decode(
+                                       BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
+                                       nlri_content + offset,
+                                       len - offset, &bpem->fragment,
+                                       &error);
+                       if (error < 0)
+                               flog_err(
+                                       EC_BGP_FLOWSPEC_PACKET,
+                                       "%s: flowspec_fragment_type_decode error %d",
+                                       __func__, error);
+                       else
+                               bpem->match_fragment_num = error;
+                       offset += ret;
                        break;
                default:
-                       error = -1;
-                       break;
+                       flog_err(EC_LIB_DEVELOPMENT, "%s: unknown type %d\n",
+                                __func__, type);
                }
-               offset += ret;
-       }
-       return false;
-}
-
-struct bgp_node *bgp_flowspec_get_match_per_ip(afi_t afi,
-                                              struct bgp_table *rib,
-                                              struct prefix *match,
-                                              int prefix_check)
-{
-       struct bgp_node *rn;
-       struct prefix *prefix;
-
-       for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
-               prefix = &rn->p;
-
-               if (prefix->family != AF_FLOWSPEC)
-                       continue;
-
-               if (bgp_flowspec_contains_prefix(prefix, match, prefix_check))
-                       return rn;
        }
-       return NULL;
+       return error;
 }