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