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