]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_ecommunity.c
zebra: Add hash name to mpls hash
[mirror_frr.git] / bgpd / bgp_ecommunity.c
CommitLineData
718e3744 1/* BGP Extended Communities Attribute
896014f4
DL
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 */
718e3744 20
21#include <zebra.h>
22
23#include "hash.h"
24#include "memory.h"
25#include "prefix.h"
26#include "command.h"
3f9c7369 27#include "queue.h"
039f3a34 28#include "filter.h"
718e3744 29
30#include "bgpd/bgpd.h"
31#include "bgpd/bgp_ecommunity.h"
57d187bc 32#include "bgpd/bgp_lcommunity.h"
0b2aa3a0 33#include "bgpd/bgp_aspath.h"
718e3744 34
35/* Hash of community attribute. */
ffa4e2c4 36static struct hash *ecomhash;
6b0655a2 37
718e3744 38/* Allocate a new ecommunities. */
d62a17ae 39struct ecommunity *ecommunity_new(void)
718e3744 40{
d62a17ae 41 return (struct ecommunity *)XCALLOC(MTYPE_ECOMMUNITY,
42 sizeof(struct ecommunity));
718e3744 43}
44
45/* Allocate ecommunities. */
d62a17ae 46void ecommunity_free(struct ecommunity **ecom)
718e3744 47{
d62a17ae 48 if ((*ecom)->val)
49 XFREE(MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
50 if ((*ecom)->str)
51 XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str);
52 XFREE(MTYPE_ECOMMUNITY, *ecom);
53 ecom = NULL;
718e3744 54}
55
d62a17ae 56static void ecommunity_hash_free(struct ecommunity *ecom)
7bae2fb9 57{
d62a17ae 58 ecommunity_free(&ecom);
7bae2fb9
LB
59}
60
61
718e3744 62/* Add a new Extended Communities value to Extended Communities
63 Attribute structure. When the value is already exists in the
64 structure, we don't add the value. Newly added value is sorted by
65 numerical order. When the value is added to the structure return 1
66 else return 0. */
d62a17ae 67int ecommunity_add_val(struct ecommunity *ecom, struct ecommunity_val *eval)
718e3744 68{
d62a17ae 69 u_int8_t *p;
70 int ret;
71 int c;
72
73 /* When this is fist value, just add it. */
74 if (ecom->val == NULL) {
75 ecom->size++;
76 ecom->val = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom_length(ecom));
77 memcpy(ecom->val, eval->val, ECOMMUNITY_SIZE);
78 return 1;
79 }
80
81 /* If the value already exists in the structure return 0. */
82 c = 0;
83 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) {
84 ret = memcmp(p, eval->val, ECOMMUNITY_SIZE);
85 if (ret == 0)
86 return 0;
87 if (ret > 0)
88 break;
89 }
90
91 /* Add the value to the structure with numerical sorting. */
92 ecom->size++;
93 ecom->val =
94 XREALLOC(MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length(ecom));
95
96 memmove(ecom->val + (c + 1) * ECOMMUNITY_SIZE,
97 ecom->val + c * ECOMMUNITY_SIZE,
98 (ecom->size - 1 - c) * ECOMMUNITY_SIZE);
99 memcpy(ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE);
100
101 return 1;
718e3744 102}
103
104/* This function takes pointer to Extended Communites strucutre then
105 create a new Extended Communities structure by uniq and sort each
e6b6a564 106 Extended Communities value. */
d62a17ae 107struct ecommunity *ecommunity_uniq_sort(struct ecommunity *ecom)
718e3744 108{
d62a17ae 109 int i;
110 struct ecommunity *new;
111 struct ecommunity_val *eval;
112
113 if (!ecom)
114 return NULL;
115
116 new = ecommunity_new();
117
118 for (i = 0; i < ecom->size; i++) {
119 eval = (struct ecommunity_val *)(ecom->val
120 + (i * ECOMMUNITY_SIZE));
121 ecommunity_add_val(new, eval);
122 }
123 return new;
718e3744 124}
125
126/* Parse Extended Communites Attribute in BGP packet. */
d62a17ae 127struct ecommunity *ecommunity_parse(u_int8_t *pnt, u_short length)
718e3744 128{
d62a17ae 129 struct ecommunity tmp;
130 struct ecommunity *new;
718e3744 131
d62a17ae 132 /* Length check. */
133 if (length % ECOMMUNITY_SIZE)
134 return NULL;
718e3744 135
d62a17ae 136 /* Prepare tmporary structure for making a new Extended Communities
137 Attribute. */
138 tmp.size = length / ECOMMUNITY_SIZE;
139 tmp.val = pnt;
718e3744 140
d62a17ae 141 /* Create a new Extended Communities Attribute by uniq and sort each
142 Extended Communities value */
143 new = ecommunity_uniq_sort(&tmp);
718e3744 144
d62a17ae 145 return ecommunity_intern(new);
718e3744 146}
147
148/* Duplicate the Extended Communities Attribute structure. */
d62a17ae 149struct ecommunity *ecommunity_dup(struct ecommunity *ecom)
718e3744 150{
d62a17ae 151 struct ecommunity *new;
152
153 new = XCALLOC(MTYPE_ECOMMUNITY, sizeof(struct ecommunity));
154 new->size = ecom->size;
155 if (new->size) {
156 new->val = XMALLOC(MTYPE_ECOMMUNITY_VAL,
157 ecom->size * ECOMMUNITY_SIZE);
158 memcpy(new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE);
159 } else
160 new->val = NULL;
161 return new;
718e3744 162}
163
4372df71 164/* Retrun string representation of communities attribute. */
d62a17ae 165char *ecommunity_str(struct ecommunity *ecom)
4372df71 166{
d62a17ae 167 if (!ecom->str)
168 ecom->str =
169 ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
170 return ecom->str;
4372df71 171}
172
718e3744 173/* Merge two Extended Communities Attribute structure. */
d62a17ae 174struct ecommunity *ecommunity_merge(struct ecommunity *ecom1,
175 struct ecommunity *ecom2)
718e3744 176{
d62a17ae 177 if (ecom1->val)
178 ecom1->val =
179 XREALLOC(MTYPE_ECOMMUNITY_VAL, ecom1->val,
180 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
181 else
182 ecom1->val =
183 XMALLOC(MTYPE_ECOMMUNITY_VAL,
184 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
185
186 memcpy(ecom1->val + (ecom1->size * ECOMMUNITY_SIZE), ecom2->val,
187 ecom2->size * ECOMMUNITY_SIZE);
188 ecom1->size += ecom2->size;
189
190 return ecom1;
718e3744 191}
192
193/* Intern Extended Communities Attribute. */
d62a17ae 194struct ecommunity *ecommunity_intern(struct ecommunity *ecom)
718e3744 195{
d62a17ae 196 struct ecommunity *find;
718e3744 197
d62a17ae 198 assert(ecom->refcnt == 0);
718e3744 199
d62a17ae 200 find = (struct ecommunity *)hash_get(ecomhash, ecom, hash_alloc_intern);
718e3744 201
d62a17ae 202 if (find != ecom)
203 ecommunity_free(&ecom);
718e3744 204
d62a17ae 205 find->refcnt++;
718e3744 206
d62a17ae 207 if (!find->str)
208 find->str =
209 ecommunity_ecom2str(find, ECOMMUNITY_FORMAT_DISPLAY, 0);
718e3744 210
d62a17ae 211 return find;
718e3744 212}
213
214/* Unintern Extended Communities Attribute. */
d62a17ae 215void ecommunity_unintern(struct ecommunity **ecom)
718e3744 216{
d62a17ae 217 struct ecommunity *ret;
218
219 if ((*ecom)->refcnt)
220 (*ecom)->refcnt--;
221
222 /* Pull off from hash. */
223 if ((*ecom)->refcnt == 0) {
224 /* Extended community must be in the hash. */
225 ret = (struct ecommunity *)hash_release(ecomhash, *ecom);
226 assert(ret != NULL);
227
228 ecommunity_free(ecom);
229 }
718e3744 230}
231
232/* Utinity function to make hash key. */
d62a17ae 233unsigned int ecommunity_hash_make(void *arg)
718e3744 234{
d62a17ae 235 const struct ecommunity *ecom = arg;
236 int size = ecom->size * ECOMMUNITY_SIZE;
237 u_int8_t *pnt = ecom->val;
238 unsigned int key = 0;
239 int c;
240
241 for (c = 0; c < size; c += ECOMMUNITY_SIZE) {
242 key += pnt[c];
243 key += pnt[c + 1];
244 key += pnt[c + 2];
245 key += pnt[c + 3];
246 key += pnt[c + 4];
247 key += pnt[c + 5];
248 key += pnt[c + 6];
249 key += pnt[c + 7];
250 }
251
252 return key;
718e3744 253}
254
255/* Compare two Extended Communities Attribute structure. */
d62a17ae 256int ecommunity_cmp(const void *arg1, const void *arg2)
718e3744 257{
d62a17ae 258 const struct ecommunity *ecom1 = arg1;
259 const struct ecommunity *ecom2 = arg2;
260
261 if (ecom1 == NULL && ecom2 == NULL)
262 return 1;
813d4307 263
d62a17ae 264 if (ecom1 == NULL || ecom2 == NULL)
265 return 0;
813d4307 266
d62a17ae 267 return (ecom1->size == ecom2->size
268 && memcmp(ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE)
269 == 0);
718e3744 270}
271
272/* Initialize Extended Comminities related hash. */
d62a17ae 273void ecommunity_init(void)
718e3744 274{
d62a17ae 275 ecomhash = hash_create(ecommunity_hash_make, ecommunity_cmp, NULL);
718e3744 276}
228da428 277
d62a17ae 278void ecommunity_finish(void)
228da428 279{
d62a17ae 280 hash_clean(ecomhash, (void (*)(void *))ecommunity_hash_free);
281 hash_free(ecomhash);
282 ecomhash = NULL;
228da428 283}
6b0655a2 284
718e3744 285/* Extended Communities token enum. */
d62a17ae 286enum ecommunity_token {
287 ecommunity_token_unknown = 0,
288 ecommunity_token_rt,
289 ecommunity_token_soo,
290 ecommunity_token_val,
718e3744 291};
292
c5900768 293/*
294 * Encode BGP extended community from passed values. Supports types
295 * defined in RFC 4360 and well-known sub-types.
296 */
d62a17ae 297static int ecommunity_encode(u_char type, u_char sub_type, int trans, as_t as,
298 struct in_addr ip, u_int32_t val,
299 struct ecommunity_val *eval)
c5900768 300{
d62a17ae 301 assert(eval);
302 if (type == ECOMMUNITY_ENCODE_AS) {
303 if (as > BGP_AS_MAX)
304 return -1;
305 } else if (type == ECOMMUNITY_ENCODE_IP
306 || type == ECOMMUNITY_ENCODE_AS4) {
307 if (val > UINT16_MAX)
308 return -1;
309 }
310
311 /* Fill in the values. */
312 eval->val[0] = type;
313 if (!trans)
314 eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
315 eval->val[1] = sub_type;
316 if (type == ECOMMUNITY_ENCODE_AS) {
317 eval->val[2] = (as >> 8) & 0xff;
318 eval->val[3] = as & 0xff;
319 eval->val[4] = (val >> 24) & 0xff;
320 eval->val[5] = (val >> 16) & 0xff;
321 eval->val[6] = (val >> 8) & 0xff;
322 eval->val[7] = val & 0xff;
323 } else if (type == ECOMMUNITY_ENCODE_IP) {
324 memcpy(&eval->val[2], &ip, sizeof(struct in_addr));
325 eval->val[6] = (val >> 8) & 0xff;
326 eval->val[7] = val & 0xff;
327 } else {
328 eval->val[2] = (as >> 24) & 0xff;
329 eval->val[3] = (as >> 16) & 0xff;
330 eval->val[4] = (as >> 8) & 0xff;
331 eval->val[5] = as & 0xff;
332 eval->val[6] = (val >> 8) & 0xff;
333 eval->val[7] = val & 0xff;
334 }
335
336 return 0;
c5900768 337}
338
718e3744 339/* Get next Extended Communities token from the string. */
d62a17ae 340static const char *ecommunity_gettoken(const char *str,
341 struct ecommunity_val *eval,
342 enum ecommunity_token *token)
718e3744 343{
d62a17ae 344 int ret;
345 int dot = 0;
346 int digit = 0;
347 int separator = 0;
348 const char *p = str;
349 char *endptr;
350 struct in_addr ip;
351 as_t as = 0;
352 u_int32_t val = 0;
353 u_char ecomm_type;
354 char buf[INET_ADDRSTRLEN + 1];
355
356 /* Skip white space. */
357 while (isspace((int)*p)) {
358 p++;
359 str++;
718e3744 360 }
d62a17ae 361
362 /* Check the end of the line. */
363 if (*p == '\0')
364 return NULL;
365
366 /* "rt" and "soo" keyword parse. */
367 if (!isdigit((int)*p)) {
368 /* "rt" match check. */
369 if (tolower((int)*p) == 'r') {
370 p++;
371 if (tolower((int)*p) == 't') {
372 p++;
373 *token = ecommunity_token_rt;
374 return p;
375 }
376 if (isspace((int)*p) || *p == '\0') {
377 *token = ecommunity_token_rt;
378 return p;
379 }
380 goto error;
718e3744 381 }
d62a17ae 382 /* "soo" match check. */
383 else if (tolower((int)*p) == 's') {
384 p++;
385 if (tolower((int)*p) == 'o') {
386 p++;
387 if (tolower((int)*p) == 'o') {
388 p++;
389 *token = ecommunity_token_soo;
390 return p;
391 }
392 if (isspace((int)*p) || *p == '\0') {
393 *token = ecommunity_token_soo;
394 return p;
395 }
396 goto error;
397 }
398 if (isspace((int)*p) || *p == '\0') {
399 *token = ecommunity_token_soo;
400 return p;
401 }
402 goto error;
718e3744 403 }
d62a17ae 404 goto error;
718e3744 405 }
d62a17ae 406
407 /* What a mess, there are several possibilities:
408 *
409 * a) A.B.C.D:MN
410 * b) EF:OPQR
411 * c) GHJK:MN
412 *
413 * A.B.C.D: Four Byte IP
414 * EF: Two byte ASN
415 * GHJK: Four-byte ASN
416 * MN: Two byte value
417 * OPQR: Four byte value
418 *
419 */
420 while (isdigit((int)*p) || *p == ':' || *p == '.') {
421 if (*p == ':') {
422 if (separator)
423 goto error;
424
425 separator = 1;
426 digit = 0;
427
428 if ((p - str) > INET_ADDRSTRLEN)
429 goto error;
430 memset(buf, 0, INET_ADDRSTRLEN + 1);
431 memcpy(buf, str, p - str);
432
433 if (dot) {
434 /* Parsing A.B.C.D in:
435 * A.B.C.D:MN
436 */
437 ret = inet_aton(buf, &ip);
438 if (ret == 0)
439 goto error;
440 } else {
441 /* ASN */
442 as = strtoul(buf, &endptr, 10);
443 if (*endptr != '\0' || as == BGP_AS4_MAX)
444 goto error;
445 }
446 } else if (*p == '.') {
447 if (separator)
448 goto error;
449 dot++;
450 if (dot > 4)
451 goto error;
452 } else {
453 digit = 1;
454
455 /* We're past the IP/ASN part */
456 if (separator) {
457 val *= 10;
458 val += (*p - '0');
459 }
460 }
461 p++;
718e3744 462 }
d62a17ae 463
464 /* Low digit part must be there. */
465 if (!digit || !separator)
466 goto error;
467
468 /* Encode result into extended community. */
469 if (dot)
470 ecomm_type = ECOMMUNITY_ENCODE_IP;
471 else if (as > BGP_AS_MAX)
472 ecomm_type = ECOMMUNITY_ENCODE_AS4;
473 else
474 ecomm_type = ECOMMUNITY_ENCODE_AS;
475 if (ecommunity_encode(ecomm_type, 0, 1, as, ip, val, eval))
476 goto error;
477 *token = ecommunity_token_val;
478 return p;
479
480error:
481 *token = ecommunity_token_unknown;
482 return p;
718e3744 483}
484
d62a17ae 485/* Convert string to extended community attribute.
718e3744 486
487 When type is already known, please specify both str and type. str
488 should not include keyword such as "rt" and "soo". Type is
489 ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
490 keyword_included should be zero.
491
492 For example route-map's "set extcommunity" command case:
493
494 "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
d62a17ae 495 type = ECOMMUNITY_ROUTE_TARGET
496 keyword_included = 0
718e3744 497
498 "soo 100:1" -> str = "100:1"
d62a17ae 499 type = ECOMMUNITY_SITE_ORIGIN
500 keyword_included = 0
718e3744 501
502 When string includes keyword for each extended community value.
503 Please specify keyword_included as non-zero value.
504
505 For example standard extcommunity-list case:
506
507 "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
d62a17ae 508 type = 0
509 keyword_include = 1
718e3744 510*/
d62a17ae 511struct ecommunity *ecommunity_str2com(const char *str, int type,
512 int keyword_included)
718e3744 513{
d62a17ae 514 struct ecommunity *ecom = NULL;
515 enum ecommunity_token token = ecommunity_token_unknown;
516 struct ecommunity_val eval;
517 int keyword = 0;
518
519 while ((str = ecommunity_gettoken(str, &eval, &token))) {
520 switch (token) {
521 case ecommunity_token_rt:
522 case ecommunity_token_soo:
523 if (!keyword_included || keyword) {
524 if (ecom)
525 ecommunity_free(&ecom);
526 return NULL;
527 }
528 keyword = 1;
529
530 if (token == ecommunity_token_rt) {
531 type = ECOMMUNITY_ROUTE_TARGET;
532 }
533 if (token == ecommunity_token_soo) {
534 type = ECOMMUNITY_SITE_ORIGIN;
535 }
536 break;
537 case ecommunity_token_val:
538 if (keyword_included) {
539 if (!keyword) {
540 if (ecom)
541 ecommunity_free(&ecom);
542 return NULL;
543 }
544 keyword = 0;
545 }
546 if (ecom == NULL)
547 ecom = ecommunity_new();
548 eval.val[1] = type;
549 ecommunity_add_val(ecom, &eval);
550 break;
551 case ecommunity_token_unknown:
552 default:
553 if (ecom)
554 ecommunity_free(&ecom);
555 return NULL;
718e3744 556 }
718e3744 557 }
d62a17ae 558 return ecom;
718e3744 559}
560
d62a17ae 561static int ecommunity_rt_soo_str(char *buf, u_int8_t *pnt, int type,
562 int sub_type, int format)
c5900768 563{
d62a17ae 564 int len = 0;
565 const char *prefix;
566
567 /* For parse Extended Community attribute tupple. */
568 struct ecommunity_as {
569 as_t as;
570 u_int32_t val;
571 } eas;
572
573 struct ecommunity_ip {
574 struct in_addr ip;
575 u_int16_t val;
576 } eip;
577
578
579 /* Determine prefix for string, if any. */
580 switch (format) {
581 case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
582 prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
583 break;
584 case ECOMMUNITY_FORMAT_DISPLAY:
585 prefix = (sub_type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
586 break;
587 case ECOMMUNITY_FORMAT_ROUTE_MAP:
588 prefix = "";
589 break;
590 default:
591 prefix = "";
592 break;
593 }
594
595 /* Put string into buffer. */
596 if (type == ECOMMUNITY_ENCODE_AS4) {
597 eas.as = (*pnt++ << 24);
598 eas.as |= (*pnt++ << 16);
599 eas.as |= (*pnt++ << 8);
600 eas.as |= (*pnt++);
601 eas.val = (*pnt++ << 8);
602 eas.val |= (*pnt++);
603
604 len = sprintf(buf, "%s%u:%u", prefix, eas.as, eas.val);
605 } else if (type == ECOMMUNITY_ENCODE_AS) {
606 eas.as = (*pnt++ << 8);
607 eas.as |= (*pnt++);
608
609 eas.val = (*pnt++ << 24);
610 eas.val |= (*pnt++ << 16);
611 eas.val |= (*pnt++ << 8);
612 eas.val |= (*pnt++);
613
614 len = sprintf(buf, "%s%u:%u", prefix, eas.as, eas.val);
615 } else if (type == ECOMMUNITY_ENCODE_IP) {
616 memcpy(&eip.ip, pnt, 4);
617 pnt += 4;
618 eip.val = (*pnt++ << 8);
619 eip.val |= (*pnt++);
620
621 len = sprintf(buf, "%s%s:%u", prefix, inet_ntoa(eip.ip),
622 eip.val);
623 }
624
625 return len;
c5900768 626}
627
d62a17ae 628/* Convert extended community attribute to string.
718e3744 629
630 Due to historical reason of industry standard implementation, there
631 are three types of format.
632
633 route-map set extcommunity format
d62a17ae 634 "rt 100:1 100:2"
635 "soo 100:3"
718e3744 636
637 extcommunity-list
d62a17ae 638 "rt 100:1 rt 100:2 soo 100:3"
718e3744 639
716b2d8a 640 "show [ip] bgp" and extcommunity-list regular expression matching
d62a17ae 641 "RT:100:1 RT:100:2 SoO:100:3"
718e3744 642
643 For each formath please use below definition for format:
644
645 ECOMMUNITY_FORMAT_ROUTE_MAP
646 ECOMMUNITY_FORMAT_COMMUNITY_LIST
647 ECOMMUNITY_FORMAT_DISPLAY
e82202b7 648
d62a17ae 649 Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
e82202b7 650 0 value displays all
718e3744 651*/
d62a17ae 652char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
718e3744 653{
d62a17ae 654 int i;
655 u_int8_t *pnt;
656 int type = 0;
657 int sub_type = 0;
0b2aa3a0 658#define ECOMMUNITY_STR_DEFAULT_LEN 27
d62a17ae 659 int str_size;
660 int str_pnt;
661 char *str_buf;
662 int len = 0;
663 int first = 1;
664
665 if (ecom->size == 0) {
666 str_buf = XMALLOC(MTYPE_ECOMMUNITY_STR, 1);
667 str_buf[0] = '\0';
668 return str_buf;
669 }
670
671 /* Prepare buffer. */
672 str_buf = XMALLOC(MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
673 str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
674 str_buf[0] = '\0';
675 str_pnt = 0;
676
677 for (i = 0; i < ecom->size; i++) {
678 int unk_ecom = 0;
679
680 /* Make it sure size is enough. */
681 while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) {
682 str_size *= 2;
683 str_buf = XREALLOC(MTYPE_ECOMMUNITY_STR, str_buf,
684 str_size);
685 }
686
687 /* Space between each value. */
688 if (!first)
689 str_buf[str_pnt++] = ' ';
690
691 pnt = ecom->val + (i * 8);
692
693 /* High-order octet of type. */
694 type = *pnt++;
695
696 if (type == ECOMMUNITY_ENCODE_AS || type == ECOMMUNITY_ENCODE_IP
697 || type == ECOMMUNITY_ENCODE_AS4) {
698 /* Low-order octet of type. */
699 sub_type = *pnt++;
700 if (sub_type != ECOMMUNITY_ROUTE_TARGET
701 && sub_type != ECOMMUNITY_SITE_ORIGIN)
702 unk_ecom = 1;
703 else
704 len = ecommunity_rt_soo_str(str_buf + str_pnt,
705 pnt, type, sub_type,
706 format);
707 } else if (type == ECOMMUNITY_ENCODE_OPAQUE) {
708 if (filter == ECOMMUNITY_ROUTE_TARGET)
709 continue;
710 if (*pnt == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP) {
711 uint16_t tunneltype;
712 memcpy(&tunneltype, pnt + 5, 2);
713 tunneltype = ntohs(tunneltype);
714 len = sprintf(str_buf + str_pnt, "ET:%d",
715 tunneltype);
716 } else
717 unk_ecom = 1;
718 } else if (type == ECOMMUNITY_ENCODE_EVPN) {
719 if (filter == ECOMMUNITY_ROUTE_TARGET)
720 continue;
721 if (*pnt == ECOMMUNITY_SITE_ORIGIN) {
722 char macaddr[6];
723 pnt++;
724 memcpy(&macaddr, pnt, 6);
725 len = sprintf(
726 str_buf + str_pnt,
727 "EVPN:%02x:%02x:%02x:%02x:%02x:%02x",
728 macaddr[0], macaddr[1], macaddr[2],
729 macaddr[3], macaddr[4], macaddr[5]);
730 } else if (*pnt
731 == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) {
732 u_int32_t seqnum;
733 u_char flags = *++pnt;
734
735 memcpy(&seqnum, pnt + 2, 4);
736 seqnum = ntohl(seqnum);
737 if (flags
738 & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
739 len = sprintf(str_buf + str_pnt,
740 "MM:%u, sticky MAC",
741 seqnum);
742 else
743 len = sprintf(str_buf + str_pnt,
744 "MM:%u", seqnum);
745 } else
746 unk_ecom = 1;
747 } else
748 unk_ecom = 1;
749
750 if (unk_ecom)
751 len = sprintf(str_buf + str_pnt, "?");
752
753 str_pnt += len;
754 first = 0;
94431dbc
C
755 }
756
d62a17ae 757 return str_buf;
718e3744 758}
4372df71 759
d62a17ae 760int ecommunity_match(const struct ecommunity *ecom1,
761 const struct ecommunity *ecom2)
4372df71 762{
d62a17ae 763 int i = 0;
764 int j = 0;
765
766 if (ecom1 == NULL && ecom2 == NULL)
767 return 1;
768
769 if (ecom1 == NULL || ecom2 == NULL)
770 return 0;
771
772 if (ecom1->size < ecom2->size)
773 return 0;
774
775 /* Every community on com2 needs to be on com1 for this to match */
776 while (i < ecom1->size && j < ecom2->size) {
777 if (memcmp(ecom1->val + i * ECOMMUNITY_SIZE,
778 ecom2->val + j * ECOMMUNITY_SIZE, ECOMMUNITY_SIZE)
779 == 0)
780 j++;
781 i++;
782 }
783
784 if (j == ecom2->size)
785 return 1;
786 else
787 return 0;
4372df71 788}
1e27ef50
PG
789
790/* return first occurence of type */
d62a17ae 791extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *ecom,
792 uint8_t type, uint8_t subtype)
1e27ef50 793{
d62a17ae 794 u_int8_t *p;
795 int c;
796
797 /* If the value already exists in the structure return 0. */
798 c = 0;
799 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) {
800 if (p == NULL) {
801 continue;
802 }
803 if (p[0] == type && p[1] == subtype)
804 return (struct ecommunity_val *)p;
805 }
806 return NULL;
1e27ef50
PG
807}
808
809/* remove ext. community matching type and subtype
810 * return 1 on success ( removed ), 0 otherwise (not present)
811 */
d62a17ae 812extern int ecommunity_strip(struct ecommunity *ecom, uint8_t type,
813 uint8_t subtype)
1e27ef50 814{
d62a17ae 815 u_int8_t *p;
816 int c, found = 0;
817 /* When this is fist value, just add it. */
818 if (ecom == NULL || ecom->val == NULL) {
819 return 0;
820 }
821
822 /* If the value already exists in the structure return 0. */
823 c = 0;
824 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) {
825 if (p[0] == type && p[1] == subtype) {
826 found = 1;
827 break;
828 }
829 }
830 if (found == 0)
831 return 0;
832 /* Strip The selected value */
833 ecom->size--;
834 /* size is reduced. no memmove to do */
835 p = XMALLOC(MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
836 if (c != 0)
837 memcpy(p, ecom->val, c * ECOMMUNITY_SIZE);
838 if ((ecom->size - c) != 0)
839 memcpy(p + (c)*ECOMMUNITY_SIZE,
840 ecom->val + (c + 1) * ECOMMUNITY_SIZE,
841 (ecom->size - c) * ECOMMUNITY_SIZE);
842 /* shift last ecommunities */
843 XFREE(MTYPE_ECOMMUNITY, ecom->val);
844 ecom->val = p;
845 return 1;
1e27ef50 846}