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