#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_flowspec_private.h"
+#include "bgpd/bgp_pbr.h"
/* struct used to dump the rate contained in FS set traffic-rate EC */
union traffic_rate {
sizeof(struct ecommunity));
}
+void ecommunity_strfree(char **s)
+{
+ XFREE(MTYPE_ECOMMUNITY_STR, *s);
+}
+
/* Allocate ecommunities. */
void ecommunity_free(struct ecommunity **ecom)
{
if ((*ecom)->str)
XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str);
XFREE(MTYPE_ECOMMUNITY, *ecom);
- ecom = NULL;
}
static void ecommunity_hash_free(struct ecommunity *ecom)
}
/* Compare two Extended Communities Attribute structure. */
-int ecommunity_cmp(const void *arg1, const void *arg2)
+bool ecommunity_cmp(const void *arg1, const void *arg2)
{
const struct ecommunity *ecom1 = arg1;
const struct ecommunity *ecom2 = arg2;
if (ecom1 == NULL && ecom2 == NULL)
- return 1;
+ return true;
if (ecom1 == NULL || ecom2 == NULL)
- return 0;
+ return false;
return (ecom1->size == ecom2->size
&& memcmp(ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE)
{
int i;
uint8_t *pnt;
- int type = 0;
- int sub_type = 0;
-#define ECOMMUNITY_STR_DEFAULT_LEN 27
+ uint8_t type = 0;
+ uint8_t sub_type = 0;
+#define ECOMMUNITY_STR_DEFAULT_LEN 64
int str_size;
int str_pnt;
char *str_buf;
else
len = sprintf(str_buf + str_pnt,
"MM:%u", seqnum);
+ } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_ND) {
+ uint8_t flags = *++pnt;
+
+ if (flags
+ & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG)
+ len = sprintf(str_buf + str_pnt,
+ "ND:Router Flag");
} else
unk_ecom = 1;
} else if (type == ECOMMUNITY_ENCODE_REDIRECT_IP_NH) {
"FS:redirect IP 0x%x", *(pnt+5));
} else
unk_ecom = 1;
- } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP) {
+ } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP ||
+ type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
+ type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_3) {
sub_type = *pnt++;
+ if (sub_type == ECOMMUNITY_REDIRECT_VRF) {
+ char buf[16];
- if (sub_type == ECOMMUNITY_TRAFFIC_ACTION) {
+ memset(buf, 0, sizeof(buf));
+ ecommunity_rt_soo_str(buf, (uint8_t *)pnt,
+ type &
+ ~ECOMMUNITY_ENCODE_TRANS_EXP,
+ ECOMMUNITY_ROUTE_TARGET,
+ ECOMMUNITY_FORMAT_DISPLAY);
+ len = snprintf(str_buf + str_pnt,
+ str_size - len,
+ "FS:redirect VRF %s", buf);
+ } else if (type != ECOMMUNITY_ENCODE_TRANS_EXP)
+ unk_ecom = 1;
+ else if (sub_type == ECOMMUNITY_TRAFFIC_ACTION) {
char action[64];
char *ptr = action;
len = sprintf(
str_buf + str_pnt,
"FS:rate %f", data.rate_float);
- } else if (sub_type == ECOMMUNITY_REDIRECT_VRF) {
- char buf[16];
-
- memset(buf, 0, sizeof(buf));
- ecommunity_rt_soo_str(buf, (uint8_t *)pnt,
- type &
- ~ECOMMUNITY_ENCODE_TRANS_EXP,
- ECOMMUNITY_ROUTE_TARGET,
- ECOMMUNITY_FORMAT_DISPLAY);
- len = snprintf(
- str_buf + str_pnt,
- str_size - len,
- "FS:redirect VRF %s", buf);
} else if (sub_type == ECOMMUNITY_TRAFFIC_MARKING) {
len = sprintf(
str_buf + str_pnt,
"FS:marking %u", *(pnt+5));
+ } else if (*pnt
+ == ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT) {
+ struct ethaddr mac;
+
+ pnt++;
+ memcpy(&mac, pnt, ETH_ALEN);
+ len = sprintf(
+ str_buf + str_pnt,
+ "ES-Import-Rt:%02x:%02x:%02x:%02x:%02x:%02x",
+ (uint8_t)mac.octet[0],
+ (uint8_t)mac.octet[1],
+ (uint8_t)mac.octet[2],
+ (uint8_t)mac.octet[3],
+ (uint8_t)mac.octet[4],
+ (uint8_t)mac.octet[5]);
} else
unk_ecom = 1;
- } else
+ } else {
+ sub_type = *pnt++;
unk_ecom = 1;
+ }
if (unk_ecom)
- len = sprintf(str_buf + str_pnt, "?");
+ len = sprintf(str_buf + str_pnt, "UNK:%d, %d",
+ type, sub_type);
str_pnt += len;
first = 0;
ecom->val = p;
return 1;
}
+
+int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
+ struct bgp_pbr_entry_action *api)
+{
+ if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_RATE) {
+ api->action = ACTION_TRAFFICRATE;
+ api->u.r.rate_info[3] = ecom_eval->val[4];
+ api->u.r.rate_info[2] = ecom_eval->val[5];
+ api->u.r.rate_info[1] = ecom_eval->val[6];
+ api->u.r.rate_info[0] = ecom_eval->val[7];
+ } else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_ACTION) {
+ api->action = ACTION_TRAFFIC_ACTION;
+ /* else distribute code is set by default */
+ if (ecom_eval->val[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL))
+ api->u.za.filter |= TRAFFIC_ACTION_TERMINATE;
+ else
+ api->u.za.filter |= TRAFFIC_ACTION_DISTRIBUTE;
+ if (ecom_eval->val[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE)
+ api->u.za.filter |= TRAFFIC_ACTION_SAMPLE;
+
+ } else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_MARKING) {
+ api->action = ACTION_MARKING;
+ api->u.marking_dscp = ecom_eval->val[7];
+ } else if (ecom_eval->val[1] == ECOMMUNITY_REDIRECT_VRF) {
+ /* must use external function */
+ return 0;
+ } else if (ecom_eval->val[1] == ECOMMUNITY_REDIRECT_IP_NH) {
+ /* see draft-ietf-idr-flowspec-redirect-ip-02
+ * Q1: how come a ext. community can host ipv6 address
+ * Q2 : from cisco documentation:
+ * Announces the reachability of one or more flowspec NLRI.
+ * When a BGP speaker receives an UPDATE message with the
+ * redirect-to-IP extended community, it is expected to
+ * create a traffic filtering rule for every flow-spec
+ * NLRI in the message that has this path as its best
+ * path. The filter entry matches the IP packets
+ * described in the NLRI field and redirects them or
+ * copies them towards the IPv4 or IPv6 address specified
+ * in the 'Network Address of Next- Hop'
+ * field of the associated MP_REACH_NLRI.
+ */
+ struct ecommunity_ip *ip_ecom = (struct ecommunity_ip *)
+ ecom_eval + 2;
+
+ api->u.zr.redirect_ip_v4 = ip_ecom->ip;
+ } else
+ return -1;
+ return 0;
+}