]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_ecommunity.c
bgpd: support for router mac extended community
[mirror_frr.git] / bgpd / bgp_ecommunity.c
CommitLineData
718e3744 1/* BGP Extended Communities Attribute
2 Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
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)
e82202b7 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{
287 ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
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;
646 str_pnt = 0;
647
648 for (i = 0; i < ecom->size; i++)
649 {
94431dbc
C
650 /* Make it sure size is enough. */
651 while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
652 {
653 str_size *= 2;
654 str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
655 }
656
4372df71 657 /* Space between each value. */
658 if (! first)
659 str_buf[str_pnt++] = ' ';
660
718e3744 661 pnt = ecom->val + (i * 8);
662
663 /* High-order octet of type. */
664 encode = *pnt++;
0014c301
LB
665
666 switch (encode)
667 {
668 case ECOMMUNITY_ENCODE_AS:
669 case ECOMMUNITY_ENCODE_IP:
670 case ECOMMUNITY_ENCODE_AS4:
671 break;
672
673 case ECOMMUNITY_ENCODE_OPAQUE:
e82202b7
PG
674 if(filter == ECOMMUNITY_ROUTE_TARGET)
675 {
676 first = 0;
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 {
696 first = 0;
697 continue;
698 }
699 if (*pnt == ECOMMUNITY_SITE_ORIGIN)
700 {
701 char macaddr[6];
702 pnt++;
703 memcpy(&macaddr, pnt, 6);
704 len = sprintf(str_buf + str_pnt, "EVPN:%02x:%02x:%02x:%02x:%02x:%02x",
705 macaddr[0], macaddr[1], macaddr[2],
706 macaddr[3], macaddr[4], macaddr[5]);
707 str_pnt += len;
708 first = 0;
709 continue;
710 }
711 len = sprintf (str_buf + str_pnt, "?");
712 str_pnt += len;
713 first = 0;
714 continue;
0014c301
LB
715 default:
716 len = sprintf (str_buf + str_pnt, "?");
717 str_pnt += len;
718 first = 0;
719 continue;
720 }
721
718e3744 722 /* Low-order octet of type. */
723 type = *pnt++;
724 if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
725 {
4372df71 726 len = sprintf (str_buf + str_pnt, "?");
727 str_pnt += len;
728 first = 0;
729 continue;
718e3744 730 }
731
732 switch (format)
733 {
734 case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
735 prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
736 break;
737 case ECOMMUNITY_FORMAT_DISPLAY:
738 prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
739 break;
740 case ECOMMUNITY_FORMAT_ROUTE_MAP:
741 prefix = "";
742 break;
743 default:
4372df71 744 prefix = "";
718e3744 745 break;
746 }
747
718e3744 748 /* Put string into buffer. */
0b2aa3a0
PJ
749 if (encode == ECOMMUNITY_ENCODE_AS4)
750 {
751 eas.as = (*pnt++ << 24);
752 eas.as |= (*pnt++ << 16);
753 eas.as |= (*pnt++ << 8);
754 eas.as |= (*pnt++);
755
756 eas.val = (*pnt++ << 8);
757 eas.val |= (*pnt++);
758
4a7ac06c 759 len = sprintf( str_buf + str_pnt, "%s%u:%u", prefix,
0b2aa3a0
PJ
760 eas.as, eas.val );
761 str_pnt += len;
762 first = 0;
763 }
718e3744 764 if (encode == ECOMMUNITY_ENCODE_AS)
765 {
766 eas.as = (*pnt++ << 8);
767 eas.as |= (*pnt++);
768
769 eas.val = (*pnt++ << 24);
770 eas.val |= (*pnt++ << 16);
771 eas.val |= (*pnt++ << 8);
772 eas.val |= (*pnt++);
773
4a7ac06c 774 len = sprintf (str_buf + str_pnt, "%s%u:%u", prefix,
718e3744 775 eas.as, eas.val);
776 str_pnt += len;
777 first = 0;
778 }
779 else if (encode == ECOMMUNITY_ENCODE_IP)
780 {
781 memcpy (&eip.ip, pnt, 4);
782 pnt += 4;
783 eip.val = (*pnt++ << 8);
784 eip.val |= (*pnt++);
785
4a7ac06c 786 len = sprintf (str_buf + str_pnt, "%s%s:%u", prefix,
718e3744 787 inet_ntoa (eip.ip), eip.val);
788 str_pnt += len;
789 first = 0;
790 }
791 }
792 return str_buf;
793}
4372df71 794
795int
fd79ac91 796ecommunity_match (const struct ecommunity *ecom1,
797 const struct ecommunity *ecom2)
4372df71 798{
799 int i = 0;
800 int j = 0;
801
802 if (ecom1 == NULL && ecom2 == NULL)
803 return 1;
804
805 if (ecom1 == NULL || ecom2 == NULL)
806 return 0;
807
808 if (ecom1->size < ecom2->size)
809 return 0;
810
811 /* Every community on com2 needs to be on com1 for this to match */
812 while (i < ecom1->size && j < ecom2->size)
813 {
9cc8cd02
RW
814 if (memcmp (ecom1->val + i * ECOMMUNITY_SIZE,
815 ecom2->val + j * ECOMMUNITY_SIZE,
816 ECOMMUNITY_SIZE) == 0)
4372df71 817 j++;
818 i++;
819 }
820
821 if (j == ecom2->size)
822 return 1;
823 else
824 return 0;
825}
1e27ef50
PG
826
827/* return first occurence of type */
828extern struct ecommunity_val *ecommunity_lookup (const struct ecommunity *ecom, uint8_t type, uint8_t subtype)
829{
830 u_int8_t *p;
831 int c;
832 struct ecommunity_val *ecom_val;
833
834 /* If the value already exists in the structure return 0. */
835 c = 0;
836 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
837 {
838 if(p == NULL)
839 {
840 continue;
841 }
842 if(p[0] == type && p[1] == subtype)
843 return (struct ecommunity_val *)p;
844 }
845 return NULL;
846}
847
848/* remove ext. community matching type and subtype
849 * return 1 on success ( removed ), 0 otherwise (not present)
850 */
851extern int ecommunity_strip (struct ecommunity *ecom, uint8_t type, uint8_t subtype)
852{
853 u_int8_t *p;
854 int c, found = 0;
855 /* When this is fist value, just add it. */
856 if (ecom == NULL || ecom->val == NULL)
857 {
858 return 0;
859 }
860
861 /* If the value already exists in the structure return 0. */
862 c = 0;
863 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
864 {
865 if (p[0] == type && p[1] == subtype)
866 {
867 found = 1;
868 break;
869 }
870 }
871 if (found == 0)
872 return 0;
873 /* Strip The selected value */
874 ecom->size--;
875 /* size is reduced. no memmove to do */
876 p = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
877 if (c != 0)
878 memcpy(p, ecom->val, c * ECOMMUNITY_SIZE);
879 if( (ecom->size - c) != 0)
880 memcpy(p + (c) * ECOMMUNITY_SIZE,
881 ecom->val + (c +1)* ECOMMUNITY_SIZE,
882 (ecom->size - c) * ECOMMUNITY_SIZE);
883 /* shift last ecommunities */
884 XFREE (MTYPE_ECOMMUNITY, ecom->val);
885 ecom->val = p;
886 return 1;
887}