summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilippe Guibert <philippe.guibert@6wind.com>2019-10-16 08:42:30 +0200
committerPhilippe Guibert <philippe.guibert@6wind.com>2020-08-21 13:37:08 +0200
commit9cec4121623c18eb5d826420e2078e2a78242362 (patch)
tree345c4ced2b1c8a527dc8dd11e7a2b2e0c2c71599
parentbgpd: flowspec code support for ipv6 (diff)
downloadfrr-9cec4121623c18eb5d826420e2078e2a78242362.tar.xz
frr-9cec4121623c18eb5d826420e2078e2a78242362.zip
bgpd: ipv6 flowspec address decoding and validation
as per [0], ipv6 adress format introduces an ipv6 offset that needs to be extracted too. The change include the validation, decoding for further usage with policy-routing and decoding for dumping. [0] https://tools.ietf.org/html/draft-ietf-idr-flow-spec-v6-09 Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
-rw-r--r--bgpd/bgp_flowspec.c2
-rw-r--r--bgpd/bgp_flowspec_util.c48
-rw-r--r--bgpd/bgp_flowspec_util.h2
-rw-r--r--bgpd/bgp_flowspec_vty.c2
-rw-r--r--bgpd/bgp_pbr.c290
-rw-r--r--bgpd/bgp_pbr.h2
6 files changed, 241 insertions, 105 deletions
diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c
index 03fc1f52c..19db1159c 100644
--- a/bgpd/bgp_flowspec.c
+++ b/bgpd/bgp_flowspec.c
@@ -50,7 +50,7 @@ static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len,
BGP_FLOWSPEC_VALIDATE_ONLY,
nlri_content + offset,
len - offset, NULL, &error,
- afi);
+ afi, NULL);
break;
case FLOWSPEC_IP_PROTOCOL:
case FLOWSPEC_PORT:
diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c
index 0e879e816..2dd35696d 100644
--- a/bgpd/bgp_flowspec_util.c
+++ b/bgpd/bgp_flowspec_util.c
@@ -101,7 +101,7 @@ bool bgp_flowspec_contains_prefix(const struct prefix *pfs,
nlri_content+offset,
len - offset,
&compare, &error,
- afi);
+ afi, NULL);
if (ret <= 0)
break;
if (prefix_check &&
@@ -162,13 +162,15 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
uint8_t *nlri_ptr,
uint32_t max_len,
void *result, int *error,
- afi_t afi)
+ afi_t afi,
+ uint8_t *ipv6_offset)
{
char *display = (char *)result; /* for return_string */
struct prefix *prefix = (struct prefix *)result;
uint32_t offset = 0;
struct prefix prefix_local;
int psize;
+ uint8_t prefix_offset = 0;
*error = 0;
memset(&prefix_local, 0, sizeof(struct prefix));
@@ -176,8 +178,13 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
prefix_local.prefixlen = nlri_ptr[offset];
psize = PSIZE(prefix_local.prefixlen);
offset++;
- /* TODO Flowspec IPv6 Support */
- prefix_local.family = AF_INET;
+ prefix_local.family = afi2family(afi);
+ if (prefix_local.family == AF_INET6) {
+ prefix_offset = nlri_ptr[offset];
+ if (ipv6_offset)
+ *ipv6_offset = prefix_offset;
+ offset++;
+ }
/* Prefix length check. */
if (prefix_local.prefixlen > prefix_blen(&prefix_local) * 8)
*error = -1;
@@ -193,11 +200,28 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
offset += psize;
switch (type) {
case BGP_FLOWSPEC_RETURN_STRING:
- prefix2str(&prefix_local, display,
- BGP_FLOWSPEC_STRING_DISPLAY_MAX);
+ if (prefix_local.family == AF_INET6) {
+ char str[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
+ int ret;
+
+ prefix2str(&prefix_local, str,
+ BGP_FLOWSPEC_STRING_DISPLAY_MAX);
+ ret = snprintf(display, BGP_FLOWSPEC_STRING_DISPLAY_MAX,
+ "%s/off %u",
+ str, prefix_offset);
+ if (ret < 0) {
+ *error = -1;
+ break;
+ }
+ } else
+ prefix2str(&prefix_local, display,
+ BGP_FLOWSPEC_STRING_DISPLAY_MAX);
break;
case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
- PREFIX_COPY_IPV4(prefix, &prefix_local)
+ if (prefix_local.family == AF_INET)
+ PREFIX_COPY_IPV4(prefix, &prefix_local)
+ else
+ PREFIX_COPY_IPV6(prefix, &prefix_local)
break;
case BGP_FLOWSPEC_VALIDATE_ONLY:
default:
@@ -430,6 +454,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
uint8_t *match_num;
uint8_t bitmask = 0;
int ret = 0, type;
+ uint8_t *prefix_offset;
while (offset < len - 1 && error >= 0) {
type = nlri_content[offset];
@@ -441,16 +466,18 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
if (type == FLOWSPEC_DEST_PREFIX) {
bitmask |= PREFIX_DST_PRESENT;
prefix = &bpem->dst_prefix;
+ prefix_offset = &bpem->dst_prefix_offset;
} else {
bitmask |= PREFIX_SRC_PRESENT;
prefix = &bpem->src_prefix;
+ prefix_offset = &bpem->src_prefix_offset;
}
ret = bgp_flowspec_ip_address(
BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
nlri_content + offset,
len - offset,
prefix, &error,
- afi);
+ afi, prefix_offset);
if (error < 0)
flog_err(EC_BGP_FLOWSPEC_PACKET,
"%s: flowspec_ip_address error %d",
@@ -462,6 +489,11 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
if (prefix->family == AF_INET
&& prefix->u.prefix4.s_addr == INADDR_ANY)
bpem->match_bitmask_iprule |= bitmask;
+ else if (prefix->family == AF_INET6
+ && !memcmp(&prefix->u.prefix6,
+ &in6addr_any,
+ sizeof(struct in6_addr)))
+ bpem->match_bitmask_iprule |= bitmask;
else
bpem->match_bitmask |= bitmask;
}
diff --git a/bgpd/bgp_flowspec_util.h b/bgpd/bgp_flowspec_util.h
index 26d919d7d..6cc4854d7 100644
--- a/bgpd/bgp_flowspec_util.h
+++ b/bgpd/bgp_flowspec_util.h
@@ -40,7 +40,7 @@ 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,
- afi_t afi);
+ afi_t afi, uint8_t *ipv6_offset);
extern int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
uint8_t *nlri_ptr,
diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c
index 5703d86be..d3e95b123 100644
--- a/bgpd/bgp_flowspec_vty.c
+++ b/bgpd/bgp_flowspec_vty.c
@@ -129,7 +129,7 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
nlri_content+offset,
len - offset,
local_string, &error,
- afi);
+ afi, NULL);
if (ret <= 0)
break;
if (json_path) {
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index 38b1ae4da..c20bade97 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -168,35 +168,61 @@ static int bgp_pbr_match_walkcb(struct hash_bucket *bucket, void *arg)
return HASHWALK_CONTINUE;
}
-static int sprintf_bgp_pbr_match_val(char *str, struct bgp_pbr_match_val *mval,
- const char *prepend)
+static int snprintf_bgp_pbr_match_val(char *str, int len, struct bgp_pbr_match_val *mval,
+ const char *prepend)
{
char *ptr = str;
+ int delta;
- if (prepend)
- ptr += sprintf(ptr, "%s", prepend);
- else {
- if (mval->unary_operator & OPERATOR_UNARY_OR)
- ptr += sprintf(ptr, ", or ");
- if (mval->unary_operator & OPERATOR_UNARY_AND)
- ptr += sprintf(ptr, ", and ");
- }
- if (mval->compare_operator & OPERATOR_COMPARE_LESS_THAN)
- ptr += sprintf(ptr, "<");
- if (mval->compare_operator & OPERATOR_COMPARE_GREATER_THAN)
- ptr += sprintf(ptr, ">");
- if (mval->compare_operator & OPERATOR_COMPARE_EQUAL_TO)
- ptr += sprintf(ptr, "=");
- if (mval->compare_operator & OPERATOR_COMPARE_EXACT_MATCH)
- ptr += sprintf(ptr, "match");
- ptr += sprintf(ptr, " %u", mval->value);
+ if (prepend) {
+ delta = snprintf(ptr, len, "%s", prepend);
+ ptr += delta;
+ len -= delta;
+ } else {
+ if (mval->unary_operator & OPERATOR_UNARY_OR) {
+ delta = snprintf(ptr, len, ", or ");
+ ptr += delta;
+ len -= delta;
+ }
+ if (mval->unary_operator & OPERATOR_UNARY_AND) {
+ delta = snprintf(ptr, len, ", and ");
+ ptr += delta;
+ len -= delta;
+ }
+ }
+ if (mval->compare_operator & OPERATOR_COMPARE_LESS_THAN) {
+ delta = snprintf(ptr, len, "<");
+ ptr += delta;
+ len -= delta;
+ }
+ if (mval->compare_operator & OPERATOR_COMPARE_GREATER_THAN) {
+ delta = snprintf(ptr, len, ">");
+ ptr += delta;
+ len -= delta;
+ }
+ if (mval->compare_operator & OPERATOR_COMPARE_EQUAL_TO) {
+ delta = snprintf(ptr, len, "=");
+ ptr += delta;
+ len -= delta;
+ }
+ if (mval->compare_operator & OPERATOR_COMPARE_EXACT_MATCH) {
+ delta = snprintf(ptr, len, "match");
+ ptr += delta;
+ len -= delta;
+ }
+ ptr += snprintf(ptr, len, " %u", mval->value);
return (int)(ptr - str);
}
-#define INCREMENT_DISPLAY(_ptr, _cnt) do { \
- if (_cnt) \
- (_ptr) += sprintf((_ptr), "; "); \
- _cnt++; \
+#define INCREMENT_DISPLAY(_ptr, _cnt, _len) do { \
+ int sn_delta; \
+ \
+ if (_cnt) { \
+ sn_delta = snprintf((_ptr), (_len), "; ");\
+ (_len) -= sn_delta; \
+ (_ptr) += sn_delta; \
+ } \
+ (_cnt)++; \
} while (0)
/* this structure can be used for port range,
@@ -1275,132 +1301,208 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
char *ptr = return_string;
char buff[64];
int nb_items = 0;
+ int delta, len = sizeof(return_string);
- ptr += sprintf(ptr, "MATCH : ");
+ delta = snprintf(ptr, sizeof(return_string), "MATCH : ");
+ len -= delta;
+ ptr += delta;
if (api->match_bitmask & PREFIX_SRC_PRESENT) {
struct prefix *p = &(api->src_prefix);
- ptr += sprintf(ptr, "@src %s", prefix2str(p, buff, 64));
- INCREMENT_DISPLAY(ptr, nb_items);
+ if (api->src_prefix_offset)
+ delta = snprintf(ptr, len, "@src %s/off%u",
+ prefix2str(p, buff, 64),
+ api->src_prefix_offset);
+ else
+ delta = snprintf(ptr, len, "@src %s",
+ prefix2str(p, buff, 64));
+ len -= delta;
+ ptr += delta;
+ INCREMENT_DISPLAY(ptr, nb_items, len);
}
if (api->match_bitmask & PREFIX_DST_PRESENT) {
struct prefix *p = &(api->dst_prefix);
- INCREMENT_DISPLAY(ptr, nb_items);
- ptr += sprintf(ptr, "@dst %s", prefix2str(p, buff, 64));
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ if (api->dst_prefix_offset)
+ delta = snprintf(ptr, len, "@dst %s/off%u",
+ prefix2str(p, buff, 64),
+ api->dst_prefix_offset);
+ else
+ delta = snprintf(ptr, len, "@dst %s", prefix2str(p, buff, 64));
+ len -= delta;
+ ptr += delta;
}
if (api->match_protocol_num)
- INCREMENT_DISPLAY(ptr, nb_items);
- for (i = 0; i < api->match_protocol_num; i++)
- ptr += sprintf_bgp_pbr_match_val(ptr, &api->protocol[i],
- i > 0 ? NULL : "@proto ");
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ for (i = 0; i < api->match_protocol_num; i++) {
+ delta = snprintf_bgp_pbr_match_val(ptr, len, &api->protocol[i],
+ i > 0 ? NULL : "@proto ");
+ len -= delta;
+ ptr += delta;
+ }
if (api->match_src_port_num)
- INCREMENT_DISPLAY(ptr, nb_items);
- for (i = 0; i < api->match_src_port_num; i++)
- ptr += sprintf_bgp_pbr_match_val(ptr, &api->src_port[i],
- i > 0 ? NULL : "@srcport ");
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ for (i = 0; i < api->match_src_port_num; i++) {
+ delta = snprintf_bgp_pbr_match_val(ptr, len, &api->src_port[i],
+ i > 0 ? NULL : "@srcport ");
+ len -= delta;
+ ptr += delta;
+ }
if (api->match_dst_port_num)
- INCREMENT_DISPLAY(ptr, nb_items);
- for (i = 0; i < api->match_dst_port_num; i++)
- ptr += sprintf_bgp_pbr_match_val(ptr, &api->dst_port[i],
- i > 0 ? NULL : "@dstport ");
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ for (i = 0; i < api->match_dst_port_num; i++) {
+ delta = snprintf_bgp_pbr_match_val(ptr, len, &api->dst_port[i],
+ i > 0 ? NULL : "@dstport ");
+ len -= delta;
+ ptr += delta;
+ }
if (api->match_port_num)
- INCREMENT_DISPLAY(ptr, nb_items);
- for (i = 0; i < api->match_port_num; i++)
- ptr += sprintf_bgp_pbr_match_val(ptr, &api->port[i],
- i > 0 ? NULL : "@port ");
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ for (i = 0; i < api->match_port_num; i++) {
+ delta = snprintf_bgp_pbr_match_val(ptr, len, &api->port[i],
+ i > 0 ? NULL : "@port ");
+ len -= delta;
+ ptr += delta;
+ }
if (api->match_icmp_type_num)
- INCREMENT_DISPLAY(ptr, nb_items);
- for (i = 0; i < api->match_icmp_type_num; i++)
- ptr += sprintf_bgp_pbr_match_val(ptr, &api->icmp_type[i],
- i > 0 ? NULL : "@icmptype ");
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ for (i = 0; i < api->match_icmp_type_num; i++) {
+ delta = snprintf_bgp_pbr_match_val(ptr, len, &api->icmp_type[i],
+ i > 0 ? NULL : "@icmptype ");
+ len -= delta;
+ ptr += delta;
+ }
if (api->match_icmp_code_num)
- INCREMENT_DISPLAY(ptr, nb_items);
- for (i = 0; i < api->match_icmp_code_num; i++)
- ptr += sprintf_bgp_pbr_match_val(ptr, &api->icmp_code[i],
- i > 0 ? NULL : "@icmpcode ");
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ for (i = 0; i < api->match_icmp_code_num; i++) {
+ delta = snprintf_bgp_pbr_match_val(ptr, len, &api->icmp_code[i],
+ i > 0 ? NULL : "@icmpcode ");
+ len -= delta;
+ ptr += delta;
+ }
if (api->match_packet_length_num)
- INCREMENT_DISPLAY(ptr, nb_items);
- for (i = 0; i < api->match_packet_length_num; i++)
- ptr += sprintf_bgp_pbr_match_val(ptr, &api->packet_length[i],
- i > 0 ? NULL : "@plen ");
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ for (i = 0; i < api->match_packet_length_num; i++) {
+ delta = snprintf_bgp_pbr_match_val(ptr, len, &api->packet_length[i],
+ i > 0 ? NULL : "@plen ");
+ len -= delta;
+ ptr += delta;
+ }
if (api->match_dscp_num)
- INCREMENT_DISPLAY(ptr, nb_items);
- for (i = 0; i < api->match_dscp_num; i++)
- ptr += sprintf_bgp_pbr_match_val(ptr, &api->dscp[i],
- i > 0 ? NULL : "@dscp ");
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ for (i = 0; i < api->match_dscp_num; i++) {
+ delta = snprintf_bgp_pbr_match_val(ptr, len, &api->dscp[i],
+ i > 0 ? NULL : "@dscp ");
+ len -= delta;
+ ptr += delta;
+ }
if (api->match_tcpflags_num)
- INCREMENT_DISPLAY(ptr, nb_items);
- for (i = 0; i < api->match_tcpflags_num; i++)
- ptr += sprintf_bgp_pbr_match_val(ptr, &api->tcpflags[i],
- i > 0 ? NULL : "@tcpflags ");
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ for (i = 0; i < api->match_tcpflags_num; i++) {
+ delta = snprintf_bgp_pbr_match_val(ptr, len, &api->tcpflags[i],
+ i > 0 ? NULL : "@tcpflags ");
+ len -= delta;
+ ptr += delta;
+ }
if (api->match_fragment_num)
- INCREMENT_DISPLAY(ptr, nb_items);
- for (i = 0; i < api->match_fragment_num; i++)
- ptr += sprintf_bgp_pbr_match_val(ptr, &api->fragment[i],
- i > 0 ? NULL : "@fragment ");
- if (!nb_items)
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ for (i = 0; i < api->match_fragment_num; i++) {
+ delta = snprintf_bgp_pbr_match_val(ptr, len, &api->fragment[i],
+ i > 0 ? NULL : "@fragment ");
+ len -= delta;
+ ptr += delta;
+ }
+
+ len = sizeof(return_string);
+ if (!nb_items) {
ptr = return_string;
- else
- ptr += sprintf(ptr, "; ");
- if (api->action_num)
- ptr += sprintf(ptr, "SET : ");
+ } else {
+ len -= (ptr - return_string);
+ delta = snprintf(ptr, len, "; ");
+ len -= delta;
+ ptr += delta;
+ }
+ if (api->action_num) {
+ delta = snprintf(ptr, len, "SET : ");
+ len -= delta;
+ ptr += delta;
+ }
nb_items = 0;
for (i = 0; i < api->action_num; i++) {
switch (api->actions[i].action) {
case ACTION_TRAFFICRATE:
- INCREMENT_DISPLAY(ptr, nb_items);
- ptr += sprintf(ptr, "@set rate %f",
- api->actions[i].u.r.rate);
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ delta = snprintf(ptr, len, "@set rate %f",
+ api->actions[i].u.r.rate);
+ len -= delta;
+ ptr += delta;
break;
case ACTION_TRAFFIC_ACTION:
- INCREMENT_DISPLAY(ptr, nb_items);
- ptr += sprintf(ptr, "@action ");
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ delta = snprintf(ptr, len, "@action ");
+ len -= delta;
+ ptr += delta;
if (api->actions[i].u.za.filter
- & TRAFFIC_ACTION_TERMINATE)
- ptr += sprintf(ptr,
- " terminate (apply filter(s))");
+ & TRAFFIC_ACTION_TERMINATE) {
+ delta = snprintf(ptr, len,
+ " terminate (apply filter(s))");
+ len -= delta;
+ ptr += delta;
+ }
if (api->actions[i].u.za.filter
- & TRAFFIC_ACTION_DISTRIBUTE)
- ptr += sprintf(ptr, " distribute");
+ & TRAFFIC_ACTION_DISTRIBUTE) {
+ delta = snprintf(ptr, len, " distribute");
+ len -= delta;
+ ptr += delta;
+ }
if (api->actions[i].u.za.filter
- & TRAFFIC_ACTION_SAMPLE)
- ptr += sprintf(ptr, " sample");
+ & TRAFFIC_ACTION_SAMPLE) {
+ delta = snprintf(ptr, len, " sample");
+ len -= delta;
+ ptr += delta;
+ }
break;
case ACTION_REDIRECT_IP:
- INCREMENT_DISPLAY(ptr, nb_items);
char local_buff[INET_ADDRSTRLEN];
+ INCREMENT_DISPLAY(ptr, nb_items, len);
if (inet_ntop(AF_INET,
&api->actions[i].u.zr.redirect_ip_v4,
local_buff, INET_ADDRSTRLEN) != NULL)
- ptr += sprintf(ptr,
+ delta = snprintf(ptr, len,
"@redirect ip nh %s", local_buff);
+ len -= delta;
+ ptr += delta;
break;
case ACTION_REDIRECT: {
struct vrf *vrf;
vrf = vrf_lookup_by_id(api->actions[i].u.redirect_vrf);
- INCREMENT_DISPLAY(ptr, nb_items);
- ptr += sprintf(ptr, "@redirect vrf %s(%u)",
- VRF_LOGNAME(vrf),
- api->actions[i].u.redirect_vrf);
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ delta = snprintf(ptr, len, "@redirect vrf %s(%u)",
+ VRF_LOGNAME(vrf),
+ api->actions[i].u.redirect_vrf);
+ len -= delta;
+ ptr += delta;
break;
}
case ACTION_MARKING:
- INCREMENT_DISPLAY(ptr, nb_items);
- ptr += sprintf(ptr, "@set dscp %u",
- api->actions[i].u.marking_dscp);
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ delta = snprintf(ptr, len, "@set dscp %u",
+ api->actions[i].u.marking_dscp);
+ len -= delta;
+ ptr += delta;
break;
default:
break;
diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h
index 52bb3b541..ff771f88d 100644
--- a/bgpd/bgp_pbr.h
+++ b/bgpd/bgp_pbr.h
@@ -118,6 +118,8 @@ struct bgp_pbr_entry_main {
struct prefix src_prefix;
struct prefix dst_prefix;
+ uint8_t src_prefix_offset;
+ uint8_t dst_prefix_offset;
#define PROTOCOL_UDP 17
#define PROTOCOL_TCP 6