]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: support for flowspec fragment list into policy routing
authorPhilippe Guibert <philippe.guibert@6wind.com>
Wed, 20 Jun 2018 11:55:20 +0000 (13:55 +0200)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Mon, 2 Jul 2018 07:20:40 +0000 (09:20 +0200)
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 <philippe.guibert@6wind.com>
bgpd/bgp_pbr.c
bgpd/bgp_pbr.h
bgpd/bgp_zebra.c
lib/pbr.h

index 1fbc9826b2946c0aeb5fc1b0aa1f21b43a4c482d..6ab155573c18d1926fa7e8849f87a63761f27107 100644 (file)
@@ -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;
index d63d3c89c8f7125b9d9786bff8370c8216589c9c..307a34e34f4c02749f49604601b0cc90b9151532 100644 (file)
@@ -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;
 
index 9036bfbab6229bf9c73cea4fb50b46cb6d5d18b1..87c9036147674f2a8ba6bebae046306133e052fe 100644 (file)
@@ -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. */
index 3da7aba23e2cdec17448be17e425e232d173df45..0c447e605be56176c8d0e5e9ddddba9341822994 100644 (file)
--- 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);