]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_ecommunity.c
Merge pull request #582 from qlyoung/ospf6-df-areaid
[mirror_frr.git] / bgpd / bgp_ecommunity.c
1 /* BGP Extended Communities Attribute
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 */
20
21 #include <zebra.h>
22
23 #include "hash.h"
24 #include "memory.h"
25 #include "prefix.h"
26 #include "command.h"
27 #include "queue.h"
28 #include "filter.h"
29
30 #include "bgpd/bgpd.h"
31 #include "bgpd/bgp_ecommunity.h"
32 #include "bgpd/bgp_lcommunity.h"
33 #include "bgpd/bgp_aspath.h"
34
35 /* Hash of community attribute. */
36 static struct hash *ecomhash;
37
38 /* Allocate a new ecommunities. */
39 struct ecommunity *
40 ecommunity_new (void)
41 {
42 return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY,
43 sizeof (struct ecommunity));
44 }
45
46 /* Allocate ecommunities. */
47 void
48 ecommunity_free (struct ecommunity **ecom)
49 {
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;
56 }
57
58 static void
59 ecommunity_hash_free (struct ecommunity *ecom)
60 {
61 ecommunity_free(&ecom);
62 }
63
64
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. */
70 int
71 ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval)
72 {
73 u_int8_t *p;
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
111 Extended Communities value. */
112 struct ecommunity *
113 ecommunity_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
122 new = ecommunity_new ();
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. */
133 struct ecommunity *
134 ecommunity_parse (u_int8_t *pnt, u_short length)
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. */
156 struct ecommunity *
157 ecommunity_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
173 /* Retrun string representation of communities attribute. */
174 char *
175 ecommunity_str (struct ecommunity *ecom)
176 {
177 if (! ecom->str)
178 ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY, 0);
179 return ecom->str;
180 }
181
182 /* Merge two Extended Communities Attribute structure. */
183 struct ecommunity *
184 ecommunity_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. */
201 struct ecommunity *
202 ecommunity_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)
211 ecommunity_free (&ecom);
212
213 find->refcnt++;
214
215 if (! find->str)
216 find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY, 0);
217
218 return find;
219 }
220
221 /* Unintern Extended Communities Attribute. */
222 void
223 ecommunity_unintern (struct ecommunity **ecom)
224 {
225 struct ecommunity *ret;
226
227 if ((*ecom)->refcnt)
228 (*ecom)->refcnt--;
229
230 /* Pull off from hash. */
231 if ((*ecom)->refcnt == 0)
232 {
233 /* Extended community must be in the hash. */
234 ret = (struct ecommunity *) hash_release (ecomhash, *ecom);
235 assert (ret != NULL);
236
237 ecommunity_free (ecom);
238 }
239 }
240
241 /* Utinity function to make hash key. */
242 unsigned int
243 ecommunity_hash_make (void *arg)
244 {
245 const struct ecommunity *ecom = arg;
246 int size = ecom->size * ECOMMUNITY_SIZE;
247 u_int8_t *pnt = ecom->val;
248 unsigned int key = 0;
249 int c;
250
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 }
262
263 return key;
264 }
265
266 /* Compare two Extended Communities Attribute structure. */
267 int
268 ecommunity_cmp (const void *arg1, const void *arg2)
269 {
270 const struct ecommunity *ecom1 = arg1;
271 const struct ecommunity *ecom2 = arg2;
272
273 if (ecom1 == NULL && ecom2 == NULL)
274 return 1;
275
276 if (ecom1 == NULL || ecom2 == NULL)
277 return 0;
278
279 return (ecom1->size == ecom2->size
280 && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0);
281 }
282
283 /* Initialize Extended Comminities related hash. */
284 void
285 ecommunity_init (void)
286 {
287 ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
288 }
289
290 void
291 ecommunity_finish (void)
292 {
293 hash_clean (ecomhash, (void (*)(void *))ecommunity_hash_free);
294 hash_free (ecomhash);
295 ecomhash = NULL;
296 }
297
298 /* Extended Communities token enum. */
299 enum ecommunity_token
300 {
301 ecommunity_token_unknown = 0,
302 ecommunity_token_rt,
303 ecommunity_token_soo,
304 ecommunity_token_val,
305 };
306
307 /* Get next Extended Communities token from the string. */
308 static const char *
309 ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
310 enum ecommunity_token *token)
311 {
312 int ret;
313 int dot = 0;
314 int digit = 0;
315 int separator = 0;
316 const char *p = str;
317 char *endptr;
318 struct in_addr ip;
319 as_t as = 0;
320 u_int32_t val = 0;
321 char buf[INET_ADDRSTRLEN + 1];
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
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 */
397 while (isdigit ((int) *p) || *p == ':' || *p == '.')
398 {
399 if (*p == ':')
400 {
401 if (separator)
402 goto error;
403
404 separator = 1;
405 digit = 0;
406
407 if ((p - str) > INET_ADDRSTRLEN)
408 goto error;
409 memset (buf, 0, INET_ADDRSTRLEN + 1);
410 memcpy (buf, str, p - str);
411
412 if (dot)
413 {
414 /* Parsing A.B.C.D in:
415 * A.B.C.D:MN
416 */
417 ret = inet_aton (buf, &ip);
418 if (ret == 0)
419 goto error;
420 }
421 else
422 {
423 /* ASN */
424 as = strtoul (buf, &endptr, 10);
425 if (*endptr != '\0' || as == BGP_AS4_MAX)
426 goto error;
427 }
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;
440
441 /* We're past the IP/ASN part */
442 if (separator)
443 {
444 val *= 10;
445 val += (*p - '0');
446 }
447 }
448 p++;
449 }
450
451 /* Low digit part must be there. */
452 if (!digit || !separator)
453 goto error;
454
455 /* Encode result into routing distinguisher. */
456 if (dot)
457 {
458 if (val > UINT16_MAX)
459 goto error;
460
461 eval->val[0] = ECOMMUNITY_ENCODE_IP;
462 eval->val[1] = 0;
463 memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
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;
480 }
481 else
482 {
483 eval->val[0] = ECOMMUNITY_ENCODE_AS;
484 eval->val[1] = 0;
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;
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 */
527 struct ecommunity *
528 ecommunity_str2com (const char *str, int type, int keyword_included)
529 {
530 struct ecommunity *ecom = NULL;
531 enum ecommunity_token token = ecommunity_token_unknown;
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)
544 ecommunity_free (&ecom);
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)
564 ecommunity_free (&ecom);
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)
577 ecommunity_free (&ecom);
578 return NULL;
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
596 "show [ip] bgp" and extcommunity-list regular expression matching
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
604
605 Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
606 0 value displays all
607 */
608 char *
609 ecommunity_ecom2str (struct ecommunity *ecom, int format, int filter)
610 {
611 int i;
612 u_int8_t *pnt;
613 int encode = 0;
614 int type = 0;
615 #define ECOMMUNITY_STR_DEFAULT_LEN 27
616 int str_size;
617 int str_pnt;
618 char *str_buf;
619 const char *prefix;
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_buf[0] = '\0';
647 str_pnt = 0;
648
649 for (i = 0; i < ecom->size; i++)
650 {
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
658 /* Space between each value. */
659 if (! first)
660 str_buf[str_pnt++] = ' ';
661
662 pnt = ecom->val + (i * 8);
663
664 /* High-order octet of type. */
665 encode = *pnt++;
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:
675 if(filter == ECOMMUNITY_ROUTE_TARGET)
676 {
677 continue;
678 }
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 }
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 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;
714 default:
715 len = sprintf (str_buf + str_pnt, "?");
716 str_pnt += len;
717 first = 0;
718 continue;
719 }
720
721 /* Low-order octet of type. */
722 type = *pnt++;
723 if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
724 {
725 len = sprintf (str_buf + str_pnt, "?");
726 str_pnt += len;
727 first = 0;
728 continue;
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:
743 prefix = "";
744 break;
745 }
746
747 /* Put string into buffer. */
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
758 len = sprintf( str_buf + str_pnt, "%s%u:%u", prefix,
759 eas.as, eas.val );
760 str_pnt += len;
761 first = 0;
762 }
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
773 len = sprintf (str_buf + str_pnt, "%s%u:%u", prefix,
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
785 len = sprintf (str_buf + str_pnt, "%s%s:%u", prefix,
786 inet_ntoa (eip.ip), eip.val);
787 str_pnt += len;
788 first = 0;
789 }
790 }
791 return str_buf;
792 }
793
794 int
795 ecommunity_match (const struct ecommunity *ecom1,
796 const struct ecommunity *ecom2)
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 {
813 if (memcmp (ecom1->val + i * ECOMMUNITY_SIZE,
814 ecom2->val + j * ECOMMUNITY_SIZE,
815 ECOMMUNITY_SIZE) == 0)
816 j++;
817 i++;
818 }
819
820 if (j == ecom2->size)
821 return 1;
822 else
823 return 0;
824 }
825
826 /* return first occurence of type */
827 extern struct ecommunity_val *ecommunity_lookup (const struct ecommunity *ecom, uint8_t type, uint8_t subtype)
828 {
829 u_int8_t *p;
830 int c;
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 */
849 extern 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 }