From a197ea1e10b26f5b209b0660deb1a802a750012d Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Wed, 20 Jun 2018 13:55:20 +0200 Subject: [PATCH] bgpd: support for flowspec fragment list into policy routing The flowspec fragment attribute is taken into account to be pushed in BGP policy routing entries. Valid values are enumerate list of 1, 2, 4, or 8 values. no combined value is supported yet. Signed-off-by: Philippe Guibert --- bgpd/bgp_pbr.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++-- bgpd/bgp_pbr.h | 1 + bgpd/bgp_zebra.c | 1 + lib/pbr.h | 1 + 4 files changed, 91 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index 1fbc9826b2..6ab155573c 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -209,6 +209,7 @@ struct bgp_pbr_filter { struct bgp_pbr_val_mask *tcp_flags; struct bgp_pbr_val_mask *dscp; struct bgp_pbr_val_mask *pkt_len_val; + struct bgp_pbr_val_mask *fragment; }; /* this structure is used to contain OR instructions @@ -219,10 +220,14 @@ struct bgp_pbr_or_filter { struct list *tcpflags; struct list *dscp; struct list *pkt_len; + struct list *fragment; }; /* 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 + * - value is copied in bgp_pbr_val_mask->val value + * - if negate form is identifierd, bgp_pbr_val_mask->mask set to 1 */ static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[], int num, uint8_t unary_operator, @@ -258,7 +263,8 @@ static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[], TCP_HEADER_ALL_FLAGS & ~(list[i].value); } else if (type_entry == FLOWSPEC_DSCP || - type_entry == FLOWSPEC_PKT_LEN) { + type_entry == FLOWSPEC_PKT_LEN || + type_entry == FLOWSPEC_FRAGMENT) { and_valmask->val = list[i].value; and_valmask->mask = 1; /* inverse */ } @@ -271,6 +277,7 @@ static bool bgp_pbr_extract_enumerate_unary(struct bgp_pbr_match_val list[], TCP_HEADER_ALL_FLAGS & ~(list[i].value); } else if (type_entry == FLOWSPEC_DSCP || + type_entry == FLOWSPEC_FRAGMENT || type_entry == FLOWSPEC_PKT_LEN) { and_valmask->val = list[i].value; and_valmask->mask = 1; /* inverse */ @@ -293,6 +300,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_FRAGMENT || type_entry == FLOWSPEC_PKT_LEN) and_valmask->val = list[i].value; listnode_add(or_valmask, and_valmask); @@ -521,6 +529,40 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api) return 0; } } + if (api->match_fragment_num) { + char fail_str[64]; + bool success; + + success = bgp_pbr_extract_enumerate(api->fragment, + api->match_fragment_num, + OPERATOR_UNARY_OR + | OPERATOR_UNARY_AND, + NULL, FLOWSPEC_FRAGMENT); + if (success) { + int i; + + for (i = 0; i < api->match_fragment_num; i++) { + if (api->fragment[i].value != 1 && + api->fragment[i].value != 2 && + api->fragment[i].value != 4 && + api->fragment[i].value != 8) { + success = false; + sprintf(fail_str, + "Value not valid (%d) for this implementation", + api->fragment[i].value); + } + } + } else + sprintf(fail_str, "too complex. ignoring"); + if (!success) { + if (BGP_DEBUG(pbr, PBR)) + zlog_debug("BGP: match fragment operation (%d) %s", + api->match_fragment_num, + fail_str); + return 0; + } + } + /* no combinations with both src_port and dst_port * or port with src_port and dst_port */ @@ -768,6 +810,7 @@ uint32_t bgp_pbr_match_hash_key(void *arg) key = jhash_1word(pbm->tcp_flags, key); key = jhash_1word(pbm->tcp_mask_flags, key); key = jhash_1word(pbm->dscp_value, key); + key = jhash_1word(pbm->fragment, key); return jhash_1word(pbm->type, key); } @@ -804,6 +847,9 @@ int bgp_pbr_match_hash_equal(const void *arg1, const void *arg2) if (r1->dscp_value != r2->dscp_value) return 0; + + if (r1->fragment != r2->fragment) + return 0; return 1; } @@ -1291,6 +1337,11 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(struct bgp *bgp, temp.flags |= MATCH_DSCP_SET; temp.dscp_value = bpf->dscp->val; } + if (bpf->fragment) { + if (bpf->fragment->mask) + temp.flags |= MATCH_FRAGMENT_INVERSE_SET; + temp.fragment = bpf->fragment->val; + } if (bpf->src == NULL || bpf->dst == NULL) { if (temp.flags & (MATCH_PORT_DST_SET | MATCH_PORT_SRC_SET)) @@ -1351,9 +1402,13 @@ static void bgp_pbr_policyroute_remove_from_zebra_recursive(struct bgp *bgp, orig_list = bpof->dscp; target_val = &bpf->dscp; } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) { - next_type_entry = 0; + next_type_entry = FLOWSPEC_FRAGMENT; orig_list = bpof->pkt_len; target_val = &bpf->pkt_len_val; + } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) { + next_type_entry = 0; + orig_list = bpof->fragment; + target_val = &bpf->fragment; } else { return bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo, bpf, bpof, 0); @@ -1387,6 +1442,10 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp, bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo, bpf, bpof, FLOWSPEC_PKT_LEN); + else if (bpof->fragment) + bgp_pbr_policyroute_remove_from_zebra_recursive(bgp, binfo, + bpf, bpof, + FLOWSPEC_FRAGMENT); else bgp_pbr_policyroute_remove_from_zebra_unit(bgp, binfo, bpf); /* flush bpof */ @@ -1396,6 +1455,8 @@ static void bgp_pbr_policyroute_remove_from_zebra(struct bgp *bgp, list_delete_all_node(bpof->dscp); if (bpof->pkt_len) list_delete_all_node(bpof->pkt_len); + if (bpof->fragment) + list_delete_all_node(bpof->fragment); } static void bgp_pbr_policyroute_add_to_zebra_unit(struct bgp *bgp, @@ -1577,6 +1638,11 @@ 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->fragment) { + if (bpf->fragment->mask) + temp.flags |= MATCH_FRAGMENT_INVERSE_SET; + temp.fragment = bpf->fragment->val; + } temp.action = bpa; bpm = hash_get(bgp->pbr_match_hash, &temp, bgp_pbr_match_alloc_intern); @@ -1699,9 +1765,13 @@ static void bgp_pbr_policyroute_add_to_zebra_recursive(struct bgp *bgp, orig_list = bpof->dscp; target_val = &bpf->dscp; } else if (type_entry == FLOWSPEC_PKT_LEN && bpof->pkt_len) { - next_type_entry = 0; + next_type_entry = FLOWSPEC_FRAGMENT; orig_list = bpof->pkt_len; target_val = &bpf->pkt_len_val; + } else if (type_entry == FLOWSPEC_FRAGMENT && bpof->fragment) { + next_type_entry = 0; + orig_list = bpof->fragment; + target_val = &bpf->fragment; } else { return bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo, bpf, bpof, nh, rate, 0); @@ -1740,6 +1810,11 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp, bpf, bpof, nh, rate, FLOWSPEC_PKT_LEN); + else if (bpof->fragment) + bgp_pbr_policyroute_add_to_zebra_recursive(bgp, binfo, + bpf, bpof, + nh, rate, + FLOWSPEC_FRAGMENT); else bgp_pbr_policyroute_add_to_zebra_unit(bgp, binfo, bpf, nh, rate); @@ -1750,6 +1825,8 @@ static void bgp_pbr_policyroute_add_to_zebra(struct bgp *bgp, list_delete_all_node(bpof->dscp); if (bpof->pkt_len) list_delete_all_node(bpof->pkt_len); + if (bpof->fragment) + list_delete_all_node(bpof->fragment); } static const struct message icmp_code_unreach_str[] = { @@ -2018,6 +2095,14 @@ static void bgp_pbr_handle_entry(struct bgp *bgp, OPERATOR_UNARY_OR, bpof.dscp, FLOWSPEC_DSCP); } + if (api->match_fragment_num) { + bpof.fragment = list_new(); + bgp_pbr_extract_enumerate(api->fragment, + api->match_fragment_num, + OPERATOR_UNARY_OR, + bpof.fragment, + FLOWSPEC_FRAGMENT); + } bpf.vrf_id = api->vrf_id; bpf.src = src; bpf.dst = dst; diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h index d63d3c89c8..307a34e34f 100644 --- a/bgpd/bgp_pbr.h +++ b/bgpd/bgp_pbr.h @@ -185,6 +185,7 @@ struct bgp_pbr_match { uint16_t tcp_flags; uint16_t tcp_mask_flags; uint8_t dscp_value; + uint8_t fragment; vrf_id_t vrf_id; diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 9036bfbab6..87c9036147 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2238,6 +2238,7 @@ static void bgp_encode_pbr_iptable_match(struct stream *s, stream_putw(s, pbm->tcp_flags); stream_putw(s, pbm->tcp_mask_flags); stream_putc(s, pbm->dscp_value); + stream_putc(s, pbm->fragment); } /* BGP has established connection with Zebra. */ diff --git a/lib/pbr.h b/lib/pbr.h index 3da7aba23e..0c447e605b 100644 --- a/lib/pbr.h +++ b/lib/pbr.h @@ -109,6 +109,7 @@ struct pbr_rule { #define MATCH_DSCP_SET (1 << 6) #define MATCH_DSCP_INVERSE_SET (1 << 7) #define MATCH_PKT_LEN_INVERSE_SET (1 << 8) +#define MATCH_FRAGMENT_INVERSE_SET (1 << 9) extern int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule); -- 2.39.5