back to topotato report
topotato coverage report
Current view: top level - bgpd - bgp_ecommunity.c (source / functions) Hit Total Coverage
Test: test_bgp_set_aspath_replace.py::BGPSetAspathReplace Lines: 13 781 1.7 %
Date: 2023-02-24 18:37:49 Functions: 4 48 8.3 %

          Line data    Source code
       1             : /* BGP Extended Communities Attribute
       2             :  * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
       3             :  *
       4             :  * This file is part of GNU Zebra.
       5             :  *
       6             :  * GNU Zebra is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the
       8             :  * Free Software Foundation; either version 2, or (at your option) any
       9             :  * later version.
      10             :  *
      11             :  * GNU Zebra is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include "hash.h"
      24             : #include "memory.h"
      25             : #include "prefix.h"
      26             : #include "command.h"
      27             : #include "queue.h"
      28             : #include "filter.h"
      29             : #include "jhash.h"
      30             : #include "stream.h"
      31             : 
      32             : #include "lib/printfrr.h"
      33             : 
      34             : #include "bgpd/bgpd.h"
      35             : #include "bgpd/bgp_ecommunity.h"
      36             : #include "bgpd/bgp_lcommunity.h"
      37             : #include "bgpd/bgp_aspath.h"
      38             : #include "bgpd/bgp_flowspec_private.h"
      39             : #include "bgpd/bgp_pbr.h"
      40             : 
      41             : /* struct used to dump the rate contained in FS set traffic-rate EC */
      42             : union traffic_rate {
      43             :         float rate_float;
      44             :         uint8_t rate_byte[4];
      45             : };
      46             : 
      47             : /* Hash of community attribute. */
      48             : static struct hash *ecomhash;
      49             : 
      50             : /* Allocate a new ecommunities.  */
      51           0 : struct ecommunity *ecommunity_new(void)
      52             : {
      53           0 :         struct ecommunity *ecom;
      54             : 
      55           0 :         ecom = (struct ecommunity *)XCALLOC(MTYPE_ECOMMUNITY,
      56             :                                             sizeof(struct ecommunity));
      57           0 :         ecom->unit_size = ECOMMUNITY_SIZE;
      58           0 :         return ecom;
      59             : }
      60             : 
      61           0 : void ecommunity_strfree(char **s)
      62             : {
      63           0 :         XFREE(MTYPE_ECOMMUNITY_STR, *s);
      64           0 : }
      65             : 
      66             : /* Free ecommunities.  */
      67         220 : void ecommunity_free(struct ecommunity **ecom)
      68             : {
      69         220 :         if (!(*ecom))
      70             :                 return;
      71             : 
      72           0 :         XFREE(MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
      73           0 :         XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str);
      74           0 :         XFREE(MTYPE_ECOMMUNITY, *ecom);
      75             : }
      76             : 
      77           0 : static void ecommunity_hash_free(struct ecommunity *ecom)
      78             : {
      79           0 :         ecommunity_free(&ecom);
      80           0 : }
      81             : 
      82             : 
      83             : /* Add a new Extended Communities value to Extended Communities
      84             :    Attribute structure.  When the value is already exists in the
      85             :    structure, we don't add the value.  Newly added value is sorted by
      86             :    numerical order.  When the value is added to the structure return 1
      87             :    else return 0.
      88             :    The additional parameters 'unique' and 'overwrite' ensure a particular
      89             :    extended community (based on type and sub-type) is present only
      90             :    once and whether the new value should replace what is existing or
      91             :    not.
      92             : */
      93           0 : static bool ecommunity_add_val_internal(struct ecommunity *ecom,
      94             :                                         const void *eval,
      95             :                                         bool unique, bool overwrite,
      96             :                                         uint8_t ecom_size)
      97             : {
      98           0 :         uint32_t c, ins_idx;
      99           0 :         const struct ecommunity_val *eval4 = (struct ecommunity_val *)eval;
     100           0 :         const struct ecommunity_val_ipv6 *eval6 =
     101             :                 (struct ecommunity_val_ipv6 *)eval;
     102             : 
     103             :         /* When this is fist value, just add it. */
     104           0 :         if (ecom->val == NULL) {
     105           0 :                 ecom->size = 1;
     106           0 :                 ecom->val = XMALLOC(MTYPE_ECOMMUNITY_VAL,
     107             :                                     ecom_length_size(ecom, ecom_size));
     108           0 :                 memcpy(ecom->val, eval, ecom_size);
     109           0 :                 return true;
     110             :         }
     111             : 
     112             :         /* If the value already exists in the structure return 0.  */
     113             :         /* check also if the extended community itself exists. */
     114             :         c = 0;
     115             : 
     116             :         ins_idx = UINT32_MAX;
     117           0 :         for (uint8_t *p = ecom->val; c < ecom->size;
     118           0 :              p += ecom_size, c++) {
     119           0 :                 if (unique) {
     120           0 :                         if (ecom_size == ECOMMUNITY_SIZE) {
     121           0 :                                 if (p[0] == eval4->val[0] &&
     122           0 :                                     p[1] == eval4->val[1]) {
     123           0 :                                         if (overwrite) {
     124           0 :                                                 memcpy(p, eval4->val,
     125             :                                                        ecom_size);
     126           0 :                                                 return true;
     127             :                                         }
     128             :                                         return false;
     129             :                                 }
     130             :                         } else {
     131           0 :                                 if (p[0] == eval6->val[0] &&
     132           0 :                                     p[1] == eval6->val[1]) {
     133           0 :                                         if (overwrite) {
     134           0 :                                                 memcpy(p, eval6->val,
     135             :                                                        ecom_size);
     136           0 :                                                 return true;
     137             :                                         }
     138             :                                         return false;
     139             :                                 }
     140             :                         }
     141             :                 }
     142           0 :                 int ret = memcmp(p, eval, ecom_size);
     143           0 :                 if (ret == 0)
     144             :                         return false;
     145           0 :                 if (ret > 0) {
     146           0 :                         if (!unique)
     147             :                                 break;
     148           0 :                         if (ins_idx == UINT32_MAX)
     149           0 :                                 ins_idx = c;
     150             :                 }
     151             :         }
     152             : 
     153           0 :         if (ins_idx == UINT32_MAX)
     154           0 :                 ins_idx = c;
     155             : 
     156             :         /* Add the value to the structure with numerical sorting.  */
     157           0 :         ecom->size++;
     158           0 :         ecom->val = XREALLOC(MTYPE_ECOMMUNITY_VAL, ecom->val,
     159             :                          ecom_length_size(ecom, ecom_size));
     160             : 
     161           0 :         memmove(ecom->val + ((ins_idx + 1) * ecom_size),
     162           0 :                 ecom->val + (ins_idx * ecom_size),
     163           0 :                 (ecom->size - 1 - ins_idx) * ecom_size);
     164           0 :         memcpy(ecom->val + (ins_idx * ecom_size),
     165             :                eval, ecom_size);
     166             : 
     167           0 :         return true;
     168             : }
     169             : 
     170             : /* Add a new Extended Communities value to Extended Communities
     171             :  * Attribute structure.  When the value is already exists in the
     172             :  * structure, we don't add the value.  Newly added value is sorted by
     173             :  * numerical order.  When the value is added to the structure return 1
     174             :  * else return 0.
     175             :  */
     176           0 : bool ecommunity_add_val(struct ecommunity *ecom, struct ecommunity_val *eval,
     177             :                        bool unique, bool overwrite)
     178             : {
     179           0 :         return ecommunity_add_val_internal(ecom, (const void *)eval, unique,
     180             :                                            overwrite, ECOMMUNITY_SIZE);
     181             : }
     182             : 
     183           0 : bool ecommunity_add_val_ipv6(struct ecommunity *ecom,
     184             :                              struct ecommunity_val_ipv6 *eval,
     185             :                              bool unique, bool overwrite)
     186             : {
     187           0 :         return ecommunity_add_val_internal(ecom, (const void *)eval, unique,
     188             :                                            overwrite, IPV6_ECOMMUNITY_SIZE);
     189             : }
     190             : 
     191             : static struct ecommunity *
     192           0 : ecommunity_uniq_sort_internal(struct ecommunity *ecom,
     193             :                               unsigned short ecom_size)
     194             : {
     195           0 :         uint32_t i;
     196           0 :         struct ecommunity *new;
     197           0 :         const void *eval;
     198             : 
     199           0 :         if (!ecom)
     200             :                 return NULL;
     201             : 
     202           0 :         new = ecommunity_new();
     203           0 :         new->unit_size = ecom_size;
     204           0 :         new->disable_ieee_floating = ecom->disable_ieee_floating;
     205             : 
     206           0 :         for (i = 0; i < ecom->size; i++) {
     207           0 :                 eval = (void *)(ecom->val + (i * ecom_size));
     208           0 :                 ecommunity_add_val_internal(new, eval, false, false, ecom_size);
     209             :         }
     210             :         return new;
     211             : }
     212             : 
     213             : /* This function takes pointer to Extended Communites structure then
     214             :  * create a new Extended Communities structure by uniq and sort each
     215             :  * Extended Communities value.
     216             :  */
     217           0 : struct ecommunity *ecommunity_uniq_sort(struct ecommunity *ecom)
     218             : {
     219           0 :         return ecommunity_uniq_sort_internal(ecom, ECOMMUNITY_SIZE);
     220             : }
     221             : 
     222             : /* Parse Extended Communites Attribute in BGP packet.  */
     223           0 : static struct ecommunity *ecommunity_parse_internal(uint8_t *pnt,
     224             :                                                     unsigned short length,
     225             :                                                     unsigned short size_ecom,
     226             :                                                     bool disable_ieee_floating)
     227             : {
     228           0 :         struct ecommunity tmp;
     229           0 :         struct ecommunity *new;
     230             : 
     231             :         /* Length check.  */
     232           0 :         if (length % size_ecom)
     233             :                 return NULL;
     234             : 
     235             :         /* Prepare tmporary structure for making a new Extended Communities
     236             :            Attribute.  */
     237           0 :         tmp.size = length / size_ecom;
     238           0 :         tmp.val = pnt;
     239           0 :         tmp.disable_ieee_floating = disable_ieee_floating;
     240             : 
     241             :         /* Create a new Extended Communities Attribute by uniq and sort each
     242             :            Extended Communities value  */
     243           0 :         new = ecommunity_uniq_sort_internal(&tmp, size_ecom);
     244             : 
     245           0 :         return ecommunity_intern(new);
     246             : }
     247             : 
     248           0 : struct ecommunity *ecommunity_parse(uint8_t *pnt, unsigned short length,
     249             :                                     bool disable_ieee_floating)
     250             : {
     251           0 :         return ecommunity_parse_internal(pnt, length, ECOMMUNITY_SIZE,
     252             :                                          disable_ieee_floating);
     253             : }
     254             : 
     255           0 : struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, unsigned short length,
     256             :                                          bool disable_ieee_floating)
     257             : {
     258           0 :         return ecommunity_parse_internal(pnt, length, IPV6_ECOMMUNITY_SIZE,
     259             :                                          disable_ieee_floating);
     260             : }
     261             : 
     262             : /* Duplicate the Extended Communities Attribute structure.  */
     263           0 : struct ecommunity *ecommunity_dup(struct ecommunity *ecom)
     264             : {
     265           0 :         struct ecommunity *new;
     266             : 
     267           0 :         new = XCALLOC(MTYPE_ECOMMUNITY, sizeof(struct ecommunity));
     268           0 :         new->size = ecom->size;
     269           0 :         new->unit_size = ecom->unit_size;
     270           0 :         if (new->size) {
     271           0 :                 new->val = XMALLOC(MTYPE_ECOMMUNITY_VAL,
     272             :                                    ecom->size * ecom->unit_size);
     273           0 :                 memcpy(new->val, ecom->val,
     274           0 :                        (size_t)ecom->size * (size_t)ecom->unit_size);
     275             :         } else
     276           0 :                 new->val = NULL;
     277           0 :         return new;
     278             : }
     279             : 
     280             : /* Return string representation of ecommunities attribute. */
     281           0 : char *ecommunity_str(struct ecommunity *ecom)
     282             : {
     283           0 :         if (!ecom->str)
     284           0 :                 ecom->str =
     285           0 :                         ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
     286           0 :         return ecom->str;
     287             : }
     288             : 
     289             : /* Merge two Extended Communities Attribute structure.  */
     290           0 : struct ecommunity *ecommunity_merge(struct ecommunity *ecom1,
     291             :                                     struct ecommunity *ecom2)
     292             : {
     293           0 :         ecom1->val = XREALLOC(MTYPE_ECOMMUNITY_VAL, ecom1->val,
     294             :                               (size_t)(ecom1->size + ecom2->size)
     295             :                                       * (size_t)ecom1->unit_size);
     296             : 
     297           0 :         memcpy(ecom1->val + (ecom1->size * ecom1->unit_size), ecom2->val,
     298           0 :                (size_t)ecom2->size * (size_t)ecom1->unit_size);
     299           0 :         ecom1->size += ecom2->size;
     300             : 
     301           0 :         return ecom1;
     302             : }
     303             : 
     304             : /* Intern Extended Communities Attribute.  */
     305           0 : struct ecommunity *ecommunity_intern(struct ecommunity *ecom)
     306             : {
     307           0 :         struct ecommunity *find;
     308             : 
     309           0 :         assert(ecom->refcnt == 0);
     310           0 :         find = (struct ecommunity *)hash_get(ecomhash, ecom, hash_alloc_intern);
     311           0 :         if (find != ecom)
     312           0 :                 ecommunity_free(&ecom);
     313             : 
     314           0 :         find->refcnt++;
     315             : 
     316           0 :         if (!find->str)
     317           0 :                 find->str =
     318           0 :                         ecommunity_ecom2str(find, ECOMMUNITY_FORMAT_DISPLAY, 0);
     319             : 
     320           0 :         return find;
     321             : }
     322             : 
     323             : /* Unintern Extended Communities Attribute.  */
     324         130 : void ecommunity_unintern(struct ecommunity **ecom)
     325             : {
     326         130 :         struct ecommunity *ret;
     327             : 
     328         130 :         if (!*ecom)
     329             :                 return;
     330             : 
     331           0 :         if ((*ecom)->refcnt)
     332           0 :                 (*ecom)->refcnt--;
     333             : 
     334             :         /* Pull off from hash.  */
     335           0 :         if ((*ecom)->refcnt == 0) {
     336             :                 /* Extended community must be in the hash.  */
     337           0 :                 ret = (struct ecommunity *)hash_release(ecomhash, *ecom);
     338           0 :                 assert(ret != NULL);
     339             : 
     340           0 :                 ecommunity_free(ecom);
     341             :         }
     342             : }
     343             : 
     344             : /* Utinity function to make hash key.  */
     345           0 : unsigned int ecommunity_hash_make(const void *arg)
     346             : {
     347           0 :         const struct ecommunity *ecom = arg;
     348           0 :         int size = ecom->size * ecom->unit_size;
     349             : 
     350           0 :         return jhash(ecom->val, size, 0x564321ab);
     351             : }
     352             : 
     353             : /* Compare two Extended Communities Attribute structure.  */
     354           0 : bool ecommunity_cmp(const void *arg1, const void *arg2)
     355             : {
     356           0 :         const struct ecommunity *ecom1 = arg1;
     357           0 :         const struct ecommunity *ecom2 = arg2;
     358             : 
     359           0 :         if (ecom1 == NULL && ecom2 == NULL)
     360             :                 return true;
     361             : 
     362           0 :         if (ecom1 == NULL || ecom2 == NULL)
     363             :                 return false;
     364             : 
     365           0 :         if (ecom1->unit_size != ecom2->unit_size)
     366             :                 return false;
     367             : 
     368           0 :         return (ecom1->size == ecom2->size
     369           0 :                 && memcmp(ecom1->val, ecom2->val, ecom1->size *
     370           0 :                           ecom1->unit_size) == 0);
     371             : }
     372             : 
     373             : /* Initialize Extended Comminities related hash. */
     374           3 : void ecommunity_init(void)
     375             : {
     376           3 :         ecomhash = hash_create(ecommunity_hash_make, ecommunity_cmp,
     377             :                                "BGP ecommunity hash");
     378           3 : }
     379             : 
     380           3 : void ecommunity_finish(void)
     381             : {
     382           3 :         hash_clean(ecomhash, (void (*)(void *))ecommunity_hash_free);
     383           3 :         hash_free(ecomhash);
     384           3 :         ecomhash = NULL;
     385           3 : }
     386             : 
     387             : /* Extended Communities token enum. */
     388             : enum ecommunity_token {
     389             :         ecommunity_token_unknown = 0,
     390             :         ecommunity_token_rt,
     391             :         ecommunity_token_soo,
     392             :         ecommunity_token_val,
     393             :         ecommunity_token_rt6,
     394             :         ecommunity_token_val6,
     395             : };
     396             : 
     397           0 : static const char *ecommunity_origin_validation_state2str(
     398             :         enum ecommunity_origin_validation_states state)
     399             : {
     400           0 :         switch (state) {
     401             :         case ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID:
     402             :                 return "valid";
     403           0 :         case ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND:
     404           0 :                 return "not-found";
     405           0 :         case ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID:
     406           0 :                 return "invalid";
     407           0 :         case ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED:
     408           0 :                 return "not-used";
     409             :         }
     410             : 
     411           0 :         return "ERROR";
     412             : }
     413             : 
     414           0 : static void ecommunity_origin_validation_state_str(char *buf, size_t bufsz,
     415             :                                                    uint8_t *ptr)
     416             : {
     417             :         /* Origin Validation State is encoded in the last octet
     418             :          *
     419             :          * 0                   1                   2                   3
     420             :          * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     421             :          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     422             :          * |       0x43    |      0x00     |             Reserved          |
     423             :          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     424             :          * |                    Reserved                   |validationstate|
     425             :          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     426             :          */
     427           0 :         uint8_t state = *(ptr + ECOMMUNITY_SIZE - 3);
     428             : 
     429           0 :         snprintf(buf, bufsz, "OVS:%s",
     430             :                  ecommunity_origin_validation_state2str(state));
     431             : 
     432           0 :         (void)ptr; /* consume value */
     433           0 : }
     434             : 
     435           0 : static int ecommunity_encode_internal(uint8_t type, uint8_t sub_type,
     436             :                                       int trans, as_t as,
     437             :                                       struct in_addr *ip,
     438             :                                       struct in6_addr *ip6,
     439             :                                       uint32_t val,
     440             :                                       void *eval_ptr)
     441             : {
     442           0 :         struct ecommunity_val *eval = (struct ecommunity_val *)eval_ptr;
     443           0 :         struct ecommunity_val_ipv6 *eval6 =
     444             :                 (struct ecommunity_val_ipv6 *)eval_ptr;
     445             : 
     446           0 :         assert(eval);
     447           0 :         if (type == ECOMMUNITY_ENCODE_AS) {
     448           0 :                 if (as > BGP_AS_MAX)
     449             :                         return -1;
     450           0 :         } else if (type == ECOMMUNITY_ENCODE_IP
     451           0 :                    || type == ECOMMUNITY_ENCODE_AS4) {
     452           0 :                 if (val > UINT16_MAX)
     453             :                         return -1;
     454           0 :         } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP &&
     455           0 :                    sub_type == ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 &&
     456           0 :                    (!ip6 || val > UINT16_MAX)) {
     457             :                 return -1;
     458             :         }
     459             : 
     460             :         /* Fill in the values. */
     461           0 :         eval->val[0] = type;
     462           0 :         if (!trans)
     463           0 :                 eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
     464           0 :         eval->val[1] = sub_type;
     465           0 :         if (type == ECOMMUNITY_ENCODE_AS) {
     466           0 :                 eval->val[2] = (as >> 8) & 0xff;
     467           0 :                 eval->val[3] = as & 0xff;
     468           0 :                 eval->val[4] = (val >> 24) & 0xff;
     469           0 :                 eval->val[5] = (val >> 16) & 0xff;
     470           0 :                 eval->val[6] = (val >> 8) & 0xff;
     471           0 :                 eval->val[7] = val & 0xff;
     472           0 :         } else if (type == ECOMMUNITY_ENCODE_IP) {
     473           0 :                 memcpy(&eval->val[2], ip, sizeof(struct in_addr));
     474           0 :                 eval->val[6] = (val >> 8) & 0xff;
     475           0 :                 eval->val[7] = val & 0xff;
     476           0 :         } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP &&
     477           0 :                    sub_type == ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) {
     478           0 :                 memcpy(&eval6->val[2], ip6, sizeof(struct in6_addr));
     479           0 :                 eval6->val[18] = (val >> 8) & 0xff;
     480           0 :                 eval6->val[19] = val & 0xff;
     481             :         } else {
     482           0 :                 eval->val[2] = (as >> 24) & 0xff;
     483           0 :                 eval->val[3] = (as >> 16) & 0xff;
     484           0 :                 eval->val[4] = (as >> 8) & 0xff;
     485           0 :                 eval->val[5] = as & 0xff;
     486           0 :                 eval->val[6] = (val >> 8) & 0xff;
     487           0 :                 eval->val[7] = val & 0xff;
     488             :         }
     489             : 
     490             :         return 0;
     491             : }
     492             : 
     493             : /*
     494             :  * Encode BGP extended community from passed values. Supports types
     495             :  * defined in RFC 4360 and well-known sub-types.
     496             :  */
     497           0 : static int ecommunity_encode(uint8_t type, uint8_t sub_type, int trans, as_t as,
     498             :                              struct in_addr ip, uint32_t val,
     499             :                              struct ecommunity_val *eval)
     500             : {
     501           0 :         return ecommunity_encode_internal(type, sub_type, trans, as,
     502             :                                           &ip, NULL, val, (void *)eval);
     503             : }
     504             : 
     505             : /* Get next Extended Communities token from the string. */
     506           0 : static const char *ecommunity_gettoken(const char *str,
     507             :                                        void *eval_ptr,
     508             :                                        enum ecommunity_token *token)
     509             : {
     510           0 :         int ret;
     511           0 :         int dot = 0;
     512           0 :         int digit = 0;
     513           0 :         int separator = 0;
     514           0 :         const char *p = str;
     515           0 :         char *endptr;
     516           0 :         struct in_addr ip;
     517           0 :         struct in6_addr ip6;
     518           0 :         as_t as = 0;
     519           0 :         uint32_t val = 0;
     520           0 :         uint8_t ecomm_type;
     521           0 :         char buf[INET_ADDRSTRLEN + 1];
     522           0 :         struct ecommunity_val *eval = (struct ecommunity_val *)eval_ptr;
     523             :         /* Skip white space. */
     524           0 :         while (isspace((unsigned char)*p)) {
     525           0 :                 p++;
     526           0 :                 str++;
     527             :         }
     528             : 
     529             :         /* Check the end of the line. */
     530           0 :         if (*p == '\0')
     531             :                 return NULL;
     532             : 
     533             :         /* "rt" and "soo" keyword parse. */
     534           0 :         if (!isdigit((unsigned char)*p)) {
     535             :                 /* "rt" match check.  */
     536           0 :                 if (tolower((unsigned char)*p) == 'r') {
     537           0 :                         p++;
     538           0 :                         if (tolower((unsigned char)*p) == 't') {
     539           0 :                                 p++;
     540           0 :                                 if (*p != '\0' && tolower((int)*p) == '6')
     541           0 :                                         *token = ecommunity_token_rt6;
     542             :                                 else
     543           0 :                                         *token = ecommunity_token_rt;
     544           0 :                                 return p;
     545             :                         }
     546           0 :                         if (isspace((unsigned char)*p) || *p == '\0') {
     547           0 :                                 *token = ecommunity_token_rt;
     548           0 :                                 return p;
     549             :                         }
     550           0 :                         goto error;
     551             :                 }
     552             :                 /* "soo" match check.  */
     553           0 :                 else if (tolower((unsigned char)*p) == 's') {
     554           0 :                         p++;
     555           0 :                         if (tolower((unsigned char)*p) == 'o') {
     556           0 :                                 p++;
     557           0 :                                 if (tolower((unsigned char)*p) == 'o') {
     558           0 :                                         p++;
     559           0 :                                         *token = ecommunity_token_soo;
     560           0 :                                         return p;
     561             :                                 }
     562           0 :                                 if (isspace((unsigned char)*p) || *p == '\0') {
     563           0 :                                         *token = ecommunity_token_soo;
     564           0 :                                         return p;
     565             :                                 }
     566           0 :                                 goto error;
     567             :                         }
     568           0 :                         if (isspace((unsigned char)*p) || *p == '\0') {
     569           0 :                                 *token = ecommunity_token_soo;
     570           0 :                                 return p;
     571             :                         }
     572           0 :                         goto error;
     573             :                 }
     574           0 :                 goto error;
     575             :         }
     576             : 
     577             :         /* What a mess, there are several possibilities:
     578             :          *
     579             :          * a) A.B.C.D:MN
     580             :          * b) EF:OPQR
     581             :          * c) GHJK:MN
     582             :          * d) <IPV6>:MN (only with rt6)
     583             :          *
     584             :          * A.B.C.D: Four Byte IP
     585             :          * EF:      Two byte ASN
     586             :          * GHJK:    Four-byte ASN
     587             :          * MN:      Two byte value
     588             :          * OPQR:    Four byte value
     589             :          *
     590             :          */
     591             :         /* IPv6 case : look for last ':' */
     592           0 :         if (*token == ecommunity_token_rt6 ||
     593             :             *token == ecommunity_token_val6) {
     594           0 :                 char *limit;
     595             : 
     596           0 :                 limit = endptr = strrchr(p, ':');
     597           0 :                 if (!endptr)
     598           0 :                         goto error;
     599             : 
     600           0 :                 endptr++;
     601           0 :                 as = strtoul(endptr, &endptr, 10);
     602           0 :                 if (*endptr != '\0' || as == BGP_AS4_MAX)
     603           0 :                         goto error;
     604             : 
     605           0 :                 memcpy(buf, p, (limit - p));
     606           0 :                 buf[limit - p] = '\0';
     607           0 :                 ret = inet_pton(AF_INET6, buf, &ip6);
     608           0 :                 if (ret == 0)
     609           0 :                         goto error;
     610             : 
     611           0 :                 ecomm_type = ECOMMUNITY_ENCODE_TRANS_EXP;
     612           0 :                 if (ecommunity_encode_internal(ecomm_type,
     613             :                                         ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6,
     614             :                                         1, 0, NULL, &ip6, as, eval_ptr))
     615           0 :                         goto error;
     616             : 
     617           0 :                 *token = ecommunity_token_val6;
     618           0 :                 while (isdigit((int)*p) || *p == ':' || *p == '.') {
     619           0 :                         p++;
     620             :                 }
     621           0 :                 return p;
     622             :         }
     623           0 :         while (isdigit((unsigned char)*p) || *p == ':' || *p == '.') {
     624           0 :                 if (*p == ':') {
     625           0 :                         if (separator)
     626           0 :                                 goto error;
     627             : 
     628           0 :                         separator = 1;
     629           0 :                         digit = 0;
     630             : 
     631           0 :                         if ((p - str) > INET_ADDRSTRLEN)
     632           0 :                                 goto error;
     633           0 :                         memset(buf, 0, INET_ADDRSTRLEN + 1);
     634           0 :                         memcpy(buf, str, p - str);
     635             : 
     636           0 :                         if (dot) {
     637             :                                 /* Parsing A.B.C.D in:
     638             :                                  * A.B.C.D:MN
     639             :                                  */
     640           0 :                                 ret = inet_aton(buf, &ip);
     641           0 :                                 if (ret == 0)
     642           0 :                                         goto error;
     643             :                         } else {
     644             :                                 /* ASN */
     645           0 :                                 as = strtoul(buf, &endptr, 10);
     646           0 :                                 if (*endptr != '\0' || as == BGP_AS4_MAX)
     647           0 :                                         goto error;
     648             :                         }
     649           0 :                 } else if (*p == '.') {
     650           0 :                         if (separator)
     651           0 :                                 goto error;
     652           0 :                         dot++;
     653           0 :                         if (dot > 4)
     654           0 :                                 goto error;
     655             :                 } else {
     656           0 :                         digit = 1;
     657             : 
     658             :                         /* We're past the IP/ASN part */
     659           0 :                         if (separator) {
     660           0 :                                 val *= 10;
     661           0 :                                 val += (*p - '0');
     662             :                         }
     663             :                 }
     664           0 :                 p++;
     665             :         }
     666             : 
     667             :         /* Low digit part must be there. */
     668           0 :         if (!digit || !separator)
     669           0 :                 goto error;
     670             : 
     671             :         /* Encode result into extended community.  */
     672           0 :         if (dot)
     673             :                 ecomm_type = ECOMMUNITY_ENCODE_IP;
     674           0 :         else if (as > BGP_AS_MAX)
     675             :                 ecomm_type = ECOMMUNITY_ENCODE_AS4;
     676             :         else
     677           0 :                 ecomm_type = ECOMMUNITY_ENCODE_AS;
     678           0 :         if (ecommunity_encode(ecomm_type, 0, 1, as, ip, val, eval))
     679           0 :                 goto error;
     680           0 :         *token = ecommunity_token_val;
     681           0 :         return p;
     682             : 
     683           0 : error:
     684           0 :         *token = ecommunity_token_unknown;
     685           0 :         return p;
     686             : }
     687             : 
     688           0 : static struct ecommunity *ecommunity_str2com_internal(const char *str, int type,
     689             :                                                       int keyword_included,
     690             :                                                       bool is_ipv6_extcomm)
     691             : {
     692           0 :         struct ecommunity *ecom = NULL;
     693           0 :         enum ecommunity_token token = ecommunity_token_unknown;
     694           0 :         struct ecommunity_val_ipv6 eval;
     695           0 :         int keyword = 0;
     696             : 
     697           0 :         if (is_ipv6_extcomm)
     698           0 :                 token = ecommunity_token_rt6;
     699           0 :         while ((str = ecommunity_gettoken(str, (void *)&eval, &token))) {
     700           0 :                 switch (token) {
     701           0 :                 case ecommunity_token_rt:
     702             :                 case ecommunity_token_rt6:
     703             :                 case ecommunity_token_soo:
     704           0 :                         if (!keyword_included || keyword) {
     705           0 :                                 if (ecom)
     706           0 :                                         ecommunity_free(&ecom);
     707           0 :                                 return NULL;
     708             :                         }
     709           0 :                         keyword = 1;
     710             : 
     711           0 :                         if (token == ecommunity_token_rt ||
     712             :                             token == ecommunity_token_rt6) {
     713           0 :                                 type = ECOMMUNITY_ROUTE_TARGET;
     714             :                         }
     715           0 :                         if (token == ecommunity_token_soo) {
     716           0 :                                 type = ECOMMUNITY_SITE_ORIGIN;
     717             :                         }
     718             :                         break;
     719           0 :                 case ecommunity_token_val:
     720           0 :                         if (keyword_included) {
     721           0 :                                 if (!keyword) {
     722           0 :                                         ecommunity_free(&ecom);
     723           0 :                                         return NULL;
     724             :                                 }
     725             :                                 keyword = 0;
     726             :                         }
     727           0 :                         if (ecom == NULL)
     728           0 :                                 ecom = ecommunity_new();
     729           0 :                         eval.val[1] = type;
     730           0 :                         ecommunity_add_val_internal(ecom, (void *)&eval,
     731             :                                                     false, false,
     732           0 :                                                     ecom->unit_size);
     733           0 :                         break;
     734           0 :                 case ecommunity_token_val6:
     735           0 :                         if (keyword_included) {
     736           0 :                                 if (!keyword) {
     737           0 :                                         ecommunity_free(&ecom);
     738           0 :                                         return NULL;
     739             :                                 }
     740             :                                 keyword = 0;
     741             :                         }
     742           0 :                         if (ecom == NULL)
     743           0 :                                 ecom = ecommunity_new();
     744           0 :                         ecom->unit_size = IPV6_ECOMMUNITY_SIZE;
     745           0 :                         eval.val[1] = type;
     746           0 :                         ecommunity_add_val_internal(ecom, (void *)&eval, false, false,
     747             :                                                     ecom->unit_size);
     748           0 :                         break;
     749           0 :                 case ecommunity_token_unknown:
     750           0 :                         if (ecom)
     751           0 :                                 ecommunity_free(&ecom);
     752             :                         return NULL;
     753             :                 }
     754             :         }
     755           0 :         return ecom;
     756             : }
     757             : 
     758             : /* Convert string to extended community attribute.
     759             :  *
     760             :  * When type is already known, please specify both str and type.  str
     761             :  * should not include keyword such as "rt" and "soo".  Type is
     762             :  * ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
     763             :  * keyword_included should be zero.
     764             :  *
     765             :  * For example route-map's "set extcommunity" command case:
     766             :  *
     767             :  * "rt 100:1 100:2 100:3"        -> str = "100:1 100:2 100:3"
     768             :  *                                  type = ECOMMUNITY_ROUTE_TARGET
     769             :  *                                  keyword_included = 0
     770             :  *
     771             :  * "soo 100:1"                   -> str = "100:1"
     772             :  *                                  type = ECOMMUNITY_SITE_ORIGIN
     773             :  *                                  keyword_included = 0
     774             :  *
     775             :  * When string includes keyword for each extended community value.
     776             :  * Please specify keyword_included as non-zero value.
     777             :  *
     778             :  * For example standard extcommunity-list case:
     779             :  *
     780             :  * "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
     781             :  *                                  type = 0
     782             :  *                                  keyword_include = 1
     783             :  */
     784           0 : struct ecommunity *ecommunity_str2com(const char *str, int type,
     785             :                                       int keyword_included)
     786             : {
     787           0 :         return ecommunity_str2com_internal(str, type,
     788             :                                            keyword_included, false);
     789             : }
     790             : 
     791           0 : struct ecommunity *ecommunity_str2com_ipv6(const char *str, int type,
     792             :                                            int keyword_included)
     793             : {
     794           0 :         return ecommunity_str2com_internal(str, type,
     795             :                                            keyword_included, true);
     796             : }
     797             : 
     798           0 : static int ecommunity_rt_soo_str_internal(char *buf, size_t bufsz,
     799             :                                           const uint8_t *pnt, int type,
     800             :                                           int sub_type, int format,
     801             :                                           unsigned short ecom_size)
     802             : {
     803           0 :         int len = 0;
     804           0 :         const char *prefix;
     805           0 :         char buf_local[INET6_ADDRSTRLEN];
     806             : 
     807             :         /* For parse Extended Community attribute tupple. */
     808           0 :         struct ecommunity_as eas;
     809           0 :         struct ecommunity_ip eip;
     810           0 :         struct ecommunity_ip6 eip6;
     811             : 
     812             :         /* Determine prefix for string, if any. */
     813           0 :         switch (format) {
     814           0 :         case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
     815           0 :                 prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
     816             :                 break;
     817           0 :         case ECOMMUNITY_FORMAT_DISPLAY:
     818           0 :                 prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
     819             :                 break;
     820             :         case ECOMMUNITY_FORMAT_ROUTE_MAP:
     821             :                 prefix = "";
     822             :                 break;
     823             :         default:
     824             :                 prefix = "";
     825             :                 break;
     826             :         }
     827             : 
     828             :         /* Put string into buffer.  */
     829           0 :         if (type == ECOMMUNITY_ENCODE_AS4) {
     830           0 :                 pnt = ptr_get_be32(pnt, &eas.as);
     831           0 :                 eas.val = (*pnt++ << 8);
     832           0 :                 eas.val |= (*pnt++);
     833             : 
     834           0 :                 len = snprintf(buf, bufsz, "%s%u:%u", prefix, eas.as, eas.val);
     835           0 :         } else if (type == ECOMMUNITY_ENCODE_AS) {
     836           0 :                 if (ecom_size == ECOMMUNITY_SIZE) {
     837           0 :                         eas.as = (*pnt++ << 8);
     838           0 :                         eas.as |= (*pnt++);
     839           0 :                         pnt = ptr_get_be32(pnt, &eas.val);
     840             : 
     841           0 :                         len = snprintf(buf, bufsz, "%s%u:%u", prefix, eas.as,
     842             :                                        eas.val);
     843             :                 } else {
     844             :                         /* this is an IPv6 ext community
     845             :                          * first 16 bytes stands for IPv6 addres
     846             :                          */
     847           0 :                         memcpy(&eip6.ip, pnt, 16);
     848           0 :                         pnt += 16;
     849           0 :                         eip6.val = (*pnt++ << 8);
     850           0 :                         eip6.val |= (*pnt++);
     851             : 
     852           0 :                         inet_ntop(AF_INET6, &eip6.ip, buf_local,
     853             :                                   sizeof(buf_local));
     854           0 :                         len = snprintf(buf, bufsz, "%s%s:%u", prefix,
     855           0 :                                        buf_local, eip6.val);
     856             :                 }
     857           0 :         } else if (type == ECOMMUNITY_ENCODE_IP) {
     858           0 :                 memcpy(&eip.ip, pnt, 4);
     859           0 :                 pnt += 4;
     860           0 :                 eip.val = (*pnt++ << 8);
     861           0 :                 eip.val |= (*pnt++);
     862             : 
     863           0 :                 len = snprintfrr(buf, bufsz, "%s%pI4:%u", prefix, &eip.ip,
     864             :                                  eip.val);
     865             :         }
     866             : 
     867             :         /* consume value */
     868           0 :         (void)pnt;
     869             : 
     870           0 :         return len;
     871             : }
     872             : 
     873           0 : static int ecommunity_rt_soo_str(char *buf, size_t bufsz, const uint8_t *pnt,
     874             :                                  int type, int sub_type, int format)
     875             : {
     876           0 :         return ecommunity_rt_soo_str_internal(buf, bufsz, pnt, type,
     877             :                                               sub_type, format,
     878             :                                               ECOMMUNITY_SIZE);
     879             : }
     880             : 
     881             : /* Helper function to convert IEEE-754 Floating Point to uint32 */
     882           0 : static uint32_t ieee_float_uint32_to_uint32(uint32_t u)
     883             : {
     884           0 :         union {
     885             :                 float r;
     886             :                 uint32_t d;
     887           0 :         } f = {.d = u};
     888             : 
     889           0 :         return (uint32_t)f.r;
     890             : }
     891             : 
     892           0 : static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt,
     893             :                              bool disable_ieee_floating)
     894             : {
     895           0 :         int len = 0;
     896           0 :         as_t as;
     897           0 :         uint32_t bw_tmp, bw;
     898           0 :         char bps_buf[20] = {0};
     899             : 
     900             : #define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8)
     901             : #define ONE_MBPS_BYTES (1000 * 1000 / 8)
     902             : #define ONE_KBPS_BYTES (1000 / 8)
     903             : 
     904           0 :         as = (*pnt++ << 8);
     905           0 :         as |= (*pnt++);
     906           0 :         (void)ptr_get_be32(pnt, &bw_tmp);
     907             : 
     908           0 :         bw = disable_ieee_floating ? bw_tmp
     909           0 :                                    : ieee_float_uint32_to_uint32(bw_tmp);
     910             : 
     911           0 :         if (bw >= ONE_GBPS_BYTES)
     912           0 :                 snprintf(bps_buf, sizeof(bps_buf), "%.3f Gbps",
     913           0 :                          (float)(bw / ONE_GBPS_BYTES));
     914           0 :         else if (bw >= ONE_MBPS_BYTES)
     915           0 :                 snprintf(bps_buf, sizeof(bps_buf), "%.3f Mbps",
     916           0 :                          (float)(bw / ONE_MBPS_BYTES));
     917           0 :         else if (bw >= ONE_KBPS_BYTES)
     918           0 :                 snprintf(bps_buf, sizeof(bps_buf), "%.3f Kbps",
     919           0 :                          (float)(bw / ONE_KBPS_BYTES));
     920             :         else
     921           0 :                 snprintf(bps_buf, sizeof(bps_buf), "%u bps", bw * 8);
     922             : 
     923           0 :         len = snprintf(buf, bufsz, "LB:%u:%u (%s)", as, bw, bps_buf);
     924           0 :         return len;
     925             : }
     926             : 
     927             : /* Convert extended community attribute to string.
     928             : 
     929             :    Due to historical reason of industry standard implementation, there
     930             :    are three types of format.
     931             : 
     932             :    route-map set extcommunity format
     933             :         "rt 100:1 100:2soo 100:3"
     934             : 
     935             :    extcommunity-list
     936             :         "rt 100:1 rt 100:2 soo 100:3show [ip] bgp" and extcommunity-list regular expression matching
     937             :         "RT:100:1 RT:100:2 SoO:100:3"
     938             : 
     939             :    For each formath please use below definition for format:
     940             : 
     941             :    ECOMMUNITY_FORMAT_ROUTE_MAP
     942             :    ECOMMUNITY_FORMAT_COMMUNITY_LIST
     943             :    ECOMMUNITY_FORMAT_DISPLAY
     944             : 
     945             :    Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
     946             :    0 value displays all
     947             : */
     948           0 : char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
     949             : {
     950           0 :         uint32_t i;
     951           0 :         uint8_t *pnt;
     952           0 :         uint8_t type = 0;
     953           0 :         uint8_t sub_type = 0;
     954           0 :         int str_size;
     955           0 :         char *str_buf;
     956             : 
     957           0 :         if (!ecom || ecom->size == 0)
     958           0 :                 return XCALLOC(MTYPE_ECOMMUNITY_STR, 1);
     959             : 
     960             :         /* ecom strlen + space + null term */
     961           0 :         str_size = (ecom->size * (ECOMMUNITY_STRLEN + 1)) + 1;
     962           0 :         str_buf = XCALLOC(MTYPE_ECOMMUNITY_STR, str_size);
     963             : 
     964           0 :         char encbuf[128];
     965             : 
     966           0 :         for (i = 0; i < ecom->size; i++) {
     967           0 :                 int unk_ecom = 0;
     968           0 :                 memset(encbuf, 0x00, sizeof(encbuf));
     969             : 
     970             :                 /* Space between each value.  */
     971           0 :                 if (i > 0)
     972           0 :                         strlcat(str_buf, " ", str_size);
     973             : 
     974             :                 /* Retrieve value field */
     975           0 :                 pnt = ecom->val + (i * ecom->unit_size);
     976             : 
     977             :                 /* High-order octet is the type */
     978           0 :                 type = *pnt++;
     979             : 
     980           0 :                 if (type == ECOMMUNITY_ENCODE_AS || type == ECOMMUNITY_ENCODE_IP
     981             :                     || type == ECOMMUNITY_ENCODE_AS4) {
     982             :                         /* Low-order octet of type. */
     983           0 :                         sub_type = *pnt++;
     984           0 :                         if (sub_type != ECOMMUNITY_ROUTE_TARGET
     985           0 :                             && sub_type != ECOMMUNITY_SITE_ORIGIN) {
     986           0 :                                 if (sub_type ==
     987           0 :                                     ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4 &&
     988           0 :                                     type == ECOMMUNITY_ENCODE_IP) {
     989           0 :                                         struct in_addr *ipv4 =
     990             :                                                 (struct in_addr *)pnt;
     991           0 :                                         snprintfrr(encbuf, sizeof(encbuf),
     992           0 :                                                    "NH:%pI4:%d", ipv4, pnt[5]);
     993           0 :                                 } else if (sub_type ==
     994           0 :                                            ECOMMUNITY_LINK_BANDWIDTH &&
     995           0 :                                            type == ECOMMUNITY_ENCODE_AS) {
     996           0 :                                         ecommunity_lb_str(
     997             :                                                 encbuf, sizeof(encbuf), pnt,
     998           0 :                                                 ecom->disable_ieee_floating);
     999             :                                 } else
    1000             :                                         unk_ecom = 1;
    1001             :                         } else {
    1002           0 :                                 ecommunity_rt_soo_str(encbuf, sizeof(encbuf),
    1003             :                                                       pnt, type, sub_type,
    1004             :                                                       format);
    1005             :                         }
    1006           0 :                 } else if (type == ECOMMUNITY_ENCODE_OPAQUE) {
    1007           0 :                         if (filter == ECOMMUNITY_ROUTE_TARGET)
    1008           0 :                                 continue;
    1009           0 :                         if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP) {
    1010           0 :                                 uint16_t tunneltype;
    1011           0 :                                 memcpy(&tunneltype, pnt + 5, 2);
    1012           0 :                                 tunneltype = ntohs(tunneltype);
    1013             : 
    1014           0 :                                 snprintf(encbuf, sizeof(encbuf), "ET:%d",
    1015             :                                          tunneltype);
    1016           0 :                         } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW) {
    1017           0 :                                 strlcpy(encbuf, "Default Gateway",
    1018             :                                         sizeof(encbuf));
    1019             :                         } else {
    1020             :                                 unk_ecom = 1;
    1021             :                         }
    1022             :                 } else if (type == ECOMMUNITY_ENCODE_EVPN) {
    1023           0 :                         if (filter == ECOMMUNITY_ROUTE_TARGET)
    1024           0 :                                 continue;
    1025           0 :                         if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC) {
    1026           0 :                                 struct ethaddr rmac;
    1027           0 :                                 pnt++;
    1028           0 :                                 memcpy(&rmac, pnt, ETH_ALEN);
    1029             : 
    1030           0 :                                 snprintf(encbuf, sizeof(encbuf),
    1031             :                                          "Rmac:%02x:%02x:%02x:%02x:%02x:%02x",
    1032             :                                          (uint8_t)rmac.octet[0],
    1033             :                                          (uint8_t)rmac.octet[1],
    1034             :                                          (uint8_t)rmac.octet[2],
    1035             :                                          (uint8_t)rmac.octet[3],
    1036             :                                          (uint8_t)rmac.octet[4],
    1037             :                                          (uint8_t)rmac.octet[5]);
    1038           0 :                         } else if (*pnt
    1039             :                                    == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) {
    1040           0 :                                 uint32_t seqnum;
    1041           0 :                                 uint8_t flags = *++pnt;
    1042             : 
    1043           0 :                                 memcpy(&seqnum, pnt + 2, 4);
    1044           0 :                                 seqnum = ntohl(seqnum);
    1045             : 
    1046           0 :                                 snprintf(encbuf, sizeof(encbuf), "MM:%u",
    1047             :                                          seqnum);
    1048             : 
    1049           0 :                                 if (CHECK_FLAG(
    1050             :                                             flags,
    1051             :                                             ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY))
    1052           0 :                                         strlcat(encbuf, ", sticky MAC",
    1053             :                                                 sizeof(encbuf));
    1054             :                         } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_ND) {
    1055           0 :                                 uint8_t flags = *++pnt;
    1056             : 
    1057           0 :                                 if (CHECK_FLAG(
    1058             :                                             flags,
    1059             :                                             ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG))
    1060           0 :                                         strlcpy(encbuf, "ND:Router Flag",
    1061             :                                                 sizeof(encbuf));
    1062           0 :                                 if (CHECK_FLAG(
    1063             :                                             flags,
    1064             :                                             ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG))
    1065           0 :                                         strlcpy(encbuf, "ND:Proxy",
    1066             :                                                 sizeof(encbuf));
    1067             :                         } else if (*pnt
    1068             :                                    == ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT) {
    1069           0 :                                 struct ethaddr mac;
    1070             : 
    1071           0 :                                 pnt++;
    1072           0 :                                 memcpy(&mac, pnt, ETH_ALEN);
    1073           0 :                                 snprintf(encbuf,
    1074             :                                         sizeof(encbuf),
    1075             :                                         "ES-Import-Rt:%02x:%02x:%02x:%02x:%02x:%02x",
    1076             :                                         (uint8_t)mac.octet[0],
    1077             :                                         (uint8_t)mac.octet[1],
    1078             :                                         (uint8_t)mac.octet[2],
    1079             :                                         (uint8_t)mac.octet[3],
    1080             :                                         (uint8_t)mac.octet[4],
    1081             :                                         (uint8_t)mac.octet[5]);
    1082             :                         } else if (*pnt
    1083             :                                    == ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL) {
    1084           0 :                                 uint8_t flags = *++pnt;
    1085             : 
    1086           0 :                                 snprintf(encbuf,
    1087             :                                         sizeof(encbuf), "ESI-label-Rt:%s",
    1088             :                                         (flags &
    1089             :                                          ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG) ?
    1090             :                                         "SA":"AA");
    1091             :                         } else if (*pnt
    1092             :                                    == ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION) {
    1093           0 :                                 uint8_t alg;
    1094           0 :                                 uint16_t pref;
    1095           0 :                                 uint16_t bmap;
    1096             : 
    1097           0 :                                 alg = *(pnt + 1);
    1098           0 :                                 memcpy(&bmap, pnt + 2, 2);
    1099           0 :                                 bmap = ntohs(bmap);
    1100           0 :                                 memcpy(&pref, pnt + 5, 2);
    1101           0 :                                 pref = ntohs(pref);
    1102             : 
    1103           0 :                                 if (bmap)
    1104           0 :                                         snprintf(
    1105             :                                                 encbuf, sizeof(encbuf),
    1106             :                                                 "DF: (alg: %u, bmap: 0x%x pref: %u)",
    1107             :                                                 alg, bmap, pref);
    1108             :                                 else
    1109           0 :                                         snprintf(encbuf, sizeof(encbuf),
    1110             :                                                  "DF: (alg: %u, pref: %u)", alg,
    1111             :                                                  pref);
    1112             :                         } else
    1113             :                                 unk_ecom = 1;
    1114             :                 } else if (type == ECOMMUNITY_ENCODE_REDIRECT_IP_NH) {
    1115           0 :                         sub_type = *pnt++;
    1116           0 :                         if (sub_type == ECOMMUNITY_REDIRECT_IP_NH) {
    1117           0 :                                 snprintf(encbuf, sizeof(encbuf),
    1118           0 :                                          "FS:redirect IP 0x%x", *(pnt + 5));
    1119             :                         } else
    1120             :                                 unk_ecom = 1;
    1121             :                 } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP ||
    1122             :                            type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 ||
    1123             :                            type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_3) {
    1124           0 :                         sub_type = *pnt++;
    1125             : 
    1126           0 :                         if (sub_type == ECOMMUNITY_ROUTE_TARGET) {
    1127           0 :                                 char buf[ECOMMUNITY_STRLEN];
    1128             : 
    1129           0 :                                 memset(buf, 0, sizeof(buf));
    1130           0 :                                 ecommunity_rt_soo_str_internal(buf, sizeof(buf),
    1131             :                                                 (const uint8_t *)pnt,
    1132             :                                                 type &
    1133             :                                                 ~ECOMMUNITY_ENCODE_TRANS_EXP,
    1134             :                                                 ECOMMUNITY_ROUTE_TARGET,
    1135             :                                                 format,
    1136             :                                                 ecom->unit_size);
    1137           0 :                                 snprintf(encbuf, sizeof(encbuf), "%s", buf);
    1138           0 :                         } else if (sub_type ==
    1139             :                                    ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6) {
    1140           0 :                                 char buf[64];
    1141             : 
    1142           0 :                                 memset(buf, 0, sizeof(buf));
    1143           0 :                                 ecommunity_rt_soo_str_internal(buf, sizeof(buf),
    1144             :                                                 (const uint8_t *)pnt,
    1145             :                                                 type &
    1146             :                                                 ~ECOMMUNITY_ENCODE_TRANS_EXP,
    1147             :                                                 ECOMMUNITY_ROUTE_TARGET,
    1148             :                                                 ECOMMUNITY_FORMAT_DISPLAY,
    1149             :                                                 ecom->unit_size);
    1150           0 :                                 snprintf(encbuf, sizeof(encbuf),
    1151             :                                          "FS:redirect VRF %s", buf);
    1152           0 :                         } else if (sub_type == ECOMMUNITY_REDIRECT_VRF) {
    1153           0 :                                 char buf[16];
    1154             : 
    1155           0 :                                 memset(buf, 0, sizeof(buf));
    1156           0 :                                 ecommunity_rt_soo_str(buf, sizeof(buf),
    1157             :                                                 (const uint8_t *)pnt,
    1158             :                                                 type &
    1159             :                                                 ~ECOMMUNITY_ENCODE_TRANS_EXP,
    1160             :                                                 ECOMMUNITY_ROUTE_TARGET,
    1161             :                                                 ECOMMUNITY_FORMAT_DISPLAY);
    1162           0 :                                 snprintf(encbuf, sizeof(encbuf),
    1163             :                                          "FS:redirect VRF %s", buf);
    1164           0 :                                 snprintf(encbuf, sizeof(encbuf),
    1165             :                                          "FS:redirect VRF %s", buf);
    1166           0 :                         } else if (type != ECOMMUNITY_ENCODE_TRANS_EXP)
    1167             :                                 unk_ecom = 1;
    1168           0 :                         else if (sub_type == ECOMMUNITY_TRAFFIC_ACTION) {
    1169           0 :                                 char action[64];
    1170             : 
    1171           0 :                                 if (*(pnt+3) ==
    1172             :                                     1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL)
    1173           0 :                                         strlcpy(action, "terminate (apply)",
    1174             :                                                 sizeof(action));
    1175             :                                 else
    1176           0 :                                         strlcpy(action, "eval stops",
    1177             :                                                 sizeof(action));
    1178             : 
    1179           0 :                                 if (*(pnt+3) ==
    1180             :                                     1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE)
    1181           0 :                                         strlcat(action, ", sample",
    1182             :                                                 sizeof(action));
    1183             : 
    1184             : 
    1185           0 :                                 snprintf(encbuf, sizeof(encbuf), "FS:action %s",
    1186             :                                          action);
    1187           0 :                         } else if (sub_type == ECOMMUNITY_TRAFFIC_RATE) {
    1188           0 :                                 union traffic_rate data;
    1189             : 
    1190           0 :                                 data.rate_byte[3] = *(pnt+2);
    1191           0 :                                 data.rate_byte[2] = *(pnt+3);
    1192           0 :                                 data.rate_byte[1] = *(pnt+4);
    1193           0 :                                 data.rate_byte[0] = *(pnt+5);
    1194           0 :                                 snprintf(encbuf, sizeof(encbuf), "FS:rate %f",
    1195           0 :                                          data.rate_float);
    1196           0 :                         } else if (sub_type == ECOMMUNITY_TRAFFIC_MARKING) {
    1197           0 :                                 snprintf(encbuf, sizeof(encbuf),
    1198           0 :                                          "FS:marking %u", *(pnt + 5));
    1199             :                         } else
    1200             :                                 unk_ecom = 1;
    1201             :                 } else if (type == ECOMMUNITY_ENCODE_AS_NON_TRANS) {
    1202           0 :                         sub_type = *pnt++;
    1203           0 :                         if (sub_type == ECOMMUNITY_LINK_BANDWIDTH)
    1204           0 :                                 ecommunity_lb_str(encbuf, sizeof(encbuf), pnt,
    1205           0 :                                                   ecom->disable_ieee_floating);
    1206             :                         else
    1207             :                                 unk_ecom = 1;
    1208             :                 } else if (type == ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS) {
    1209           0 :                         sub_type = *pnt++;
    1210           0 :                         if (sub_type == ECOMMUNITY_ORIGIN_VALIDATION_STATE)
    1211           0 :                                 ecommunity_origin_validation_state_str(
    1212             :                                         encbuf, sizeof(encbuf), pnt);
    1213             :                         else
    1214             :                                 unk_ecom = 1;
    1215             :                 } else {
    1216           0 :                         sub_type = *pnt++;
    1217           0 :                         unk_ecom = 1;
    1218             :                 }
    1219             : 
    1220           0 :                 if (unk_ecom)
    1221           0 :                         snprintf(encbuf, sizeof(encbuf), "UNK:%d, %d", type,
    1222             :                                  sub_type);
    1223             : 
    1224           0 :                 int r = strlcat(str_buf, encbuf, str_size);
    1225           0 :                 assert(r < str_size);
    1226             :         }
    1227             : 
    1228             :         return str_buf;
    1229             : }
    1230             : 
    1231           0 : bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2)
    1232             : {
    1233           0 :         uint32_t i, j;
    1234             : 
    1235           0 :         if (!e1 || !e2)
    1236             :                 return false;
    1237           0 :         for (i = 0; i < e1->size; ++i) {
    1238           0 :                 for (j = 0; j < e2->size; ++j) {
    1239           0 :                         if (!memcmp(e1->val + (i * e1->unit_size),
    1240           0 :                                     e2->val + (j * e2->unit_size),
    1241           0 :                                     e1->unit_size))
    1242             :                                 return true;
    1243             :                 }
    1244             :         }
    1245             :         return false;
    1246             : }
    1247             : 
    1248           0 : bool ecommunity_match(const struct ecommunity *ecom1,
    1249             :                       const struct ecommunity *ecom2)
    1250             : {
    1251           0 :         uint32_t i = 0;
    1252           0 :         uint32_t j = 0;
    1253             : 
    1254           0 :         if (ecom1 == NULL && ecom2 == NULL)
    1255             :                 return true;
    1256             : 
    1257           0 :         if (ecom1 == NULL || ecom2 == NULL)
    1258             :                 return false;
    1259             : 
    1260           0 :         if (ecom1->size < ecom2->size)
    1261             :                 return false;
    1262             : 
    1263             :         /* Every community on com2 needs to be on com1 for this to match */
    1264           0 :         while (i < ecom1->size && j < ecom2->size) {
    1265           0 :                 if (memcmp(ecom1->val + i * ecom1->unit_size,
    1266           0 :                            ecom2->val + j * ecom2->unit_size,
    1267           0 :                            ecom2->unit_size)
    1268             :                     == 0)
    1269           0 :                         j++;
    1270           0 :                 i++;
    1271             :         }
    1272             : 
    1273           0 :         if (j == ecom2->size)
    1274             :                 return true;
    1275             :         else
    1276           0 :                 return false;
    1277             : }
    1278             : 
    1279             : /* return first occurence of type */
    1280           0 : extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *ecom,
    1281             :                                                 uint8_t type, uint8_t subtype)
    1282             : {
    1283           0 :         uint8_t *p;
    1284           0 :         uint32_t c;
    1285             : 
    1286             :         /* If the value already exists in the structure return 0.  */
    1287           0 :         c = 0;
    1288           0 :         for (p = ecom->val; c < ecom->size; p += ecom->unit_size, c++) {
    1289           0 :                 if (p == NULL) {
    1290           0 :                         continue;
    1291             :                 }
    1292           0 :                 if (p[0] == type && p[1] == subtype)
    1293           0 :                         return (struct ecommunity_val *)p;
    1294             :         }
    1295             :         return NULL;
    1296             : }
    1297             : 
    1298             : /* remove ext. community matching type and subtype
    1299             :  * return 1 on success ( removed ), 0 otherwise (not present)
    1300             :  */
    1301           0 : bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
    1302             :                       uint8_t subtype)
    1303             : {
    1304           0 :         uint8_t *p, *q, *new;
    1305           0 :         uint32_t c, found = 0;
    1306             :         /* When this is fist value, just add it.  */
    1307           0 :         if (ecom == NULL || ecom->val == NULL)
    1308             :                 return false;
    1309             : 
    1310             :         /* Check if any existing ext community matches. */
    1311             :         /* Certain extended communities like the Route Target can be present
    1312             :          * multiple times, handle that.
    1313             :          */
    1314             :         c = 0;
    1315           0 :         for (p = ecom->val; c < ecom->size; p += ecom->unit_size, c++) {
    1316           0 :                 if (p[0] == type && p[1] == subtype)
    1317           0 :                         found++;
    1318             :         }
    1319             :         /* If no matching ext community exists, return. */
    1320           0 :         if (found == 0)
    1321             :                 return false;
    1322             : 
    1323             :         /* Handle the case where everything needs to be stripped. */
    1324           0 :         if (found == ecom->size) {
    1325           0 :                 XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
    1326           0 :                 ecom->size = 0;
    1327           0 :                 return true;
    1328             :         }
    1329             : 
    1330             :         /* Strip matching ext community(ies). */
    1331           0 :         new = XMALLOC(MTYPE_ECOMMUNITY_VAL,
    1332             :                       (ecom->size - found) * ecom->unit_size);
    1333           0 :         q = new;
    1334           0 :         for (c = 0, p = ecom->val; c < ecom->size; c++, p += ecom->unit_size) {
    1335           0 :                 if (!(p[0] == type && p[1] == subtype)) {
    1336           0 :                         memcpy(q, p, ecom->unit_size);
    1337           0 :                         q += ecom->unit_size;
    1338             :                 }
    1339             :         }
    1340           0 :         XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
    1341           0 :         ecom->val = new;
    1342           0 :         ecom->size -= found;
    1343           0 :         return true;
    1344             : }
    1345             : 
    1346             : /*
    1347             :  * Remove specified extended community value from extended community.
    1348             :  * Returns 1 if value was present (and hence, removed), 0 otherwise.
    1349             :  */
    1350           0 : bool ecommunity_del_val(struct ecommunity *ecom, struct ecommunity_val *eval)
    1351             : {
    1352           0 :         uint8_t *p;
    1353           0 :         uint32_t c, found = 0;
    1354             : 
    1355             :         /* Make sure specified value exists. */
    1356           0 :         if (ecom == NULL || ecom->val == NULL)
    1357             :                 return false;
    1358             :         c = 0;
    1359           0 :         for (p = ecom->val; c < ecom->size; p += ecom->unit_size, c++) {
    1360           0 :                 if (!memcmp(p, eval->val, ecom->unit_size)) {
    1361             :                         found = 1;
    1362             :                         break;
    1363             :                 }
    1364             :         }
    1365           0 :         if (found == 0)
    1366             :                 return false;
    1367             : 
    1368             :         /* Delete the selected value */
    1369           0 :         ecom->size--;
    1370           0 :         if (ecom->size) {
    1371           0 :                 p = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom->size * ecom->unit_size);
    1372           0 :                 if (c != 0)
    1373           0 :                         memcpy(p, ecom->val, c * ecom->unit_size);
    1374           0 :                 if ((ecom->size - c) != 0)
    1375           0 :                         memcpy(p + (c)*ecom->unit_size,
    1376           0 :                                ecom->val + (c + 1) * ecom->unit_size,
    1377           0 :                                (ecom->size - c) * ecom->unit_size);
    1378           0 :                 XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
    1379           0 :                 ecom->val = p;
    1380             :         } else
    1381           0 :                 XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
    1382             : 
    1383             :         return true;
    1384             : }
    1385             : 
    1386           0 : int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
    1387             :                                struct bgp_pbr_entry_action *api,
    1388             :                                afi_t afi)
    1389             : {
    1390           0 :         if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_RATE) {
    1391           0 :                 api->action = ACTION_TRAFFICRATE;
    1392           0 :                 api->u.r.rate_info[3] = ecom_eval->val[4];
    1393           0 :                 api->u.r.rate_info[2] = ecom_eval->val[5];
    1394           0 :                 api->u.r.rate_info[1] = ecom_eval->val[6];
    1395           0 :                 api->u.r.rate_info[0] = ecom_eval->val[7];
    1396           0 :         } else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_ACTION) {
    1397           0 :                 api->action = ACTION_TRAFFIC_ACTION;
    1398             :                 /* else distribute code is set by default */
    1399           0 :                 if (ecom_eval->val[5] & (1 << FLOWSPEC_TRAFFIC_ACTION_TERMINAL))
    1400           0 :                         api->u.za.filter |= TRAFFIC_ACTION_TERMINATE;
    1401             :                 else
    1402           0 :                         api->u.za.filter |= TRAFFIC_ACTION_DISTRIBUTE;
    1403           0 :                 if (ecom_eval->val[5] == 1 << FLOWSPEC_TRAFFIC_ACTION_SAMPLE)
    1404           0 :                         api->u.za.filter |= TRAFFIC_ACTION_SAMPLE;
    1405             : 
    1406           0 :         } else if (ecom_eval->val[1] == ECOMMUNITY_TRAFFIC_MARKING) {
    1407           0 :                 api->action = ACTION_MARKING;
    1408           0 :                 api->u.marking_dscp = ecom_eval->val[7];
    1409           0 :         } else if (ecom_eval->val[1] == ECOMMUNITY_REDIRECT_VRF) {
    1410             :                 /* must use external function */
    1411             :                 return 0;
    1412           0 :         } else if (ecom_eval->val[1] == ECOMMUNITY_REDIRECT_IP_NH &&
    1413           0 :                    afi == AFI_IP) {
    1414             :                 /* see draft-ietf-idr-flowspec-redirect-ip-02
    1415             :                  * Q1: how come a ext. community can host ipv6 address
    1416             :                  * Q2 : from cisco documentation:
    1417             :                  * Announces the reachability of one or more flowspec NLRI.
    1418             :                  * When a BGP speaker receives an UPDATE message with the
    1419             :                  * redirect-to-IP extended community, it is expected to
    1420             :                  * create a traffic filtering rule for every flow-spec
    1421             :                  * NLRI in the message that has this path as its best
    1422             :                  * path. The filter entry matches the IP packets
    1423             :                  * described in the NLRI field and redirects them or
    1424             :                  * copies them towards the IPv4 or IPv6 address specified
    1425             :                  * in the 'Network Address of Next- Hop'
    1426             :                  * field of the associated MP_REACH_NLRI.
    1427             :                  */
    1428           0 :                 struct ecommunity_ip *ip_ecom = (struct ecommunity_ip *)
    1429             :                         ecom_eval + 2;
    1430             : 
    1431           0 :                 api->u.zr.redirect_ip_v4 = ip_ecom->ip;
    1432             :         } else
    1433             :                 return -1;
    1434             :         return 0;
    1435             : }
    1436             : 
    1437           0 : static struct ecommunity *bgp_aggr_ecommunity_lookup(
    1438             :                                                 struct bgp_aggregate *aggregate,
    1439             :                                                 struct ecommunity *ecommunity)
    1440             : {
    1441           0 :         return hash_lookup(aggregate->ecommunity_hash, ecommunity);
    1442             : }
    1443             : 
    1444           0 : static void *bgp_aggr_ecommunty_hash_alloc(void *p)
    1445             : {
    1446           0 :         struct ecommunity *ref = (struct ecommunity *)p;
    1447           0 :         struct ecommunity *ecommunity = NULL;
    1448             : 
    1449           0 :         ecommunity = ecommunity_dup(ref);
    1450           0 :         return ecommunity;
    1451             : }
    1452             : 
    1453           0 : static void bgp_aggr_ecommunity_prepare(struct hash_bucket *hb, void *arg)
    1454             : {
    1455           0 :         struct ecommunity *hb_ecommunity = hb->data;
    1456           0 :         struct ecommunity **aggr_ecommunity = arg;
    1457             : 
    1458           0 :         if (*aggr_ecommunity)
    1459           0 :                 *aggr_ecommunity = ecommunity_merge(*aggr_ecommunity,
    1460             :                                                     hb_ecommunity);
    1461             :         else
    1462           0 :                 *aggr_ecommunity = ecommunity_dup(hb_ecommunity);
    1463           0 : }
    1464             : 
    1465           0 : void bgp_aggr_ecommunity_remove(void *arg)
    1466             : {
    1467           0 :         struct ecommunity *ecommunity = arg;
    1468             : 
    1469           0 :         ecommunity_free(&ecommunity);
    1470           0 : }
    1471             : 
    1472           0 : void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate,
    1473             :                                       struct ecommunity *ecommunity)
    1474             : {
    1475           0 :         bgp_compute_aggregate_ecommunity_hash(aggregate, ecommunity);
    1476           0 :         bgp_compute_aggregate_ecommunity_val(aggregate);
    1477           0 : }
    1478             : 
    1479             : 
    1480           0 : void bgp_compute_aggregate_ecommunity_hash(struct bgp_aggregate *aggregate,
    1481             :                                            struct ecommunity *ecommunity)
    1482             : {
    1483           0 :         struct ecommunity *aggr_ecommunity = NULL;
    1484             : 
    1485           0 :         if ((aggregate == NULL) || (ecommunity == NULL))
    1486             :                 return;
    1487             : 
    1488             :         /* Create hash if not already created.
    1489             :          */
    1490           0 :         if (aggregate->ecommunity_hash == NULL)
    1491           0 :                 aggregate->ecommunity_hash = hash_create(
    1492             :                                         ecommunity_hash_make, ecommunity_cmp,
    1493             :                                         "BGP Aggregator ecommunity hash");
    1494             : 
    1495           0 :         aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity);
    1496           0 :         if (aggr_ecommunity == NULL) {
    1497             :                 /* Insert ecommunity into hash.
    1498             :                  */
    1499           0 :                 aggr_ecommunity = hash_get(aggregate->ecommunity_hash,
    1500             :                                            ecommunity,
    1501             :                                            bgp_aggr_ecommunty_hash_alloc);
    1502             :         }
    1503             : 
    1504             :         /* Increment reference counter.
    1505             :          */
    1506           0 :         aggr_ecommunity->refcnt++;
    1507             : }
    1508             : 
    1509           0 : void bgp_compute_aggregate_ecommunity_val(struct bgp_aggregate *aggregate)
    1510             : {
    1511           0 :         struct ecommunity *ecommerge = NULL;
    1512             : 
    1513           0 :         if (aggregate == NULL)
    1514           0 :                 return;
    1515             : 
    1516             :         /* Re-compute aggregate's ecommunity.
    1517             :          */
    1518           0 :         if (aggregate->ecommunity)
    1519           0 :                 ecommunity_free(&aggregate->ecommunity);
    1520           0 :         if (aggregate->ecommunity_hash
    1521           0 :             && aggregate->ecommunity_hash->count) {
    1522           0 :                 hash_iterate(aggregate->ecommunity_hash,
    1523             :                              bgp_aggr_ecommunity_prepare,
    1524           0 :                              &aggregate->ecommunity);
    1525           0 :                 ecommerge = aggregate->ecommunity;
    1526           0 :                 aggregate->ecommunity = ecommunity_uniq_sort(ecommerge);
    1527           0 :                 if (ecommerge)
    1528           0 :                         ecommunity_free(&ecommerge);
    1529             :         }
    1530             : }
    1531             : 
    1532           0 : void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate,
    1533             :                                           struct ecommunity *ecommunity)
    1534             : {
    1535           0 :         struct ecommunity *aggr_ecommunity = NULL;
    1536           0 :         struct ecommunity *ret_ecomm = NULL;
    1537             : 
    1538           0 :         if ((!aggregate)
    1539           0 :             || (!aggregate->ecommunity_hash)
    1540           0 :             || (!ecommunity))
    1541           0 :                 return;
    1542             : 
    1543             :         /* Look-up the ecommunity in the hash.
    1544             :          */
    1545           0 :         aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity);
    1546           0 :         if (aggr_ecommunity) {
    1547           0 :                 aggr_ecommunity->refcnt--;
    1548             : 
    1549           0 :                 if (aggr_ecommunity->refcnt == 0) {
    1550           0 :                         ret_ecomm = hash_release(aggregate->ecommunity_hash,
    1551             :                                                  aggr_ecommunity);
    1552           0 :                         ecommunity_free(&ret_ecomm);
    1553           0 :                         bgp_compute_aggregate_ecommunity_val(aggregate);
    1554             :                 }
    1555             :         }
    1556             : }
    1557             : 
    1558           0 : void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate *aggregate,
    1559             :                                           struct ecommunity *ecommunity)
    1560             : {
    1561             : 
    1562           0 :         struct ecommunity *aggr_ecommunity = NULL;
    1563           0 :         struct ecommunity *ret_ecomm = NULL;
    1564             : 
    1565           0 :         if ((!aggregate)
    1566           0 :             || (!aggregate->ecommunity_hash)
    1567           0 :             || (!ecommunity))
    1568           0 :                 return;
    1569             : 
    1570             :         /* Look-up the ecommunity in the hash.
    1571             :          */
    1572           0 :         aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity);
    1573           0 :         if (aggr_ecommunity) {
    1574           0 :                 aggr_ecommunity->refcnt--;
    1575             : 
    1576           0 :                 if (aggr_ecommunity->refcnt == 0) {
    1577           0 :                         ret_ecomm = hash_release(aggregate->ecommunity_hash,
    1578             :                                                  aggr_ecommunity);
    1579           0 :                         ecommunity_free(&ret_ecomm);
    1580             :                 }
    1581             :         }
    1582             : }
    1583             : 
    1584             : struct ecommunity *
    1585           0 : ecommunity_add_origin_validation_state(enum rpki_states rpki_state,
    1586             :                                        struct ecommunity *old)
    1587             : {
    1588           0 :         struct ecommunity *new = NULL;
    1589           0 :         struct ecommunity ovs_ecomm = {0};
    1590           0 :         struct ecommunity_val ovs_eval;
    1591             : 
    1592           0 :         encode_origin_validation_state(rpki_state, &ovs_eval);
    1593             : 
    1594           0 :         if (old) {
    1595           0 :                 new = ecommunity_dup(old);
    1596           0 :                 ecommunity_add_val(new, &ovs_eval, true, true);
    1597           0 :                 if (!old->refcnt)
    1598           0 :                         ecommunity_free(&old);
    1599             :         } else {
    1600           0 :                 ovs_ecomm.size = 1;
    1601           0 :                 ovs_ecomm.unit_size = ECOMMUNITY_SIZE;
    1602           0 :                 ovs_ecomm.val = (uint8_t *)&ovs_eval.val;
    1603           0 :                 new = ecommunity_dup(&ovs_ecomm);
    1604             :         }
    1605             : 
    1606           0 :         return new;
    1607             : }
    1608             : 
    1609             : /*
    1610             :  * return the BGP link bandwidth extended community, if present;
    1611             :  * the actual bandwidth is returned via param
    1612             :  */
    1613           0 : const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
    1614             : {
    1615           0 :         const uint8_t *eval;
    1616           0 :         uint32_t i;
    1617             : 
    1618           0 :         if (bw)
    1619           0 :                 *bw = 0;
    1620             : 
    1621           0 :         if (!ecom || !ecom->size)
    1622             :                 return NULL;
    1623             : 
    1624           0 :         for (i = 0; i < ecom->size; i++) {
    1625           0 :                 const uint8_t *pnt;
    1626           0 :                 uint8_t type, sub_type;
    1627           0 :                 uint32_t bwval;
    1628             : 
    1629           0 :                 eval = pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
    1630           0 :                 type = *pnt++;
    1631           0 :                 sub_type = *pnt++;
    1632             : 
    1633           0 :                 if ((type == ECOMMUNITY_ENCODE_AS ||
    1634           0 :                      type == ECOMMUNITY_ENCODE_AS_NON_TRANS) &&
    1635             :                     sub_type == ECOMMUNITY_LINK_BANDWIDTH) {
    1636           0 :                         pnt += 2; /* bandwidth is encoded as AS:val */
    1637           0 :                         pnt = ptr_get_be32(pnt, &bwval);
    1638           0 :                         (void)pnt; /* consume value */
    1639           0 :                         if (bw)
    1640           0 :                                 *bw = ecom->disable_ieee_floating
    1641             :                                               ? bwval
    1642           0 :                                               : ieee_float_uint32_to_uint32(
    1643             :                                                         bwval);
    1644           0 :                         return eval;
    1645             :                 }
    1646             :         }
    1647             : 
    1648             :         return NULL;
    1649             : }
    1650             : 
    1651             : 
    1652           0 : struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom,
    1653             :                                              uint64_t cum_bw,
    1654             :                                              bool disable_ieee_floating)
    1655             : {
    1656           0 :         struct ecommunity *new;
    1657           0 :         struct ecommunity_val lb_eval;
    1658           0 :         const uint8_t *eval;
    1659           0 :         uint8_t type;
    1660           0 :         uint32_t cur_bw;
    1661             : 
    1662             :         /* Nothing to replace if link-bandwidth doesn't exist or
    1663             :          * is non-transitive - just return existing extcommunity.
    1664             :          */
    1665           0 :         new = ecom;
    1666           0 :         if (!ecom || !ecom->size)
    1667             :                 return new;
    1668             : 
    1669           0 :         eval = ecommunity_linkbw_present(ecom, &cur_bw);
    1670           0 :         if (!eval)
    1671             :                 return new;
    1672             : 
    1673           0 :         type = *eval;
    1674           0 :         if (type & ECOMMUNITY_FLAG_NON_TRANSITIVE)
    1675             :                 return new;
    1676             : 
    1677             :         /* Transitive link-bandwidth exists, replace with the passed
    1678             :          * (cumulative) bandwidth value. We need to create a new
    1679             :          * extcommunity for this - refer to AS-Path replace function
    1680             :          * for reference.
    1681             :          */
    1682           0 :         if (cum_bw > 0xFFFFFFFF)
    1683             :                 cum_bw = 0xFFFFFFFF;
    1684           0 :         encode_lb_extcomm(as > BGP_AS_MAX ? BGP_AS_TRANS : as, cum_bw, false,
    1685             :                           &lb_eval, disable_ieee_floating);
    1686           0 :         new = ecommunity_dup(ecom);
    1687           0 :         ecommunity_add_val(new, &lb_eval, true, true);
    1688             : 
    1689           0 :         return new;
    1690             : }

Generated by: LCOV version v1.16-topotato