summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_pbr.c130
-rw-r--r--bgpd/bgp_pbr.h7
-rw-r--r--bgpd/bgp_route.c2
3 files changed, 138 insertions, 1 deletions
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index 87c8851ca5..672bb0bd58 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -25,6 +25,10 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_pbr.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_flowspec_util.h"
+#include "bgpd/bgp_ecommunity.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
static int sprintf_bgp_pbr_match_val(char *str, struct bgp_pbr_match_val *mval,
const char *prepend)
@@ -88,6 +92,108 @@ static int bgp_pbr_validate_policy_route(struct bgp_pbr_entry_main *api)
return 1;
}
+/* return -1 if build or validation failed */
+static int bgp_pbr_build_and_validate_entry(struct prefix *p,
+ struct bgp_info *info,
+ struct bgp_pbr_entry_main *api)
+{
+ int ret;
+ int i, action_count = 0;
+ struct ecommunity *ecom;
+ struct ecommunity_val *ecom_eval;
+ struct bgp_pbr_entry_action *api_action;
+ struct prefix *src = NULL, *dst = NULL;
+ int valid_prefix = 0;
+ afi_t afi = AFI_IP;
+
+ /* extract match from flowspec entries */
+ ret = bgp_flowspec_match_rules_fill((uint8_t *)p->u.prefix_flowspec.ptr,
+ p->u.prefix_flowspec.prefixlen, api);
+ if (ret < 0)
+ return -1;
+ /* extract actiosn from flowspec ecom list */
+ if (info && info->attr && info->attr->ecommunity) {
+ ecom = info->attr->ecommunity;
+ for (i = 0; i < ecom->size; i++) {
+ ecom_eval = (struct ecommunity_val *)
+ ecom->val + (i * ECOMMUNITY_SIZE);
+
+ if (action_count > ACTIONS_MAX_NUM) {
+ zlog_err("%s: flowspec actions exceeds limit (max %u)",
+ __func__, action_count);
+ break;
+ }
+ api_action = &api->actions[action_count];
+
+ if ((ecom_eval->val[1] ==
+ (char)ECOMMUNITY_REDIRECT_VRF) &&
+ (ecom_eval->val[0] ==
+ (char)ECOMMUNITY_ENCODE_TRANS_EXP ||
+ ecom_eval->val[0] ==
+ (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
+ ecom_eval->val[0] ==
+ (char)ECOMMUNITY_EXTENDED_COMMUNITY_PART_3)) {
+ struct ecommunity *eckey = ecommunity_new();
+ struct ecommunity_val ecom_copy;
+
+ memcpy(&ecom_copy, ecom_eval,
+ sizeof(struct ecommunity_val));
+ ecom_copy.val[0] &=
+ ~ECOMMUNITY_ENCODE_TRANS_EXP;
+ ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
+ ecommunity_add_val(eckey, &ecom_copy);
+
+ api_action->action = ACTION_REDIRECT;
+ api_action->u.redirect_vrf =
+ get_first_vrf_for_redirect_with_rt(
+ eckey);
+ ecommunity_free(&eckey);
+ } else if ((ecom_eval->val[0] ==
+ (char)ECOMMUNITY_ENCODE_REDIRECT_IP_NH) &&
+ (ecom_eval->val[1] ==
+ (char)ECOMMUNITY_REDIRECT_IP_NH)) {
+ api_action->action = ACTION_REDIRECT_IP;
+ api_action->u.zr.redirect_ip_v4.s_addr =
+ info->attr->nexthop.s_addr;
+ api_action->u.zr.duplicate = ecom_eval->val[7];
+ } else {
+ if (ecom_eval->val[0] !=
+ (char)ECOMMUNITY_ENCODE_TRANS_EXP)
+ continue;
+ ret = ecommunity_fill_pbr_action(ecom_eval,
+ api_action);
+ if (ret != 0)
+ continue;
+ }
+ api->action_num++;
+ }
+ }
+
+ /* validate if incoming matc/action is compatible
+ * with our policy routing engine
+ */
+ if (!bgp_pbr_validate_policy_route(api))
+ return -1;
+
+ /* check inconsistency in the match rule */
+ if (api->match_bitmask & PREFIX_SRC_PRESENT) {
+ src = &api->src_prefix;
+ afi = family2afi(src->family);
+ valid_prefix = 1;
+ }
+ if (api->match_bitmask & PREFIX_DST_PRESENT) {
+ dst = &api->dst_prefix;
+ if (valid_prefix && afi != family2afi(dst->family)) {
+ if (BGP_DEBUG(pbr, PBR))
+ bgp_pbr_print_policy_route(api);
+ zlog_err("%s: inconsistency: no match for afi src and dst (%u/%u)",
+ __func__, afi, family2afi(dst->family));
+ return -1;
+ }
+ }
+ return 0;
+}
+
uint32_t bgp_pbr_match_hash_key(void *arg)
{
struct bgp_pbr_match *pbm = (struct bgp_pbr_match *)arg;
@@ -354,3 +460,27 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
}
zlog_info("%s", return_string);
}
+
+void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
+ struct bgp_info *info, afi_t afi, safi_t safi,
+ bool nlri_update)
+{
+ struct bgp_pbr_entry_main api;
+
+ if (afi == AFI_IP6)
+ return; /* IPv6 not supported */
+ if (safi != SAFI_FLOWSPEC)
+ return; /* not supported */
+ /* Make Zebra API structure. */
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = bgp->vrf_id;
+ api.afi = afi;
+
+ if (bgp_pbr_build_and_validate_entry(p, info, &api) < 0) {
+ zlog_err("%s: cancel updating entry in bgp pbr",
+ __func__);
+ return;
+ }
+ /* TODO. update prefix and pbr hash contexts */
+}
+
diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h
index 6ed8b297d5..1fb1b0cccc 100644
--- a/bgpd/bgp_pbr.h
+++ b/bgpd/bgp_pbr.h
@@ -241,4 +241,11 @@ extern int bgp_pbr_match_hash_equal(const void *arg1,
void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api);
+struct bgp_node;
+struct bgp_info;
+extern void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
+ struct bgp_info *new_select,
+ afi_t afi, safi_t safi,
+ bool nlri_update);
+
#endif /* __BGP_PBR_H__ */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 90fa39b445..06670d10dd 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -75,6 +75,7 @@
#include "bgpd/bgp_evpn_vty.h"
#include "bgpd/bgp_flowspec.h"
#include "bgpd/bgp_flowspec_util.h"
+#include "bgpd/bgp_pbr.h"
#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_route_clippy.c"
@@ -2229,7 +2230,6 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
/* If best route remains the same and this is not due to user-initiated
* clear, see exactly what needs to be done.
*/
-
if (old_select && old_select == new_select
&& !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)
&& !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED)