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