blob: 9e7ae1b3e4bdeefb1ee2cf6c09dc8867b5725610 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* 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"
27
28#include "bgpd/bgpd.h"
29#include "bgpd/bgp_ecommunity.h"
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000030#include "bgpd/bgp_aspath.h"
paul718e3742002-12-13 20:15:29 +000031
32/* Hash of community attribute. */
33struct hash *ecomhash;
34
35/* Allocate a new ecommunities. */
36struct ecommunity *
37ecommunity_new ()
38{
39 return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY,
40 sizeof (struct ecommunity));
41}
42
43/* Allocate ecommunities. */
44void
45ecommunity_free (struct ecommunity *ecom)
46{
47 if (ecom->val)
48 XFREE (MTYPE_ECOMMUNITY_VAL, ecom->val);
49 if (ecom->str)
50 XFREE (MTYPE_ECOMMUNITY_STR, ecom->str);
51 XFREE (MTYPE_ECOMMUNITY, ecom);
52}
53
54/* Add a new Extended Communities value to Extended Communities
55 Attribute structure. When the value is already exists in the
56 structure, we don't add the value. Newly added value is sorted by
57 numerical order. When the value is added to the structure return 1
58 else return 0. */
59static int
60ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval)
61{
paul5228ad22004-06-04 17:58:18 +000062 u_int8_t *p;
paul718e3742002-12-13 20:15:29 +000063 int ret;
64 int c;
65
66 /* When this is fist value, just add it. */
67 if (ecom->val == NULL)
68 {
69 ecom->size++;
70 ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom));
71 memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE);
72 return 1;
73 }
74
75 /* If the value already exists in the structure return 0. */
76 c = 0;
77 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
78 {
79 ret = memcmp (p, eval->val, ECOMMUNITY_SIZE);
80 if (ret == 0)
81 return 0;
82 if (ret > 0)
83 break;
84 }
85
86 /* Add the value to the structure with numerical sorting. */
87 ecom->size++;
88 ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom));
89
90 memmove (ecom->val + (c + 1) * ECOMMUNITY_SIZE,
91 ecom->val + c * ECOMMUNITY_SIZE,
92 (ecom->size - 1 - c) * ECOMMUNITY_SIZE);
93 memcpy (ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE);
94
95 return 1;
96}
97
98/* This function takes pointer to Extended Communites strucutre then
99 create a new Extended Communities structure by uniq and sort each
100 Exteneded Communities value. */
paul94f2b392005-06-28 12:44:16 +0000101static struct ecommunity *
paul718e3742002-12-13 20:15:29 +0000102ecommunity_uniq_sort (struct ecommunity *ecom)
103{
104 int i;
105 struct ecommunity *new;
106 struct ecommunity_val *eval;
107
108 if (! ecom)
109 return NULL;
110
111 new = ecommunity_new ();;
112
113 for (i = 0; i < ecom->size; i++)
114 {
115 eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE));
116 ecommunity_add_val (new, eval);
117 }
118 return new;
119}
120
121/* Parse Extended Communites Attribute in BGP packet. */
122struct ecommunity *
paul5228ad22004-06-04 17:58:18 +0000123ecommunity_parse (u_int8_t *pnt, u_short length)
paul718e3742002-12-13 20:15:29 +0000124{
125 struct ecommunity tmp;
126 struct ecommunity *new;
127
128 /* Length check. */
129 if (length % ECOMMUNITY_SIZE)
130 return NULL;
131
132 /* Prepare tmporary structure for making a new Extended Communities
133 Attribute. */
134 tmp.size = length / ECOMMUNITY_SIZE;
135 tmp.val = pnt;
136
137 /* Create a new Extended Communities Attribute by uniq and sort each
138 Extended Communities value */
139 new = ecommunity_uniq_sort (&tmp);
140
141 return ecommunity_intern (new);
142}
143
144/* Duplicate the Extended Communities Attribute structure. */
145struct ecommunity *
146ecommunity_dup (struct ecommunity *ecom)
147{
148 struct ecommunity *new;
149
150 new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity));
151 new->size = ecom->size;
152 if (new->size)
153 {
154 new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
155 memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE);
156 }
157 else
158 new->val = NULL;
159 return new;
160}
161
hasso4372df72004-05-20 10:20:02 +0000162/* Retrun string representation of communities attribute. */
163char *
164ecommunity_str (struct ecommunity *ecom)
165{
166 if (! ecom->str)
167 ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
168 return ecom->str;
169}
170
paul718e3742002-12-13 20:15:29 +0000171/* Merge two Extended Communities Attribute structure. */
172struct ecommunity *
173ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2)
174{
175 if (ecom1->val)
176 ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val,
177 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
178 else
179 ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL,
180 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
181
182 memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE),
183 ecom2->val, ecom2->size * ECOMMUNITY_SIZE);
184 ecom1->size += ecom2->size;
185
186 return ecom1;
187}
188
189/* Intern Extended Communities Attribute. */
190struct ecommunity *
191ecommunity_intern (struct ecommunity *ecom)
192{
193 struct ecommunity *find;
194
195 assert (ecom->refcnt == 0);
196
197 find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern);
198
199 if (find != ecom)
200 ecommunity_free (ecom);
201
202 find->refcnt++;
203
204 if (! find->str)
205 find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY);
206
207 return find;
208}
209
210/* Unintern Extended Communities Attribute. */
211void
212ecommunity_unintern (struct ecommunity *ecom)
213{
214 struct ecommunity *ret;
215
216 if (ecom->refcnt)
217 ecom->refcnt--;
218
219 /* Pull off from hash. */
220 if (ecom->refcnt == 0)
221 {
222 /* Extended community must be in the hash. */
223 ret = (struct ecommunity *) hash_release (ecomhash, ecom);
224 assert (ret != NULL);
225
226 ecommunity_free (ecom);
227 }
228}
229
230/* Utinity function to make hash key. */
231unsigned int
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000232ecommunity_hash_make (void *arg)
paul718e3742002-12-13 20:15:29 +0000233{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000234 const struct ecommunity *ecom = arg;
paul718e3742002-12-13 20:15:29 +0000235 int c;
236 unsigned int key;
paul5228ad22004-06-04 17:58:18 +0000237 u_int8_t *pnt;
paul718e3742002-12-13 20:15:29 +0000238
239 key = 0;
240 pnt = ecom->val;
241
242 for (c = 0; c < ecom->size * ECOMMUNITY_SIZE; c++)
243 key += pnt[c];
244
245 return key;
246}
247
248/* Compare two Extended Communities Attribute structure. */
249int
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000250ecommunity_cmp (void *arg1, void *arg2)
paul718e3742002-12-13 20:15:29 +0000251{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000252 const struct ecommunity *ecom1 = arg1;
253 const struct ecommunity *ecom2 = arg2;
254
paul718e3742002-12-13 20:15:29 +0000255 if (ecom1->size == ecom2->size
256 && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0)
257 return 1;
258 return 0;
259}
260
261/* Initialize Extended Comminities related hash. */
262void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000263ecommunity_init (void)
paul718e3742002-12-13 20:15:29 +0000264{
265 ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
266}
267
268/* Extended Communities token enum. */
269enum ecommunity_token
270{
271 ecommunity_token_rt,
272 ecommunity_token_soo,
273 ecommunity_token_val,
274 ecommunity_token_unknown
275};
276
277/* Get next Extended Communities token from the string. */
paul94f2b392005-06-28 12:44:16 +0000278static const char *
paulfd79ac92004-10-13 05:06:08 +0000279ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
paul718e3742002-12-13 20:15:29 +0000280 enum ecommunity_token *token)
281{
282 int ret;
283 int dot = 0;
284 int digit = 0;
285 int separator = 0;
paulfd79ac92004-10-13 05:06:08 +0000286 const char *p = str;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000287 char *endptr;
paul718e3742002-12-13 20:15:29 +0000288 struct in_addr ip;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000289 as_t as = 0;
290 u_int32_t val = 0;
291 char buf[INET_ADDRSTRLEN + 1];
paul718e3742002-12-13 20:15:29 +0000292
293 /* Skip white space. */
294 while (isspace ((int) *p))
295 {
296 p++;
297 str++;
298 }
299
300 /* Check the end of the line. */
301 if (*p == '\0')
302 return NULL;
303
304 /* "rt" and "soo" keyword parse. */
305 if (! isdigit ((int) *p))
306 {
307 /* "rt" match check. */
308 if (tolower ((int) *p) == 'r')
309 {
310 p++;
311 if (tolower ((int) *p) == 't')
312 {
313 p++;
314 *token = ecommunity_token_rt;
315 return p;
316 }
317 if (isspace ((int) *p) || *p == '\0')
318 {
319 *token = ecommunity_token_rt;
320 return p;
321 }
322 goto error;
323 }
324 /* "soo" match check. */
325 else if (tolower ((int) *p) == 's')
326 {
327 p++;
328 if (tolower ((int) *p) == 'o')
329 {
330 p++;
331 if (tolower ((int) *p) == 'o')
332 {
333 p++;
334 *token = ecommunity_token_soo;
335 return p;
336 }
337 if (isspace ((int) *p) || *p == '\0')
338 {
339 *token = ecommunity_token_soo;
340 return p;
341 }
342 goto error;
343 }
344 if (isspace ((int) *p) || *p == '\0')
345 {
346 *token = ecommunity_token_soo;
347 return p;
348 }
349 goto error;
350 }
351 goto error;
352 }
353
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000354 /* What a mess, there are several possibilities:
355 *
356 * a) A.B.C.D:MN
357 * b) EF:OPQR
358 * c) GHJK:MN
359 *
360 * A.B.C.D: Four Byte IP
361 * EF: Two byte ASN
362 * GHJK: Four-byte ASN
363 * MN: Two byte value
364 * OPQR: Four byte value
365 *
366 */
paul718e3742002-12-13 20:15:29 +0000367 while (isdigit ((int) *p) || *p == ':' || *p == '.')
368 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000369 if (*p == ':')
paul718e3742002-12-13 20:15:29 +0000370 {
371 if (separator)
372 goto error;
373
374 separator = 1;
375 digit = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000376
377 if ((p - str) > INET_ADDRSTRLEN)
378 goto error;
379 memset (buf, 0, INET_ADDRSTRLEN + 1);
380 memcpy (buf, str, p - str);
381
paul718e3742002-12-13 20:15:29 +0000382 if (dot)
383 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000384 /* Parsing A.B.C.D in:
385 * A.B.C.D:MN
386 */
387 ret = inet_aton (buf, &ip);
paul718e3742002-12-13 20:15:29 +0000388 if (ret == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000389 goto error;
paul718e3742002-12-13 20:15:29 +0000390 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000391 else
392 {
393 /* ASN */
394 as = strtoul (buf, &endptr, 10);
395 if (*endptr != '\0' || as == BGP_AS4_MAX)
396 goto error;
397 }
paul718e3742002-12-13 20:15:29 +0000398 }
399 else if (*p == '.')
400 {
401 if (separator)
402 goto error;
403 dot++;
404 if (dot > 4)
405 goto error;
406 }
407 else
408 {
409 digit = 1;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000410
411 /* We're past the IP/ASN part */
412 if (separator)
413 {
414 val *= 10;
415 val += (*p - '0');
416 }
paul718e3742002-12-13 20:15:29 +0000417 }
418 p++;
419 }
420
421 /* Low digit part must be there. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000422 if (!digit || !separator)
paul718e3742002-12-13 20:15:29 +0000423 goto error;
424
425 /* Encode result into routing distinguisher. */
426 if (dot)
427 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000428 if (val > UINT16_MAX)
429 goto error;
430
paul718e3742002-12-13 20:15:29 +0000431 eval->val[0] = ECOMMUNITY_ENCODE_IP;
432 eval->val[1] = 0;
433 memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000434 eval->val[6] = (val >> 8) & 0xff;
435 eval->val[7] = val & 0xff;
436 }
437 else if (as > BGP_AS_MAX)
438 {
439 if (val > UINT16_MAX)
440 goto error;
441
442 eval->val[0] = ECOMMUNITY_ENCODE_AS4;
443 eval->val[1] = 0;
444 eval->val[2] = (as >>24) & 0xff;
445 eval->val[3] = (as >>16) & 0xff;
446 eval->val[4] = (as >>8) & 0xff;
447 eval->val[5] = as & 0xff;
448 eval->val[6] = (val >> 8) & 0xff;
449 eval->val[7] = val & 0xff;
paul718e3742002-12-13 20:15:29 +0000450 }
451 else
452 {
453 eval->val[0] = ECOMMUNITY_ENCODE_AS;
454 eval->val[1] = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000455
456 eval->val[2] = (as >>8) & 0xff;
457 eval->val[3] = as & 0xff;
458 eval->val[4] = (val >>24) & 0xff;
459 eval->val[5] = (val >>16) & 0xff;
460 eval->val[6] = (val >>8) & 0xff;
461 eval->val[7] = val & 0xff;
paul718e3742002-12-13 20:15:29 +0000462 }
463 *token = ecommunity_token_val;
464 return p;
465
466 error:
467 *token = ecommunity_token_unknown;
468 return p;
469}
470
471/* Convert string to extended community attribute.
472
473 When type is already known, please specify both str and type. str
474 should not include keyword such as "rt" and "soo". Type is
475 ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
476 keyword_included should be zero.
477
478 For example route-map's "set extcommunity" command case:
479
480 "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
481 type = ECOMMUNITY_ROUTE_TARGET
482 keyword_included = 0
483
484 "soo 100:1" -> str = "100:1"
485 type = ECOMMUNITY_SITE_ORIGIN
486 keyword_included = 0
487
488 When string includes keyword for each extended community value.
489 Please specify keyword_included as non-zero value.
490
491 For example standard extcommunity-list case:
492
493 "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
494 type = 0
495 keyword_include = 1
496*/
497struct ecommunity *
paulfd79ac92004-10-13 05:06:08 +0000498ecommunity_str2com (const char *str, int type, int keyword_included)
paul718e3742002-12-13 20:15:29 +0000499{
500 struct ecommunity *ecom = NULL;
501 enum ecommunity_token token;
502 struct ecommunity_val eval;
503 int keyword = 0;
504
505 while ((str = ecommunity_gettoken (str, &eval, &token)))
506 {
507 switch (token)
508 {
509 case ecommunity_token_rt:
510 case ecommunity_token_soo:
511 if (! keyword_included || keyword)
512 {
513 if (ecom)
514 ecommunity_free (ecom);
515 return NULL;
516 }
517 keyword = 1;
518
519 if (token == ecommunity_token_rt)
520 {
521 type = ECOMMUNITY_ROUTE_TARGET;
522 }
523 if (token == ecommunity_token_soo)
524 {
525 type = ECOMMUNITY_SITE_ORIGIN;
526 }
527 break;
528 case ecommunity_token_val:
529 if (keyword_included)
530 {
531 if (! keyword)
532 {
533 if (ecom)
534 ecommunity_free (ecom);
535 return NULL;
536 }
537 keyword = 0;
538 }
539 if (ecom == NULL)
540 ecom = ecommunity_new ();
541 eval.val[1] = type;
542 ecommunity_add_val (ecom, &eval);
543 break;
544 case ecommunity_token_unknown:
545 default:
546 if (ecom)
547 ecommunity_free (ecom);
548 return NULL;
paul718e3742002-12-13 20:15:29 +0000549 }
550 }
551 return ecom;
552}
553
554/* Convert extended community attribute to string.
555
556 Due to historical reason of industry standard implementation, there
557 are three types of format.
558
559 route-map set extcommunity format
560 "rt 100:1 100:2"
561 "soo 100:3"
562
563 extcommunity-list
564 "rt 100:1 rt 100:2 soo 100:3"
565
566 "show ip bgp" and extcommunity-list regular expression matching
567 "RT:100:1 RT:100:2 SoO:100:3"
568
569 For each formath please use below definition for format:
570
571 ECOMMUNITY_FORMAT_ROUTE_MAP
572 ECOMMUNITY_FORMAT_COMMUNITY_LIST
573 ECOMMUNITY_FORMAT_DISPLAY
574*/
575char *
576ecommunity_ecom2str (struct ecommunity *ecom, int format)
577{
578 int i;
paul5228ad22004-06-04 17:58:18 +0000579 u_int8_t *pnt;
paul718e3742002-12-13 20:15:29 +0000580 int encode = 0;
581 int type = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000582#define ECOMMUNITY_STR_DEFAULT_LEN 27
paul718e3742002-12-13 20:15:29 +0000583 int str_size;
584 int str_pnt;
paul5228ad22004-06-04 17:58:18 +0000585 char *str_buf;
paulfd79ac92004-10-13 05:06:08 +0000586 const char *prefix;
paul718e3742002-12-13 20:15:29 +0000587 int len = 0;
588 int first = 1;
589
590 /* For parse Extended Community attribute tupple. */
591 struct ecommunity_as
592 {
593 as_t as;
594 u_int32_t val;
595 } eas;
596
597 struct ecommunity_ip
598 {
599 struct in_addr ip;
600 u_int16_t val;
601 } eip;
602
603 if (ecom->size == 0)
604 {
605 str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1);
606 str_buf[0] = '\0';
607 return str_buf;
608 }
609
610 /* Prepare buffer. */
611 str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
612 str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
613 str_pnt = 0;
614
615 for (i = 0; i < ecom->size; i++)
616 {
hasso4372df72004-05-20 10:20:02 +0000617 /* Space between each value. */
618 if (! first)
619 str_buf[str_pnt++] = ' ';
620
paul718e3742002-12-13 20:15:29 +0000621 pnt = ecom->val + (i * 8);
622
623 /* High-order octet of type. */
624 encode = *pnt++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000625 if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP
626 && encode != ECOMMUNITY_ENCODE_AS4)
paul718e3742002-12-13 20:15:29 +0000627 {
hasso4372df72004-05-20 10:20:02 +0000628 len = sprintf (str_buf + str_pnt, "?");
629 str_pnt += len;
630 first = 0;
631 continue;
paul718e3742002-12-13 20:15:29 +0000632 }
633
634 /* Low-order octet of type. */
635 type = *pnt++;
636 if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
637 {
hasso4372df72004-05-20 10:20:02 +0000638 len = sprintf (str_buf + str_pnt, "?");
639 str_pnt += len;
640 first = 0;
641 continue;
paul718e3742002-12-13 20:15:29 +0000642 }
643
644 switch (format)
645 {
646 case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
647 prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
648 break;
649 case ECOMMUNITY_FORMAT_DISPLAY:
650 prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
651 break;
652 case ECOMMUNITY_FORMAT_ROUTE_MAP:
653 prefix = "";
654 break;
655 default:
hasso4372df72004-05-20 10:20:02 +0000656 prefix = "";
paul718e3742002-12-13 20:15:29 +0000657 break;
658 }
659
660 /* Make it sure size is enough. */
661 while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
662 {
663 str_size *= 2;
664 str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
665 }
666
paul718e3742002-12-13 20:15:29 +0000667 /* Put string into buffer. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000668 if (encode == ECOMMUNITY_ENCODE_AS4)
669 {
670 eas.as = (*pnt++ << 24);
671 eas.as |= (*pnt++ << 16);
672 eas.as |= (*pnt++ << 8);
673 eas.as |= (*pnt++);
674
675 eas.val = (*pnt++ << 8);
676 eas.val |= (*pnt++);
677
678 len = sprintf( str_buf + str_pnt, "%s%d:%d", prefix,
679 eas.as, eas.val );
680 str_pnt += len;
681 first = 0;
682 }
paul718e3742002-12-13 20:15:29 +0000683 if (encode == ECOMMUNITY_ENCODE_AS)
684 {
685 eas.as = (*pnt++ << 8);
686 eas.as |= (*pnt++);
687
688 eas.val = (*pnt++ << 24);
689 eas.val |= (*pnt++ << 16);
690 eas.val |= (*pnt++ << 8);
691 eas.val |= (*pnt++);
692
693 len = sprintf (str_buf + str_pnt, "%s%d:%d", prefix,
694 eas.as, eas.val);
695 str_pnt += len;
696 first = 0;
697 }
698 else if (encode == ECOMMUNITY_ENCODE_IP)
699 {
700 memcpy (&eip.ip, pnt, 4);
701 pnt += 4;
702 eip.val = (*pnt++ << 8);
703 eip.val |= (*pnt++);
704
705 len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix,
706 inet_ntoa (eip.ip), eip.val);
707 str_pnt += len;
708 first = 0;
709 }
710 }
711 return str_buf;
712}
hasso4372df72004-05-20 10:20:02 +0000713
714int
paulfd79ac92004-10-13 05:06:08 +0000715ecommunity_match (const struct ecommunity *ecom1,
716 const struct ecommunity *ecom2)
hasso4372df72004-05-20 10:20:02 +0000717{
718 int i = 0;
719 int j = 0;
720
721 if (ecom1 == NULL && ecom2 == NULL)
722 return 1;
723
724 if (ecom1 == NULL || ecom2 == NULL)
725 return 0;
726
727 if (ecom1->size < ecom2->size)
728 return 0;
729
730 /* Every community on com2 needs to be on com1 for this to match */
731 while (i < ecom1->size && j < ecom2->size)
732 {
733 if (memcmp (ecom1->val + i, ecom2->val + j, ECOMMUNITY_SIZE) == 0)
734 j++;
735 i++;
736 }
737
738 if (j == ecom2->size)
739 return 1;
740 else
741 return 0;
742}
743