]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_ecommunity.c
bgpd isisd lib: fix return on void functions
[mirror_frr.git] / bgpd / bgp_ecommunity.c
index 80166dd32bed22410d7f304c4c89340bf6ce14a8..8029164184fe46d566e2967c32a1be210d8c8f4b 100644 (file)
@@ -34,6 +34,7 @@
 #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 {
@@ -51,6 +52,11 @@ struct ecommunity *ecommunity_new(void)
                                            sizeof(struct ecommunity));
 }
 
+void ecommunity_strfree(char **s)
+{
+       XFREE(MTYPE_ECOMMUNITY_STR, *s);
+}
+
 /* Allocate ecommunities.  */
 void ecommunity_free(struct ecommunity **ecom)
 {
@@ -59,7 +65,6 @@ 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)
@@ -248,16 +253,16 @@ unsigned int ecommunity_hash_make(void *arg)
 }
 
 /* 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)
@@ -636,9 +641,9 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
 {
        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;
@@ -734,6 +739,13 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                                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) {
@@ -744,10 +756,25 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                                        "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;
 
@@ -776,30 +803,35 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                                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;
@@ -895,3 +927,88 @@ extern int ecommunity_strip(struct ecommunity *ecom, uint8_t type,
        ecom->val = p;
        return 1;
 }
+
+/*
+ * Remove specified extended community value from extended community.
+ * Returns 1 if value was present (and hence, removed), 0 otherwise.
+ */
+int ecommunity_del_val(struct ecommunity *ecom, struct ecommunity_val *eval)
+{
+       uint8_t *p;
+       int c, found = 0;
+
+       /* Make sure specified value exists. */
+       if (ecom == NULL || ecom->val == NULL)
+               return 0;
+       c = 0;
+       for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) {
+               if (!memcmp(p, eval->val, ECOMMUNITY_SIZE)) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (found == 0)
+               return 0;
+
+       /* Delete the selected value */
+       ecom->size--;
+       p = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
+       if (c != 0)
+               memcpy(p, ecom->val, c * ECOMMUNITY_SIZE);
+       if ((ecom->size - c) != 0)
+               memcpy(p + (c)*ECOMMUNITY_SIZE,
+                      ecom->val + (c + 1) * ECOMMUNITY_SIZE,
+                      (ecom->size - c) * ECOMMUNITY_SIZE);
+       XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
+       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;
+}