summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_flowspec.c7
-rw-r--r--bgpd/bgp_flowspec_private.h1
-rw-r--r--bgpd/bgp_flowspec_util.c27
-rw-r--r--bgpd/bgp_flowspec_vty.c3
-rw-r--r--bgpd/bgp_pbr.c85
-rw-r--r--bgpd/bgp_pbr.h3
-rw-r--r--lib/pbr.h2
7 files changed, 123 insertions, 5 deletions
diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c
index 19db1159c..341cfe9d0 100644
--- a/bgpd/bgp_flowspec.c
+++ b/bgpd/bgp_flowspec.c
@@ -52,6 +52,13 @@ static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len,
len - offset, NULL, &error,
afi, NULL);
break;
+ case FLOWSPEC_FLOW_LABEL:
+ if (afi == AFI_IP)
+ return -1;
+ ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY,
+ nlri_content + offset,
+ len - offset, NULL, &error);
+ break;
case FLOWSPEC_IP_PROTOCOL:
case FLOWSPEC_PORT:
case FLOWSPEC_DEST_PORT:
diff --git a/bgpd/bgp_flowspec_private.h b/bgpd/bgp_flowspec_private.h
index cec244c16..757a8ae2e 100644
--- a/bgpd/bgp_flowspec_private.h
+++ b/bgpd/bgp_flowspec_private.h
@@ -41,5 +41,6 @@
#define FLOWSPEC_PKT_LEN 10
#define FLOWSPEC_DSCP 11
#define FLOWSPEC_FRAGMENT 12
+#define FLOWSPEC_FLOW_LABEL 13 /* For IPv6 only */
#endif /* _FRR_BGP_FLOWSPEC_PRIVATE_H */
diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c
index 2dd35696d..0115d7af1 100644
--- a/bgpd/bgp_flowspec_util.c
+++ b/bgpd/bgp_flowspec_util.c
@@ -118,6 +118,16 @@ bool bgp_flowspec_contains_prefix(const struct prefix *pfs,
&compare.u.prefix6.s6_addr))
return true;
break;
+ case FLOWSPEC_FLOW_LABEL:
+ if (afi == AFI_IP) {
+ error = -1;
+ continue;
+ }
+ ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY,
+ nlri_content+offset,
+ len - offset,
+ NULL, &error);
+ break;
case FLOWSPEC_IP_PROTOCOL:
case FLOWSPEC_PORT:
case FLOWSPEC_DEST_PORT:
@@ -499,6 +509,20 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
}
offset += ret;
break;
+ case FLOWSPEC_FLOW_LABEL:
+ if (afi == AFI_IP) {
+ error = -1;
+ continue;
+ }
+ match_num = &(bpem->match_flowlabel_num);
+ mval = (struct bgp_pbr_match_val *)
+ &(bpem->flow_label);
+ offset += bgp_flowspec_call_non_opaque_decode(
+ nlri_content + offset,
+ len - offset,
+ mval, match_num,
+ &error);
+ break;
case FLOWSPEC_IP_PROTOCOL:
match_num = &(bpem->match_protocol_num);
mval = (struct bgp_pbr_match_val *)
@@ -621,7 +645,8 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
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->match_protocol_num || bpem->match_bitmask ||
+ bpem->match_flowlabel_num)
bpem->type = BGP_PBR_IPSET;
else if ((bpem->match_bitmask_iprule & PREFIX_SRC_PRESENT) ||
(bpem->match_bitmask_iprule & PREFIX_DST_PRESENT))
diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c
index d3e95b123..4b1d26b2f 100644
--- a/bgpd/bgp_flowspec_vty.c
+++ b/bgpd/bgp_flowspec_vty.c
@@ -50,6 +50,7 @@ static const struct message bgp_flowspec_display_large[] = {
{FLOWSPEC_PKT_LEN, "Packet Length"},
{FLOWSPEC_DSCP, "DSCP field"},
{FLOWSPEC_FRAGMENT, "Packet Fragment"},
+ {FLOWSPEC_FLOW_LABEL, "Packet Flow Label"},
{0}
};
@@ -66,6 +67,7 @@ static const struct message bgp_flowspec_display_min[] = {
{FLOWSPEC_PKT_LEN, "pktlen"},
{FLOWSPEC_DSCP, "dscp"},
{FLOWSPEC_FRAGMENT, "pktfrag"},
+ {FLOWSPEC_FLOW_LABEL, "flwlbl"},
{0}
};
@@ -147,6 +149,7 @@ void bgp_fs_nlri_get_string(unsigned char *nlri_content, size_t len,
len_string -= len_written;
ptr += len_written;
break;
+ case FLOWSPEC_FLOW_LABEL:
case FLOWSPEC_IP_PROTOCOL:
case FLOWSPEC_PORT:
case FLOWSPEC_DEST_PORT:
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index c20bade97..715781143 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -257,6 +257,7 @@ struct bgp_pbr_filter {
struct bgp_pbr_range_port *dst_port;
struct bgp_pbr_val_mask *tcp_flags;
struct bgp_pbr_val_mask *dscp;
+ struct bgp_pbr_val_mask *flow_label;
struct bgp_pbr_val_mask *pkt_len_val;
struct bgp_pbr_val_mask *fragment;
};
@@ -268,6 +269,7 @@ struct bgp_pbr_filter {
struct bgp_pbr_or_filter {
struct list *tcpflags;
struct list *dscp;
+ struct list *flowlabel;
struct list *pkt_len;
struct list *fragment;
struct list *icmp_type;
@@ -294,6 +296,7 @@ static bool bgp_pbr_extract_enumerate_unary_opposite(
TCP_HEADER_ALL_FLAGS &
~(value);
} else if (type_entry == FLOWSPEC_DSCP ||
+ type_entry == FLOWSPEC_FLOW_LABEL ||
type_entry == FLOWSPEC_PKT_LEN ||
type_entry == FLOWSPEC_FRAGMENT) {
and_valmask->val = value;
@@ -308,6 +311,7 @@ static bool bgp_pbr_extract_enumerate_unary_opposite(
TCP_HEADER_ALL_FLAGS &
~(value);
} else if (type_entry == FLOWSPEC_DSCP ||
+ type_entry == FLOWSPEC_FLOW_LABEL ||
type_entry == FLOWSPEC_FRAGMENT ||
type_entry == FLOWSPEC_PKT_LEN) {
and_valmask->val = value;
@@ -322,7 +326,7 @@ static bool bgp_pbr_extract_enumerate_unary_opposite(
/* TCP : FIN and SYN -> val = ALL; mask = 3
* TCP : not (FIN and SYN) -> val = ALL; mask = ALL & ~(FIN|RST)
- * other variables type: dscp, pkt len, fragment
+ * other variables type: dscp, pkt len, fragment, flow label
* - value is copied in bgp_pbr_val_mask->val value
* - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1
*/
@@ -377,6 +381,7 @@ static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[],
and_valmask->mask |=
TCP_HEADER_ALL_FLAGS & list[i].value;
} else if (type_entry == FLOWSPEC_DSCP ||
+ type_entry == FLOWSPEC_FLOW_LABEL ||
type_entry == FLOWSPEC_ICMP_TYPE ||
type_entry == FLOWSPEC_ICMP_CODE ||
type_entry == FLOWSPEC_FRAGMENT ||
@@ -601,6 +606,23 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
return 0;
}
}
+ if (api->match_flowlabel_num) {
+ if (api->afi == AFI_IP) {
+ if (BGP_DEBUG(pbr, PBR))
+ zlog_debug("BGP: match Flow Label operations:"
+ "Not for IPv4.");
+ return 0;
+ }
+ if (!bgp_pbr_extract_enumerate(api->flow_label,
+ api->match_flowlabel_num,
+ OPERATOR_UNARY_OR | OPERATOR_UNARY_AND,
+ NULL, FLOWSPEC_FLOW_LABEL)) {
+ if (BGP_DEBUG(pbr, PBR))
+ zlog_debug("BGP: match FlowLabel operations:"
+ "too complex. ignoring.");
+ return 0;
+ }
+ }
if (api->match_fragment_num) {
char fail_str[64];
bool success;
@@ -624,6 +646,13 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
"Value not valid (%d) for this implementation",
api->fragment[i].value);
}
+ if (api->afi == AFI_IP6 &&
+ api->fragment[i].value == 1) {
+ success = false;
+ snprintf(fail_str, sizeof(fail_str),
+ "IPv6 dont fragment match invalid (%d)",
+ api->fragment[i].value);
+ }
}
} else
snprintf(fail_str, sizeof(fail_str),
@@ -669,7 +698,7 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
if (api->actions[i].action == ACTION_MARKING) {
if (BGP_DEBUG(pbr, PBR)) {
bgp_pbr_print_policy_route(api);
- zlog_warn("PBR: iprule set DSCP %u not supported",
+ zlog_warn("PBR: iprule set DSCP/Flow Label %u not supported",
api->actions[i].u.marking_dscp);
}
}
@@ -1001,6 +1030,7 @@ uint32_t bgp_pbr_match_hash_key(const void *arg)
key = jhash(&pbm->tcp_flags, 2, key);
key = jhash(&pbm->tcp_mask_flags, 2, key);
key = jhash(&pbm->dscp_value, 1, key);
+ key = jhash(&pbm->flow_label, 2, key);
key = jhash(&pbm->fragment, 1, key);
key = jhash(&pbm->protocol, 1, key);
return jhash_1word(pbm->type, key);
@@ -1040,6 +1070,9 @@ bool bgp_pbr_match_hash_equal(const void *arg1, const void *arg2)
if (r1->dscp_value != r2->dscp_value)
return false;
+ if (r1->flow_label != r2->flow_label)
+ return false;
+
if (r1->fragment != r2->fragment)
return false;
@@ -1406,6 +1439,15 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
ptr += delta;
}
+ if (api->match_flowlabel_num)
+ INCREMENT_DISPLAY(ptr, nb_items, len);
+ for (i = 0; i < api->match_flowlabel_num; i++) {
+ delta = snprintf_bgp_pbr_match_val(ptr, len, &api->flow_label[i],
+ i > 0 ? NULL : "@flowlabel ");
+ len -= delta;
+ ptr += delta;
+ }
+
if (api->match_tcpflags_num)
INCREMENT_DISPLAY(ptr, nb_items, len);
for (i = 0; i < api->match_tcpflags_num; i++) {
@@ -1499,7 +1541,7 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
}
case ACTION_MARKING:
INCREMENT_DISPLAY(ptr, nb_items, len);
- delta = snprintf(ptr, len, "@set dscp %u",
+ delta = snprintf(ptr, len, "@set dscp/flowlabel %u",
api->actions[i].u.marking_dscp);
len -= delta;
ptr += delta;
@@ -1676,6 +1718,7 @@ static int bgp_pbr_get_remaining_entry(struct hash_bucket *bucket, void *arg)
bpm_temp->pkt_len_min != bpm->pkt_len_min ||
bpm_temp->pkt_len_max != bpm->pkt_len_max ||
bpm_temp->dscp_value != bpm->dscp_value ||
+ bpm_temp->flow_label != bpm->flow_label ||
bpm_temp->fragment != bpm->fragment)
return HASHWALK_CONTINUE;
@@ -1799,6 +1842,14 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
temp.flags |= MATCH_DSCP_SET;
temp.dscp_value = bpf->dscp->val;
}
+ if (bpf->flow_label) {
+ if (bpf->flow_label->mask)
+ temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET;
+ else
+ temp.flags |= MATCH_FLOW_LABEL_SET;
+ temp.flow_label = bpf->flow_label->val;
+ }
+
if (bpf->fragment) {
if (bpf->fragment->mask)
temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
@@ -1845,6 +1896,8 @@ static uint8_t bgp_pbr_next_type_entry(uint8_t type_entry)
if (type_entry == FLOWSPEC_TCP_FLAGS)
return FLOWSPEC_DSCP;
if (type_entry == FLOWSPEC_DSCP)
+ return FLOWSPEC_FLOW_LABEL;
+ if (type_entry == FLOWSPEC_FLOW_LABEL)
return FLOWSPEC_PKT_LEN;
if (type_entry == FLOWSPEC_PKT_LEN)
return FLOWSPEC_FRAGMENT;
@@ -1938,6 +1991,9 @@ static void bgp_pbr_policyroute_remove_from_zebra_recursive(
} else if (type_entry == FLOWSPEC_DSCP && bpof->dscp) {
orig_list = bpof->dscp;
target_val = &bpf->dscp;
+ } else if (type_entry == FLOWSPEC_FLOW_LABEL && bpof->flowlabel) {
+ orig_list = bpof->flowlabel;
+ target_val = &bpf->flow_label;
} else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) {
orig_list = bpof->pkt_len;
target_val = &bpf->pkt_len_val;
@@ -1975,6 +2031,9 @@ static void bgp_pbr_policyroute_remove_from_zebra(
else if (bpof->dscp)
bgp_pbr_policyroute_remove_from_zebra_recursive(
bgp, path, bpf, bpof, FLOWSPEC_DSCP);
+ else if (bpof->flowlabel)
+ bgp_pbr_policyroute_remove_from_zebra_recursive(
+ bgp, path, bpf, bpof, FLOWSPEC_FLOW_LABEL);
else if (bpof->pkt_len)
bgp_pbr_policyroute_remove_from_zebra_recursive(
bgp, path, bpf, bpof, FLOWSPEC_PKT_LEN);
@@ -1991,6 +2050,8 @@ static void bgp_pbr_policyroute_remove_from_zebra(
list_delete_all_node(bpof->tcpflags);
if (bpof->dscp)
list_delete_all_node(bpof->dscp);
+ if (bpof->flowlabel)
+ list_delete_all_node(bpof->flowlabel);
if (bpof->pkt_len)
list_delete_all_node(bpof->pkt_len);
if (bpof->fragment)
@@ -2082,6 +2143,15 @@ static void bgp_pbr_dump_entry(struct bgp_pbr_filter *bpf, bool add)
? "!" : "",
bpf->dscp->val);
}
+ if (bpf->flow_label) {
+ snprintf(buffer + remaining_len,
+ sizeof(buffer)
+ - remaining_len,
+ "%s flow_label %d",
+ bpf->flow_label->mask
+ ? "!" : "",
+ bpf->flow_label->val);
+ }
zlog_debug("BGP: %s FS PBR from %s to %s, %s %s",
add ? "adding" : "removing",
bpf->src == NULL ? "<all>" :
@@ -2265,6 +2335,13 @@ static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp,
temp.flags |= MATCH_DSCP_SET;
temp.dscp_value = bpf->dscp->val;
}
+ if (bpf->flow_label) {
+ if (bpf->flow_label->mask)
+ temp.flags |= MATCH_FLOW_LABEL_INVERSE_SET;
+ else
+ temp.flags |= MATCH_FLOW_LABEL_SET;
+ temp.flow_label = bpf->flow_label->val;
+ }
if (bpf->fragment) {
if (bpf->fragment->mask)
temp.flags |= MATCH_FRAGMENT_INVERSE_SET;
@@ -2683,7 +2760,7 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, struct bgp_path_info *path,
case ACTION_MARKING:
if (BGP_DEBUG(pbr, PBR)) {
bgp_pbr_print_policy_route(api);
- zlog_warn("PBR: Set DSCP %u Ignored",
+ zlog_warn("PBR: Set DSCP/FlowLabel %u Ignored",
api->actions[i].u.marking_dscp);
}
break;
diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h
index ff771f88d..403300dc0 100644
--- a/bgpd/bgp_pbr.h
+++ b/bgpd/bgp_pbr.h
@@ -115,6 +115,7 @@ struct bgp_pbr_entry_main {
uint8_t match_dscp_num;
uint8_t match_tcpflags_num;
uint8_t match_fragment_num;
+ uint8_t match_flowlabel_num;
struct prefix src_prefix;
struct prefix dst_prefix;
@@ -132,6 +133,7 @@ struct bgp_pbr_entry_main {
struct bgp_pbr_match_val icmp_code[BGP_PBR_MATCH_VAL_MAX];
struct bgp_pbr_match_val packet_length[BGP_PBR_MATCH_VAL_MAX];
struct bgp_pbr_match_val dscp[BGP_PBR_MATCH_VAL_MAX];
+ struct bgp_pbr_match_val flow_label[BGP_PBR_MATCH_VAL_MAX];
struct bgp_pbr_match_val tcpflags[BGP_PBR_MATCH_VAL_MAX];
struct bgp_pbr_match_val fragment[BGP_PBR_MATCH_VAL_MAX];
@@ -190,6 +192,7 @@ struct bgp_pbr_match {
uint8_t dscp_value;
uint8_t fragment;
uint8_t protocol;
+ uint16_t flow_label;
vrf_id_t vrf_id;
diff --git a/lib/pbr.h b/lib/pbr.h
index fd183d711..53a63122c 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -129,6 +129,8 @@ struct pbr_rule {
#define MATCH_FRAGMENT_INVERSE_SET (1 << 9)
#define MATCH_ICMP_SET (1 << 10)
#define MATCH_PROTOCOL_SET (1 << 11)
+#define MATCH_FLOW_LABEL_SET (1 << 12)
+#define MATCH_FLOW_LABEL_INVERSE_SET (1 << 13)
extern int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s,
struct pbr_rule *zrule);