#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)
{
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);
+}
#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];
*/
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;
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__ */