#include "zebra.h"
#include "prefix.h"
+#include "lib_errors.h"
+#include "bgp_route.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)
{
len,
mval, error);
if (*error < 0)
- zlog_err("%s: flowspec_op_decode error %d",
- __func__, *error);
+ flog_err(EC_BGP_FLOWSPEC_PACKET,
+ "%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)
+bool bgp_flowspec_contains_prefix(struct prefix *pfs,
+ struct prefix *input,
+ int prefix_check)
{
uint32_t offset = 0;
int type;
len - offset,
NULL, &error);
break;
+ case FLOWSPEC_FRAGMENT:
case FLOWSPEC_TCP_FLAGS:
- ret = bgp_flowspec_tcpflags_decode(
+ ret = bgp_flowspec_bitmask_decode(
BGP_FLOWSPEC_VALIDATE_ONLY,
nlri_content+offset,
len - 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;
/*
- * 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)
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;
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 */
- 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 {
- 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:
- mval->bitmask = (uint8_t)value;
- 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;
-}
-
int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
struct bgp_pbr_entry_main *bpem)
{
len - offset,
prefix, &error);
if (error < 0)
- zlog_err("%s: flowspec_ip_address error %d",
+ flog_err(EC_BGP_FLOWSPEC_PACKET,
+ "%s: flowspec_ip_address error %d",
__func__, error);
- else
- bpem->match_bitmask |= bitmask;
+ 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)
+ bpem->match_bitmask_iprule |= bitmask;
+ else
+ bpem->match_bitmask |= bitmask;
+ }
offset += ret;
break;
case FLOWSPEC_IP_PROTOCOL:
&error);
break;
case FLOWSPEC_TCP_FLAGS:
- ret = bgp_flowspec_tcpflags_decode(
+ ret = bgp_flowspec_bitmask_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);
+ 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(
+ ret = bgp_flowspec_bitmask_decode(
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);
+ flog_err(
+ EC_BGP_FLOWSPEC_PACKET,
+ "%s: flowspec_fragment_type_decode error %d",
+ __func__, error);
else
- bpem->match_bitmask |= FRAGMENT_PRESENT;
+ bpem->match_fragment_num = error;
offset += ret;
break;
default:
- zlog_err("%s: unknown type %d\n", __func__, type);
+ flog_err(EC_LIB_DEVELOPMENT, "%s: unknown type %d\n",
+ __func__, type);
}
}
+ if (bpem->match_packet_length_num || bpem->match_fragment_num ||
+ bpem->match_tcpflags_num || bpem->match_dscp_num ||
+ bpem->match_packet_length_num || bpem->match_icmp_code_num ||
+ bpem->match_icmp_type_num || bpem->match_port_num ||
+ bpem->match_src_port_num || bpem->match_dst_port_num ||
+ bpem->match_protocol_num || bpem->match_bitmask)
+ bpem->type = BGP_PBR_IPSET;
+ else if ((bpem->match_bitmask_iprule & PREFIX_SRC_PRESENT) ||
+ (bpem->match_bitmask_iprule & PREFIX_DST_PRESENT))
+ /* the extracted policy rule may not need an
+ * iptables/ipset filtering. check this may not be
+ * a standard ip rule : permit any to any ( eg)
+ */
+ bpem->type = BGP_PBR_IPRULE;
+ else
+ bpem->type = BGP_PBR_UNDEFINED;
return error;
}
-
-struct bgp_node *bgp_flowspec_get_match_per_ip(afi_t afi,
- struct bgp_table *rib,
- struct prefix *match,
- int prefix_check)
+/* return 1 if FS entry invalid or no NH IP */
+int bgp_flowspec_get_first_nh(struct bgp *bgp, struct bgp_path_info *pi,
+ struct prefix *p)
{
- struct bgp_node *rn;
- struct prefix *prefix;
+ struct bgp_pbr_entry_main api;
+ int i;
+ struct bgp_node *rn = pi->net;
+ struct bgp_pbr_entry_action *api_action;
- for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
- prefix = &rn->p;
-
- if (prefix->family != AF_FLOWSPEC)
+ memset(&api, 0, sizeof(struct bgp_pbr_entry_main));
+ if (bgp_pbr_build_and_validate_entry(&rn->p, pi, &api) < 0)
+ return 1;
+ for (i = 0; i < api.action_num; i++) {
+ api_action = &api.actions[i];
+ if (api_action->action != ACTION_REDIRECT_IP)
continue;
-
- if (bgp_flowspec_contains_prefix(prefix, match, prefix_check))
- return rn;
+ p->family = AF_INET;
+ p->prefixlen = IPV4_MAX_BITLEN;
+ p->u.prefix4 = api_action->u.zr.redirect_ip_v4;
+ return 0;
}
- return NULL;
+ return 1;
}