blob: 9f4aaa4bf0745da41b7691673d1a27fbb6cf3da2 [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. */
Stephen Hemmingerffa4e2c2009-05-15 10:28:11 -070033static struct hash *ecomhash;
paul718e3742002-12-13 20:15:29 +000034
35/* Allocate a new ecommunities. */
Stephen Hemmingerffa4e2c2009-05-15 10:28:11 -070036static struct ecommunity *
Stephen Hemminger66e5cd82009-02-09 10:14:16 -080037ecommunity_new (void)
paul718e3742002-12-13 20:15:29 +000038{
39 return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY,
40 sizeof (struct ecommunity));
41}
42
43/* Allocate ecommunities. */
44void
Paul Jakmaf6f434b2010-11-23 21:28:03 +000045ecommunity_free (struct ecommunity **ecom)
paul718e3742002-12-13 20:15:29 +000046{
Paul Jakmaf6f434b2010-11-23 21:28:03 +000047 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 ecom = NULL;
paul718e3742002-12-13 20:15:29 +000053}
54
55/* Add a new Extended Communities value to Extended Communities
56 Attribute structure. When the value is already exists in the
57 structure, we don't add the value. Newly added value is sorted by
58 numerical order. When the value is added to the structure return 1
59 else return 0. */
60static int
61ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval)
62{
paul5228ad22004-06-04 17:58:18 +000063 u_int8_t *p;
paul718e3742002-12-13 20:15:29 +000064 int ret;
65 int c;
66
67 /* When this is fist value, just add it. */
68 if (ecom->val == NULL)
69 {
70 ecom->size++;
71 ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom));
72 memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE);
73 return 1;
74 }
75
76 /* If the value already exists in the structure return 0. */
77 c = 0;
78 for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++)
79 {
80 ret = memcmp (p, eval->val, ECOMMUNITY_SIZE);
81 if (ret == 0)
82 return 0;
83 if (ret > 0)
84 break;
85 }
86
87 /* Add the value to the structure with numerical sorting. */
88 ecom->size++;
89 ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom));
90
91 memmove (ecom->val + (c + 1) * ECOMMUNITY_SIZE,
92 ecom->val + c * ECOMMUNITY_SIZE,
93 (ecom->size - 1 - c) * ECOMMUNITY_SIZE);
94 memcpy (ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE);
95
96 return 1;
97}
98
99/* This function takes pointer to Extended Communites strucutre then
100 create a new Extended Communities structure by uniq and sort each
Denis Ovsienkoe6b6a562009-06-01 20:20:36 +0400101 Extended Communities value. */
Josh Bailey0b597ef2011-07-20 20:49:11 -0700102struct ecommunity *
paul718e3742002-12-13 20:15:29 +0000103ecommunity_uniq_sort (struct ecommunity *ecom)
104{
105 int i;
106 struct ecommunity *new;
107 struct ecommunity_val *eval;
108
109 if (! ecom)
110 return NULL;
111
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800112 new = ecommunity_new ();
paul718e3742002-12-13 20:15:29 +0000113
114 for (i = 0; i < ecom->size; i++)
115 {
116 eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE));
117 ecommunity_add_val (new, eval);
118 }
119 return new;
120}
121
122/* Parse Extended Communites Attribute in BGP packet. */
123struct ecommunity *
paul5228ad22004-06-04 17:58:18 +0000124ecommunity_parse (u_int8_t *pnt, u_short length)
paul718e3742002-12-13 20:15:29 +0000125{
126 struct ecommunity tmp;
127 struct ecommunity *new;
128
129 /* Length check. */
130 if (length % ECOMMUNITY_SIZE)
131 return NULL;
132
133 /* Prepare tmporary structure for making a new Extended Communities
134 Attribute. */
135 tmp.size = length / ECOMMUNITY_SIZE;
136 tmp.val = pnt;
137
138 /* Create a new Extended Communities Attribute by uniq and sort each
139 Extended Communities value */
140 new = ecommunity_uniq_sort (&tmp);
141
142 return ecommunity_intern (new);
143}
144
145/* Duplicate the Extended Communities Attribute structure. */
146struct ecommunity *
147ecommunity_dup (struct ecommunity *ecom)
148{
149 struct ecommunity *new;
150
151 new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity));
152 new->size = ecom->size;
153 if (new->size)
154 {
155 new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE);
156 memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE);
157 }
158 else
159 new->val = NULL;
160 return new;
161}
162
hasso4372df72004-05-20 10:20:02 +0000163/* Retrun string representation of communities attribute. */
164char *
165ecommunity_str (struct ecommunity *ecom)
166{
167 if (! ecom->str)
168 ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
169 return ecom->str;
170}
171
paul718e3742002-12-13 20:15:29 +0000172/* Merge two Extended Communities Attribute structure. */
173struct ecommunity *
174ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2)
175{
176 if (ecom1->val)
177 ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val,
178 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
179 else
180 ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL,
181 (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE);
182
183 memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE),
184 ecom2->val, ecom2->size * ECOMMUNITY_SIZE);
185 ecom1->size += ecom2->size;
186
187 return ecom1;
188}
189
190/* Intern Extended Communities Attribute. */
191struct ecommunity *
192ecommunity_intern (struct ecommunity *ecom)
193{
194 struct ecommunity *find;
195
196 assert (ecom->refcnt == 0);
197
198 find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern);
199
200 if (find != ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000201 ecommunity_free (&ecom);
paul718e3742002-12-13 20:15:29 +0000202
203 find->refcnt++;
204
205 if (! find->str)
206 find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY);
207
208 return find;
209}
210
211/* Unintern Extended Communities Attribute. */
212void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000213ecommunity_unintern (struct ecommunity **ecom)
paul718e3742002-12-13 20:15:29 +0000214{
215 struct ecommunity *ret;
216
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000217 if ((*ecom)->refcnt)
218 (*ecom)->refcnt--;
219
paul718e3742002-12-13 20:15:29 +0000220 /* Pull off from hash. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000221 if ((*ecom)->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000222 {
223 /* Extended community must be in the hash. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000224 ret = (struct ecommunity *) hash_release (ecomhash, *ecom);
paul718e3742002-12-13 20:15:29 +0000225 assert (ret != NULL);
226
227 ecommunity_free (ecom);
228 }
229}
230
231/* Utinity function to make hash key. */
232unsigned int
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000233ecommunity_hash_make (void *arg)
paul718e3742002-12-13 20:15:29 +0000234{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000235 const struct ecommunity *ecom = arg;
paul718e3742002-12-13 20:15:29 +0000236 int c;
237 unsigned int key;
paul5228ad22004-06-04 17:58:18 +0000238 u_int8_t *pnt;
paul718e3742002-12-13 20:15:29 +0000239
240 key = 0;
241 pnt = ecom->val;
242
243 for (c = 0; c < ecom->size * ECOMMUNITY_SIZE; c++)
244 key += pnt[c];
245
246 return key;
247}
248
249/* Compare two Extended Communities Attribute structure. */
250int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100251ecommunity_cmp (const void *arg1, const void *arg2)
paul718e3742002-12-13 20:15:29 +0000252{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000253 const struct ecommunity *ecom1 = arg1;
254 const struct ecommunity *ecom2 = arg2;
255
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100256 return (ecom1->size == ecom2->size
257 && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0);
paul718e3742002-12-13 20:15:29 +0000258}
259
260/* Initialize Extended Comminities related hash. */
261void
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000262ecommunity_init (void)
paul718e3742002-12-13 20:15:29 +0000263{
264 ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
265}
Chris Caputo228da422009-07-18 05:44:03 +0000266
267void
268ecommunity_finish (void)
269{
270 hash_free (ecomhash);
271 ecomhash = NULL;
272}
paul718e3742002-12-13 20:15:29 +0000273
274/* Extended Communities token enum. */
275enum ecommunity_token
276{
277 ecommunity_token_rt,
278 ecommunity_token_soo,
279 ecommunity_token_val,
280 ecommunity_token_unknown
281};
282
283/* Get next Extended Communities token from the string. */
paul94f2b392005-06-28 12:44:16 +0000284static const char *
paulfd79ac92004-10-13 05:06:08 +0000285ecommunity_gettoken (const char *str, struct ecommunity_val *eval,
paul718e3742002-12-13 20:15:29 +0000286 enum ecommunity_token *token)
287{
288 int ret;
289 int dot = 0;
290 int digit = 0;
291 int separator = 0;
paulfd79ac92004-10-13 05:06:08 +0000292 const char *p = str;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000293 char *endptr;
paul718e3742002-12-13 20:15:29 +0000294 struct in_addr ip;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000295 as_t as = 0;
296 u_int32_t val = 0;
297 char buf[INET_ADDRSTRLEN + 1];
paul718e3742002-12-13 20:15:29 +0000298
299 /* Skip white space. */
300 while (isspace ((int) *p))
301 {
302 p++;
303 str++;
304 }
305
306 /* Check the end of the line. */
307 if (*p == '\0')
308 return NULL;
309
310 /* "rt" and "soo" keyword parse. */
311 if (! isdigit ((int) *p))
312 {
313 /* "rt" match check. */
314 if (tolower ((int) *p) == 'r')
315 {
316 p++;
317 if (tolower ((int) *p) == 't')
318 {
319 p++;
320 *token = ecommunity_token_rt;
321 return p;
322 }
323 if (isspace ((int) *p) || *p == '\0')
324 {
325 *token = ecommunity_token_rt;
326 return p;
327 }
328 goto error;
329 }
330 /* "soo" match check. */
331 else if (tolower ((int) *p) == 's')
332 {
333 p++;
334 if (tolower ((int) *p) == 'o')
335 {
336 p++;
337 if (tolower ((int) *p) == 'o')
338 {
339 p++;
340 *token = ecommunity_token_soo;
341 return p;
342 }
343 if (isspace ((int) *p) || *p == '\0')
344 {
345 *token = ecommunity_token_soo;
346 return p;
347 }
348 goto error;
349 }
350 if (isspace ((int) *p) || *p == '\0')
351 {
352 *token = ecommunity_token_soo;
353 return p;
354 }
355 goto error;
356 }
357 goto error;
358 }
359
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000360 /* What a mess, there are several possibilities:
361 *
362 * a) A.B.C.D:MN
363 * b) EF:OPQR
364 * c) GHJK:MN
365 *
366 * A.B.C.D: Four Byte IP
367 * EF: Two byte ASN
368 * GHJK: Four-byte ASN
369 * MN: Two byte value
370 * OPQR: Four byte value
371 *
372 */
paul718e3742002-12-13 20:15:29 +0000373 while (isdigit ((int) *p) || *p == ':' || *p == '.')
374 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000375 if (*p == ':')
paul718e3742002-12-13 20:15:29 +0000376 {
377 if (separator)
378 goto error;
379
380 separator = 1;
381 digit = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000382
383 if ((p - str) > INET_ADDRSTRLEN)
384 goto error;
385 memset (buf, 0, INET_ADDRSTRLEN + 1);
386 memcpy (buf, str, p - str);
387
paul718e3742002-12-13 20:15:29 +0000388 if (dot)
389 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000390 /* Parsing A.B.C.D in:
391 * A.B.C.D:MN
392 */
393 ret = inet_aton (buf, &ip);
paul718e3742002-12-13 20:15:29 +0000394 if (ret == 0)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000395 goto error;
paul718e3742002-12-13 20:15:29 +0000396 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000397 else
398 {
399 /* ASN */
400 as = strtoul (buf, &endptr, 10);
401 if (*endptr != '\0' || as == BGP_AS4_MAX)
402 goto error;
403 }
paul718e3742002-12-13 20:15:29 +0000404 }
405 else if (*p == '.')
406 {
407 if (separator)
408 goto error;
409 dot++;
410 if (dot > 4)
411 goto error;
412 }
413 else
414 {
415 digit = 1;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000416
417 /* We're past the IP/ASN part */
418 if (separator)
419 {
420 val *= 10;
421 val += (*p - '0');
422 }
paul718e3742002-12-13 20:15:29 +0000423 }
424 p++;
425 }
426
427 /* Low digit part must be there. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000428 if (!digit || !separator)
paul718e3742002-12-13 20:15:29 +0000429 goto error;
430
431 /* Encode result into routing distinguisher. */
432 if (dot)
433 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000434 if (val > UINT16_MAX)
435 goto error;
436
paul718e3742002-12-13 20:15:29 +0000437 eval->val[0] = ECOMMUNITY_ENCODE_IP;
438 eval->val[1] = 0;
439 memcpy (&eval->val[2], &ip, sizeof (struct in_addr));
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000440 eval->val[6] = (val >> 8) & 0xff;
441 eval->val[7] = val & 0xff;
442 }
443 else if (as > BGP_AS_MAX)
444 {
445 if (val > UINT16_MAX)
446 goto error;
447
448 eval->val[0] = ECOMMUNITY_ENCODE_AS4;
449 eval->val[1] = 0;
450 eval->val[2] = (as >>24) & 0xff;
451 eval->val[3] = (as >>16) & 0xff;
452 eval->val[4] = (as >>8) & 0xff;
453 eval->val[5] = as & 0xff;
454 eval->val[6] = (val >> 8) & 0xff;
455 eval->val[7] = val & 0xff;
paul718e3742002-12-13 20:15:29 +0000456 }
457 else
458 {
459 eval->val[0] = ECOMMUNITY_ENCODE_AS;
460 eval->val[1] = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000461
462 eval->val[2] = (as >>8) & 0xff;
463 eval->val[3] = as & 0xff;
464 eval->val[4] = (val >>24) & 0xff;
465 eval->val[5] = (val >>16) & 0xff;
466 eval->val[6] = (val >>8) & 0xff;
467 eval->val[7] = val & 0xff;
paul718e3742002-12-13 20:15:29 +0000468 }
469 *token = ecommunity_token_val;
470 return p;
471
472 error:
473 *token = ecommunity_token_unknown;
474 return p;
475}
476
477/* Convert string to extended community attribute.
478
479 When type is already known, please specify both str and type. str
480 should not include keyword such as "rt" and "soo". Type is
481 ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN.
482 keyword_included should be zero.
483
484 For example route-map's "set extcommunity" command case:
485
486 "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3"
487 type = ECOMMUNITY_ROUTE_TARGET
488 keyword_included = 0
489
490 "soo 100:1" -> str = "100:1"
491 type = ECOMMUNITY_SITE_ORIGIN
492 keyword_included = 0
493
494 When string includes keyword for each extended community value.
495 Please specify keyword_included as non-zero value.
496
497 For example standard extcommunity-list case:
498
499 "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1"
500 type = 0
501 keyword_include = 1
502*/
503struct ecommunity *
paulfd79ac92004-10-13 05:06:08 +0000504ecommunity_str2com (const char *str, int type, int keyword_included)
paul718e3742002-12-13 20:15:29 +0000505{
506 struct ecommunity *ecom = NULL;
507 enum ecommunity_token token;
508 struct ecommunity_val eval;
509 int keyword = 0;
510
511 while ((str = ecommunity_gettoken (str, &eval, &token)))
512 {
513 switch (token)
514 {
515 case ecommunity_token_rt:
516 case ecommunity_token_soo:
517 if (! keyword_included || keyword)
518 {
519 if (ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000520 ecommunity_free (&ecom);
paul718e3742002-12-13 20:15:29 +0000521 return NULL;
522 }
523 keyword = 1;
524
525 if (token == ecommunity_token_rt)
526 {
527 type = ECOMMUNITY_ROUTE_TARGET;
528 }
529 if (token == ecommunity_token_soo)
530 {
531 type = ECOMMUNITY_SITE_ORIGIN;
532 }
533 break;
534 case ecommunity_token_val:
535 if (keyword_included)
536 {
537 if (! keyword)
538 {
539 if (ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000540 ecommunity_free (&ecom);
paul718e3742002-12-13 20:15:29 +0000541 return NULL;
542 }
543 keyword = 0;
544 }
545 if (ecom == NULL)
546 ecom = ecommunity_new ();
547 eval.val[1] = type;
548 ecommunity_add_val (ecom, &eval);
549 break;
550 case ecommunity_token_unknown:
551 default:
552 if (ecom)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000553 ecommunity_free (&ecom);
paul718e3742002-12-13 20:15:29 +0000554 return NULL;
paul718e3742002-12-13 20:15:29 +0000555 }
556 }
557 return ecom;
558}
559
560/* Convert extended community attribute to string.
561
562 Due to historical reason of industry standard implementation, there
563 are three types of format.
564
565 route-map set extcommunity format
566 "rt 100:1 100:2"
567 "soo 100:3"
568
569 extcommunity-list
570 "rt 100:1 rt 100:2 soo 100:3"
571
572 "show ip bgp" and extcommunity-list regular expression matching
573 "RT:100:1 RT:100:2 SoO:100:3"
574
575 For each formath please use below definition for format:
576
577 ECOMMUNITY_FORMAT_ROUTE_MAP
578 ECOMMUNITY_FORMAT_COMMUNITY_LIST
579 ECOMMUNITY_FORMAT_DISPLAY
580*/
581char *
582ecommunity_ecom2str (struct ecommunity *ecom, int format)
583{
584 int i;
paul5228ad22004-06-04 17:58:18 +0000585 u_int8_t *pnt;
paul718e3742002-12-13 20:15:29 +0000586 int encode = 0;
587 int type = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000588#define ECOMMUNITY_STR_DEFAULT_LEN 27
paul718e3742002-12-13 20:15:29 +0000589 int str_size;
590 int str_pnt;
paul5228ad22004-06-04 17:58:18 +0000591 char *str_buf;
paulfd79ac92004-10-13 05:06:08 +0000592 const char *prefix;
paul718e3742002-12-13 20:15:29 +0000593 int len = 0;
594 int first = 1;
595
596 /* For parse Extended Community attribute tupple. */
597 struct ecommunity_as
598 {
599 as_t as;
600 u_int32_t val;
601 } eas;
602
603 struct ecommunity_ip
604 {
605 struct in_addr ip;
606 u_int16_t val;
607 } eip;
608
609 if (ecom->size == 0)
610 {
611 str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1);
612 str_buf[0] = '\0';
613 return str_buf;
614 }
615
616 /* Prepare buffer. */
617 str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1);
618 str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1;
619 str_pnt = 0;
620
621 for (i = 0; i < ecom->size; i++)
622 {
CROSS94431db2011-09-26 13:17:05 +0400623 /* Make it sure size is enough. */
624 while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size)
625 {
626 str_size *= 2;
627 str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
628 }
629
hasso4372df72004-05-20 10:20:02 +0000630 /* Space between each value. */
631 if (! first)
632 str_buf[str_pnt++] = ' ';
633
paul718e3742002-12-13 20:15:29 +0000634 pnt = ecom->val + (i * 8);
635
636 /* High-order octet of type. */
637 encode = *pnt++;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000638 if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP
639 && encode != ECOMMUNITY_ENCODE_AS4)
paul718e3742002-12-13 20:15:29 +0000640 {
hasso4372df72004-05-20 10:20:02 +0000641 len = sprintf (str_buf + str_pnt, "?");
642 str_pnt += len;
643 first = 0;
644 continue;
paul718e3742002-12-13 20:15:29 +0000645 }
646
647 /* Low-order octet of type. */
648 type = *pnt++;
649 if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
650 {
hasso4372df72004-05-20 10:20:02 +0000651 len = sprintf (str_buf + str_pnt, "?");
652 str_pnt += len;
653 first = 0;
654 continue;
paul718e3742002-12-13 20:15:29 +0000655 }
656
657 switch (format)
658 {
659 case ECOMMUNITY_FORMAT_COMMUNITY_LIST:
660 prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo ");
661 break;
662 case ECOMMUNITY_FORMAT_DISPLAY:
663 prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:");
664 break;
665 case ECOMMUNITY_FORMAT_ROUTE_MAP:
666 prefix = "";
667 break;
668 default:
hasso4372df72004-05-20 10:20:02 +0000669 prefix = "";
paul718e3742002-12-13 20:15:29 +0000670 break;
671 }
672
paul718e3742002-12-13 20:15:29 +0000673 /* Put string into buffer. */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000674 if (encode == ECOMMUNITY_ENCODE_AS4)
675 {
676 eas.as = (*pnt++ << 24);
677 eas.as |= (*pnt++ << 16);
678 eas.as |= (*pnt++ << 8);
679 eas.as |= (*pnt++);
680
681 eas.val = (*pnt++ << 8);
682 eas.val |= (*pnt++);
683
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400684 len = sprintf( str_buf + str_pnt, "%s%u:%d", prefix,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000685 eas.as, eas.val );
686 str_pnt += len;
687 first = 0;
688 }
paul718e3742002-12-13 20:15:29 +0000689 if (encode == ECOMMUNITY_ENCODE_AS)
690 {
691 eas.as = (*pnt++ << 8);
692 eas.as |= (*pnt++);
693
694 eas.val = (*pnt++ << 24);
695 eas.val |= (*pnt++ << 16);
696 eas.val |= (*pnt++ << 8);
697 eas.val |= (*pnt++);
698
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400699 len = sprintf (str_buf + str_pnt, "%s%u:%d", prefix,
paul718e3742002-12-13 20:15:29 +0000700 eas.as, eas.val);
701 str_pnt += len;
702 first = 0;
703 }
704 else if (encode == ECOMMUNITY_ENCODE_IP)
705 {
706 memcpy (&eip.ip, pnt, 4);
707 pnt += 4;
708 eip.val = (*pnt++ << 8);
709 eip.val |= (*pnt++);
710
711 len = sprintf (str_buf + str_pnt, "%s%s:%d", prefix,
712 inet_ntoa (eip.ip), eip.val);
713 str_pnt += len;
714 first = 0;
715 }
716 }
717 return str_buf;
718}
hasso4372df72004-05-20 10:20:02 +0000719
720int
paulfd79ac92004-10-13 05:06:08 +0000721ecommunity_match (const struct ecommunity *ecom1,
722 const struct ecommunity *ecom2)
hasso4372df72004-05-20 10:20:02 +0000723{
724 int i = 0;
725 int j = 0;
726
727 if (ecom1 == NULL && ecom2 == NULL)
728 return 1;
729
730 if (ecom1 == NULL || ecom2 == NULL)
731 return 0;
732
733 if (ecom1->size < ecom2->size)
734 return 0;
735
736 /* Every community on com2 needs to be on com1 for this to match */
737 while (i < ecom1->size && j < ecom2->size)
738 {
739 if (memcmp (ecom1->val + i, ecom2->val + j, ECOMMUNITY_SIZE) == 0)
740 j++;
741 i++;
742 }
743
744 if (j == ecom2->size)
745 return 1;
746 else
747 return 0;
748}
749