]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_attr_evpn.c
bgpd: Allow shortened 'no set large-community' and 'no set large-comm-list'
[mirror_frr.git] / bgpd / bgp_attr_evpn.c
index 5b24d4ec61318909f40d2ef0117afa8abbdabac3..88e520fdc508c24de4fdd1014124cd9cf3dee105 100644 (file)
@@ -1,22 +1,22 @@
 /* Ethernet-VPN Attribute handling file
  Copyright (C) 2016 6WIND
-
-This file is part of FRRouting.
-
-FRRouting is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
-
-FRRouting is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with FRRouting; see the file COPYING.  If not, write to the Free
-Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
* Copyright (C) 2016 6WIND
+ *
+ * This file is part of FRRouting.
+ *
+ * FRRouting is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRRouting is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
 
 #include <zebra.h>
 
@@ -33,21 +33,20 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include "bgpd/bgp_attr_evpn.h"
 #include "bgpd/bgp_ecommunity.h"
 #include "bgpd/bgp_evpn.h"
+#include "bgpd/bgp_evpn_private.h"
 
 void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac)
 {
        struct ecommunity_val routermac_ecom;
 
-       if (attr->extra) {
-               memset(&routermac_ecom, 0, sizeof(struct ecommunity_val));
-               routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN;
-               routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC;
-               memcpy(&routermac_ecom.val[2], routermac->octet, ETHER_ADDR_LEN);
-               if (!attr->extra->ecommunity)
-                       attr->extra->ecommunity = ecommunity_new();
-               ecommunity_add_val(attr->extra->ecommunity, &routermac_ecom);
-               ecommunity_str (attr->extra->ecommunity);
-       }
+       memset(&routermac_ecom, 0, sizeof(struct ecommunity_val));
+       routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN;
+       routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC;
+       memcpy(&routermac_ecom.val[2], routermac->octet, ETH_ALEN);
+       if (!attr->ecommunity)
+               attr->ecommunity = ecommunity_new();
+       ecommunity_add_val(attr->ecommunity, &routermac_ecom);
+       ecommunity_str(attr->ecommunity);
 }
 
 /* converts to an esi
@@ -62,10 +61,9 @@ int str2esi(const char *str, struct eth_segment_id *id)
 
        if (!str)
                return 0;
-       if (sscanf (str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x",
-                    a + 0, a + 1, a + 2, a + 3, a + 4, a + 5,
-                    a + 6, a + 7, a + 8, a + 9) != ESI_LEN)
-       {
+       if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x", a + 0, a + 1,
+                  a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9)
+           != ESI_LEN) {
                /* error in incoming str length */
                return 0;
        }
@@ -80,18 +78,19 @@ int str2esi(const char *str, struct eth_segment_id *id)
 char *esi2str(struct eth_segment_id *id)
 {
        char *ptr;
-       u_char *val;
+       uint8_t *val;
 
        if (!id)
                return NULL;
 
        val = id->val;
-       ptr = (char *)XMALLOC(MTYPE_TMP, (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char));
+       ptr = (char *)XMALLOC(MTYPE_TMP,
+                             (ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char));
 
        snprintf(ptr, (ESI_LEN * 2 + ESI_LEN - 1 + 1),
-                "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
-                val[0], val[1], val[2], val[3], val[4],
-                val[5], val[6], val[7], val[8], val[9]);
+                "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", val[0],
+                val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8],
+                val[9]);
 
        return ptr;
 }
@@ -102,12 +101,151 @@ char *ecom_mac2str(char *ecom_mac)
 
        en = ecom_mac;
        en += 2;
-        return prefix_mac2str((struct ethaddr *)en, NULL, 0);
+
+       return prefix_mac2str((struct ethaddr *)en, NULL, 0);
+}
+
+/* Fetch router-mac from extended community */
+void bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
+{
+       int i = 0;
+       struct ecommunity *ecom;
+
+       ecom = attr->ecommunity;
+       if (!ecom || !ecom->size)
+               return;
+
+       /* If there is a router mac extended community, set RMAC in attr */
+       for (i = 0; i < ecom->size; i++) {
+               uint8_t *pnt = NULL;
+               uint8_t type = 0;
+               uint8_t sub_type = 0;
+
+               pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
+               type = *pnt++;
+               sub_type = *pnt++;
+
+               if (!(type == ECOMMUNITY_ENCODE_EVPN
+                     && sub_type == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC))
+                       continue;
+
+               memcpy(rmac, pnt, ETH_ALEN);
+       }
+}
+
+/*
+ * return true if attr contains default gw extended community
+ */
+uint8_t bgp_attr_default_gw(struct attr *attr)
+{
+       struct ecommunity *ecom;
+       int i;
+
+       ecom = attr->ecommunity;
+       if (!ecom || !ecom->size)
+               return 0;
+
+       /* If there is a default gw extendd community return true otherwise
+        * return 0 */
+       for (i = 0; i < ecom->size; i++) {
+               uint8_t *pnt;
+               uint8_t type, sub_type;
+
+               pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
+               type = *pnt++;
+               sub_type = *pnt++;
+
+               if ((type == ECOMMUNITY_ENCODE_OPAQUE
+                    && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
+                       return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Fetch and return the sequence number from MAC Mobility extended
+ * community, if present, else 0.
+ */
+uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
+{
+       struct ecommunity *ecom;
+       int i;
+       uint8_t flags = 0;
+
+       ecom = attr->ecommunity;
+       if (!ecom || !ecom->size)
+               return 0;
+
+       /* If there is a MAC Mobility extended community, return its
+        * sequence number.
+        * TODO: RFC is silent on handling of multiple MAC mobility extended
+        * communities for the same route. We will bail out upon the first
+        * one.
+        */
+       for (i = 0; i < ecom->size; i++) {
+               uint8_t *pnt;
+               uint8_t type, sub_type;
+               uint32_t seq_num;
+
+               pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
+               type = *pnt++;
+               sub_type = *pnt++;
+               if (!(type == ECOMMUNITY_ENCODE_EVPN
+                     && sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY))
+                       continue;
+               flags = *pnt++;
+
+               if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
+                       *sticky = 1;
+               else
+                       *sticky = 0;
+
+               pnt++;
+               pnt = ptr_get_be32(pnt, &seq_num);
+               (void)pnt; /* consume value */
+               return seq_num;
+       }
+
+       return 0;
+}
+
+/*
+ * return true if attr contains router flag extended community
+ */
+void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag)
+{
+       struct ecommunity *ecom;
+       int i;
+       uint8_t val;
+
+       ecom = attr->ecommunity;
+       if (!ecom || !ecom->size)
+               return;
+
+       /* If there is a evpn na extendd community set router_flag */
+       for (i = 0; i < ecom->size; i++) {
+               uint8_t *pnt;
+               uint8_t type, sub_type;
+
+               pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
+               type = *pnt++;
+               sub_type = *pnt++;
+
+               if (type == ECOMMUNITY_ENCODE_EVPN &&
+                   sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) {
+                       val = *pnt++;
+                       if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG) {
+                               *router_flag = 1;
+                               break;
+                       }
+               }
+       }
 }
 
 /* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */
-extern int
-bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, struct prefix *dst)
+extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag,
+                                struct prefix *dst)
 {
        struct evpn_addr *p_evpn_p;
        struct prefix p2;
@@ -119,21 +257,23 @@ bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, struct prefix *dst)
        prefix_copy(src, dst);
        memset(dst, 0, sizeof(struct prefix));
        p_evpn_p = &(dst->u.prefix_evpn);
-       dst->family = AF_ETHERNET;
+       dst->family = AF_EVPN;
        p_evpn_p->route_type = evpn_type;
-       if (evpn_type == EVPN_IP_PREFIX) {
-               p_evpn_p->eth_tag = eth_tag;
-               p_evpn_p->ip_prefix_length = p2.prefixlen;
+       if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) {
+               p_evpn_p->prefix_addr.eth_tag = eth_tag;
+               p_evpn_p->prefix_addr.ip_prefix_length = p2.prefixlen;
                if (src->family == AF_INET) {
-                       p_evpn_p->flags = IP_PREFIX_V4;
-                       memcpy(&p_evpn_p->ip.v4_addr, &src->u.prefix4,
+                       SET_IPADDR_V4(&p_evpn_p->prefix_addr.ip);
+                       memcpy(&p_evpn_p->prefix_addr.ip.ipaddr_v4,
+                              &src->u.prefix4,
                               sizeof(struct in_addr));
-                       dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4;
+                       dst->prefixlen = (uint8_t)PREFIX_LEN_ROUTE_TYPE_5_IPV4;
                } else {
-                       p_evpn_p->flags = IP_PREFIX_V6;
-                       memcpy(&p_evpn_p->ip.v6_addr, &src->u.prefix6,
+                       SET_IPADDR_V6(&p_evpn_p->prefix_addr.ip);
+                       memcpy(&p_evpn_p->prefix_addr.ip.ipaddr_v6,
+                              &src->u.prefix6,
                               sizeof(struct in6_addr));
-                       dst->prefixlen = (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV6;
+                       dst->prefixlen = (uint8_t)PREFIX_LEN_ROUTE_TYPE_5_IPV6;
                }
        } else
                return -1;