]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: add bgp_pbr_route structure
authorPhilippe Guibert <philippe.guibert@6wind.com>
Thu, 8 Mar 2018 16:41:15 +0000 (17:41 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Mon, 30 Apr 2018 09:56:23 +0000 (11:56 +0200)
This structure is the model exchange between some bgp services like
flowspec and the policy routing service. This structure reflects what
the nlri entry means. To handle that structure, a dump routine is made
available. Also, a validation function is here to cancel a policy route
installation, whenever it is not possible to install the requested
policy routing.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
bgpd/bgp_pbr.c
bgpd/bgp_pbr.h

index e11a7e889bb2ff43e082ca65b966379da0d374b3..87c8851ca51a90e2a38967c6fcd10b4a05b8268b 100644 (file)
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_pbr.h"
+#include "bgpd/bgp_debug.h"
+
+static int sprintf_bgp_pbr_match_val(char *str, struct bgp_pbr_match_val *mval,
+                                    const char *prepend)
+{
+       char *ptr = str;
+
+       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);
+       return (int)(ptr - str);
+}
+
+#define INCREMENT_DISPLAY(_ptr, _cnt) do { \
+               if (_cnt) \
+                       (_ptr) += sprintf((_ptr), "; "); \
+               _cnt++; \
+       } while (0)
+
+/* return 1 if OK, 0 if validation should stop) */
+static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
+{
+       /* because bgp pbr entry may contain unsupported
+        * combinations, a message will be displayed here if
+        * not supported.
+        * for now, only match/set supported is
+        * - combination src/dst => redirect nexthop [ + rate]
+        * - combination src/dst => redirect VRF [ + rate]
+        * - combination src/dst => drop
+        */
+       if (api->match_src_port_num || api->match_dst_port_num
+           || api->match_port_num || api->match_protocol_num
+           || api->match_icmp_type_num || api->match_icmp_type_num
+           || api->match_packet_length_num || api->match_dscp_num
+           || api->match_tcpflags_num) {
+               if (BGP_DEBUG(pbr, PBR))
+                       bgp_pbr_print_policy_route(api);
+               zlog_err("BGP: some SET actions not supported by Zebra. ignoring.");
+               return 0;
+       }
+       if (!(api->match_bitmask & PREFIX_SRC_PRESENT) &&
+           !(api->match_bitmask & PREFIX_DST_PRESENT)) {
+               if (BGP_DEBUG(pbr, PBR))
+                       bgp_pbr_print_policy_route(api);
+               zlog_err("BGP: SET actions without src or dst address can not operate. ignoring.");
+               return 0;
+       }
+       return 1;
+}
 
 uint32_t bgp_pbr_match_hash_key(void *arg)
 {
@@ -156,3 +219,138 @@ void bgp_pbr_init(struct bgp *bgp)
                                 bgp_pbr_action_hash_equal,
                                 "Match Hash Entry");
 }
+
+void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
+{
+       int i = 0;
+       char return_string[512];
+       char *ptr = return_string;
+       char buff[64];
+       int nb_items = 0;
+
+       ptr += sprintf(ptr, "MATCH : ");
+       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->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));
+       }
+
+       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 ");
+
+       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 ");
+
+       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 ");
+
+       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 ");
+
+       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 ");
+
+       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 ");
+
+       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 ");
+
+       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 ");
+
+       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 ");
+
+       if (api->match_bitmask & FRAGMENT_PRESENT) {
+               INCREMENT_DISPLAY(ptr, nb_items);
+               ptr += sprintf(ptr, "@fragment %u", api->fragment.bitmask);
+       }
+       if (!nb_items)
+               ptr = return_string;
+       else
+               ptr += sprintf(ptr, "; ");
+       if (api->action_num)
+               ptr += sprintf(ptr, "SET : ");
+       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);
+                       break;
+               case ACTION_TRAFFIC_ACTION:
+                       INCREMENT_DISPLAY(ptr, nb_items);
+                       ptr += sprintf(ptr, "@action ");
+                       if (api->actions[i].u.za.filter
+                           & TRAFFIC_ACTION_TERMINATE)
+                               ptr += sprintf(ptr,
+                                              " terminate (apply filter(s))");
+                       if (api->actions[i].u.za.filter
+                           & TRAFFIC_ACTION_DISTRIBUTE)
+                               ptr += sprintf(ptr, " distribute");
+                       if (api->actions[i].u.za.filter
+                           & TRAFFIC_ACTION_SAMPLE)
+                               ptr += sprintf(ptr, " sample");
+                       break;
+               case ACTION_REDIRECT_IP:
+                       INCREMENT_DISPLAY(ptr, nb_items);
+                       char local_buff[INET_ADDRSTRLEN];
+
+                       if (inet_ntop(AF_INET,
+                                     &api->actions[i].u.zr.redirect_ip_v4,
+                                     local_buff, INET_ADDRSTRLEN) != NULL)
+                               ptr += sprintf(ptr,
+                                         "@redirect ip nh %s", local_buff);
+                       break;
+               case ACTION_REDIRECT:
+                       INCREMENT_DISPLAY(ptr, nb_items);
+                       ptr += sprintf(ptr, "@redirect vrf %u",
+                                      api->actions[i].u.redirect_vrf);
+                       break;
+               case ACTION_MARKING:
+                       INCREMENT_DISPLAY(ptr, nb_items);
+                       ptr += sprintf(ptr, "@set dscp %u",
+                                 api->actions[i].u.marking_dscp);
+                       break;
+               default:
+                       break;
+               }
+       }
+       zlog_info("%s", return_string);
+}
index 62fe7aa4fb329f8b8607c1c4ae152c1633ac946a..6ed8b297d51444114a07da5bc98a88383c78f2f0 100644 (file)
 #include "nexthop.h"
 #include "zclient.h"
 
+/* flowspec case: 0 to 3 actions maximum:
+ * 1 redirect
+ * 1 set dscp
+ * 1 set traffic rate
+ */
+#define ACTIONS_MAX_NUM 4
+enum bgp_pbr_action_enum {
+       ACTION_TRAFFICRATE = 1,
+       ACTION_TRAFFIC_ACTION = 2,
+       ACTION_REDIRECT = 3,
+       ACTION_MARKING = 4,
+       ACTION_REDIRECT_IP = 5
+};
+
+#define TRAFFIC_ACTION_SAMPLE     (1 << 0)
+#define TRAFFIC_ACTION_TERMINATE  (1 << 1)
+#define TRAFFIC_ACTION_DISTRIBUTE (1 << 2)
+
+#define OPERATOR_COMPARE_LESS_THAN    (1<<1)
+#define OPERATOR_COMPARE_GREATER_THAN (1<<2)
+#define OPERATOR_COMPARE_EQUAL_TO     (1<<3)
+#define OPERATOR_COMPARE_EXACT_MATCH  (1<<4)
+
+#define OPERATOR_UNARY_OR    (1<<1)
+#define OPERATOR_UNARY_AND   (1<<2)
+
+/* struct used to store values [0;65535]
+ * this can be used for port number of protocol
+ */
+#define BGP_PBR_MATCH_VAL_MAX 5
+
+struct bgp_pbr_match_val {
+       uint16_t value;
+       uint8_t compare_operator;
+       uint8_t unary_operator;
+} bgp_pbr_value_t;
+
+#define FRAGMENT_DONT  1
+#define FRAGMENT_IS    2
+#define FRAGMENT_FIRST 4
+#define FRAGMENT_LAST  8
+
+struct bgp_pbr_fragment_val {
+       uint8_t bitmask;
+};
+
+struct bgp_pbr_entry_action {
+       /* used to store enum bgp_pbr_action_enum enumerate */
+       uint8_t action;
+       union {
+               union {
+                       uint8_t rate_info[4]; /* IEEE.754.1985 */
+                       float rate;
+               } r __attribute__((aligned(8)));
+               struct _pbr_action {
+                       uint8_t do_sample;
+                       uint8_t filter;
+               } za;
+               vrf_id_t redirect_vrf;
+               struct _pbr_redirect_ip {
+                       struct in_addr redirect_ip_v4;
+                       uint8_t duplicate;
+               } zr;
+               uint8_t marking_dscp;
+       } u __attribute__((aligned(8)));
+};
+
+/* BGP Policy Route structure */
+struct bgp_pbr_entry_main {
+       uint8_t type;
+       uint16_t instance;
+
+       uint32_t flags;
+
+       uint8_t message;
+
+       /*
+        * This is an enum but we are going to treat it as a uint8_t
+        * for purpose of encoding/decoding
+        */
+       afi_t afi;
+       safi_t safi;
+
+#define PREFIX_SRC_PRESENT (1 << 0)
+#define PREFIX_DST_PRESENT (1 << 1)
+#define FRAGMENT_PRESENT   (1 << 2)
+       uint8_t match_bitmask;
+
+       uint8_t match_src_port_num;
+       uint8_t match_dst_port_num;
+       uint8_t match_port_num;
+       uint8_t match_protocol_num;
+       uint8_t match_icmp_type_num;
+       uint8_t match_icmp_code_num;
+       uint8_t match_packet_length_num;
+       uint8_t match_dscp_num;
+       uint8_t match_tcpflags_num;
+
+       struct prefix src_prefix;
+       struct prefix dst_prefix;
+
+       struct bgp_pbr_match_val protocol[BGP_PBR_MATCH_VAL_MAX];
+       struct bgp_pbr_match_val src_port[BGP_PBR_MATCH_VAL_MAX];
+       struct bgp_pbr_match_val dst_port[BGP_PBR_MATCH_VAL_MAX];
+       struct bgp_pbr_match_val port[BGP_PBR_MATCH_VAL_MAX];
+       struct bgp_pbr_match_val icmp_type[BGP_PBR_MATCH_VAL_MAX];
+       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 tcpflags[BGP_PBR_MATCH_VAL_MAX];
+       struct bgp_pbr_fragment_val fragment;
+
+       uint16_t action_num;
+       struct bgp_pbr_entry_action actions[ACTIONS_MAX_NUM];
+
+       uint8_t distance;
+
+       uint32_t metric;
+
+       route_tag_t tag;
+
+       uint32_t mtu;
+
+       vrf_id_t vrf_id;
+};
+
 struct bgp_pbr_match {
        char ipset_name[ZEBRA_IPSET_NAME_SIZE];
 
@@ -29,8 +155,8 @@ struct bgp_pbr_match {
         */
        uint32_t type;
 
-#define MATCH_IP_SRC_SET    1 << 0
-#define MATCH_IP_DST_SET    1 << 1
+#define MATCH_IP_SRC_SET               (1 << 0)
+#define MATCH_IP_DST_SET               (1 << 1)
        uint32_t flags;
 
        vrf_id_t vrf_id;
@@ -113,4 +239,6 @@ extern uint32_t bgp_pbr_match_hash_key(void *arg);
 extern int bgp_pbr_match_hash_equal(const void *arg1,
                                    const void *arg2);
 
+void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api);
+
 #endif /* __BGP_PBR_H__ */