diff options
author | root <root@hestia.halldom.com> | 2010-07-28 01:04:21 +0100 |
---|---|---|
committer | root <root@hestia.halldom.com> | 2010-07-28 01:04:21 +0100 |
commit | 5992b25ebee1ef68a6f0c9aaa9c67f9f7e6d74e9 (patch) | |
tree | a519f97cadd30fbb8f9219e464a3be5c679f0356 | |
parent | 0f1365093f448e9503b618a5097eb8d6433e7710 (diff) | |
download | quagga-5992b25ebee1ef68a6f0c9aaa9c67f9f7e6d74e9.tar.bz2 quagga-5992b25ebee1ef68a6f0c9aaa9c67f9f7e6d74e9.tar.xz |
Introduce "rs-in" route-map
All peers may be configured with an "rs-in" route-map, whether they
are rsclients, or not.
All routes from a given peer are passed through the "rs-in" route-map
before being considered for inclusion in any rsclients RIBs.
Routes pass through the "rs-in" route-map once, irrespective of the
number of rsclients.
An "rs-in" route-map is intended to be used to ensure that routes
from a given peer are kosher, before being passed to rsclients.
The "in" route-map and filters may do the same, but for the main RIB.
Any route-selection type actions that the "in" route-map may do for
the main RIB will probably be done in the "import" route-map for an
rsclient RIB.
Also:
* make zfree() work for NULL items, in lib/memory.c
* fix clear ip bgp .... so works when pEstablished
Version change to ex03.
-rw-r--r-- | bgpd/bgp_aspath.c | 339 | ||||
-rw-r--r-- | bgpd/bgp_attr.c | 123 | ||||
-rw-r--r-- | bgpd/bgp_peer.h | 20 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 1024 | ||||
-rw-r--r-- | bgpd/bgp_route.h | 27 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 17 | ||||
-rw-r--r-- | bgpd/bgpd.c | 39 | ||||
-rwxr-xr-x | configure.ac | 2 | ||||
-rw-r--r-- | lib/memory.c | 15 | ||||
-rw-r--r-- | lib/routemap.h | 12 |
10 files changed, 1059 insertions, 559 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index a9602d90..1053f1e8 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -34,9 +34,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_attr.h" - + /* Attr. Flags and Attr. Type Code. */ -#define AS_HEADER_SIZE 2 +#define AS_HEADER_SIZE 2 /* Now FOUR octets are used for AS value. */ #define AS_VALUE_SIZE sizeof (as_t) @@ -76,7 +76,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \ && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) ) -/* As segment header - the on-wire representation +/* As segment header - the on-wire representation * NOT the internal representation! */ struct assegment_header @@ -90,7 +90,7 @@ static struct hash *ashash; /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; - + static inline as_t * assegment_data_new (int num) { @@ -112,15 +112,15 @@ static struct assegment * assegment_new (u_char type, u_short length) { struct assegment *new; - + new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment)); - + if (length) new->as = assegment_data_new (length); - + new->length = length; new->type = type; - + return new; } @@ -129,12 +129,12 @@ assegment_free (struct assegment *seg) { if (!seg) return; - + if (seg->as) XFREE (MTYPE_AS_SEG_DATA, seg->as); memset (seg, 0xfe, sizeof(struct assegment)); XFREE (MTYPE_AS_SEG, seg); - + return; } @@ -143,7 +143,7 @@ static void assegment_free_all (struct assegment *seg) { struct assegment *prev; - + while (seg) { prev = seg; @@ -157,10 +157,10 @@ static struct assegment * assegment_dup (struct assegment *seg) { struct assegment *new; - + new = assegment_new (seg->type, seg->length); memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) ); - + return new; } @@ -170,7 +170,7 @@ assegment_dup_all (struct assegment *seg) { struct assegment *new = NULL; struct assegment *head = NULL; - + while (seg) { if (head) @@ -180,7 +180,7 @@ assegment_dup_all (struct assegment *seg) } else head = new = assegment_dup (seg); - + seg = seg->next; } return head; @@ -191,24 +191,24 @@ static struct assegment * assegment_prepend_asns (struct assegment *seg, as_t asnum, int num) { as_t *newas; - + if (!num) return seg; - + if (num >= AS_SEGMENT_MAX) return seg; /* we don't do huge prepends */ - + newas = assegment_data_new (seg->length + num); - + if (newas) { int i; for (i = 0; i < num; i++) newas[i] = asnum; - + memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1)); XFREE (MTYPE_AS_SEG_DATA, seg->as); - seg->as = newas; + seg->as = newas; seg->length += num; return seg; } @@ -222,7 +222,7 @@ static struct assegment * assegment_append_asns (struct assegment *seg, as_t *asnos, int num) { as_t *newas; - + newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as, ASSEGMENT_DATA_SIZE (seg->length + num, 1)); @@ -243,8 +243,8 @@ int_cmp (const void *p1, const void *p2) { const as_t *as1 = p1; const as_t *as2 = p2; - - return (*as1 == *as2) + + return (*as1 == *as2) ? 0 : ( (*as1 > *as2) ? 1 : -1); } @@ -259,14 +259,14 @@ assegment_normalise (struct assegment *head) { struct assegment *seg = head, *pin; struct assegment *tmp; - + if (!head) return head; - + while (seg) { pin = seg; - + /* Sort values SET segments, for determinism in paths to aid * creation of hash values / path comparisons * and because it helps other lesser implementations ;) @@ -275,15 +275,15 @@ assegment_normalise (struct assegment *head) { int tail = 0; int i; - + qsort (seg->as, seg->length, sizeof(as_t), int_cmp); - + /* weed out dupes */ for (i=1; i < seg->length; i++) { if (seg->as[tail] == seg->as[i]) continue; - + tail++; if (tail < i) seg->as[tail] = seg->as[i]; @@ -297,28 +297,28 @@ assegment_normalise (struct assegment *head) * are packable/mergeable. Append all following packable segments * to the segment we have pinned and remove these appended * segments. - */ + */ while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next)) { tmp = pin->next; seg = pin->next; - + /* append the next sequence to the pinned sequence */ pin = assegment_append_asns (pin, seg->as, seg->length); - + /* bypass the next sequence */ pin->next = seg->next; - + /* get rid of the now referenceless segment */ assegment_free (tmp); - + } seg = pin->next; } return head; } - + static struct aspath * aspath_new (void) { @@ -413,14 +413,14 @@ aspath_count_confeds (struct aspath *aspath) { int count = 0; struct assegment *seg = aspath->segments; - + while (seg) { if (seg->type == AS_CONFED_SEQUENCE) count += seg->length; else if (seg->type == AS_CONFED_SET) count++; - + seg = seg->next; } return count; @@ -431,14 +431,14 @@ aspath_count_hops (struct aspath *aspath) { int count = 0; struct assegment *seg = aspath->segments; - + while (seg) { if (seg->type == AS_SEQUENCE) count += seg->length; else if (seg->type == AS_SET) count++; - + seg = seg->next; } return count; @@ -455,7 +455,7 @@ aspath_size (struct aspath *aspath) { int size = 0; struct assegment *seg = aspath->segments; - + while (seg) { size += ASSEGMENT_SIZE(seg->length, 1); @@ -471,7 +471,7 @@ aspath_highest (struct aspath *aspath) struct assegment *seg = aspath->segments; as_t highest = 0; unsigned int i; - + while (seg) { for (i = 0; i < seg->length; i++) @@ -490,7 +490,7 @@ aspath_has_as4 (struct aspath *aspath) { struct assegment *seg = aspath->segments; unsigned int i; - + while (seg) { for (i = 0; i < seg->length; i++) @@ -517,9 +517,9 @@ aspath_make_str_count (struct aspath *as) str_buf[0] = '\0'; return str_buf; } - + seg = as->segments; - + /* ASN takes 5 to 10 chars plus seperator, see below. * If there is one differing segment type, we need an additional * 2 chars for segment delimiters, and the final '\0'. @@ -538,7 +538,7 @@ aspath_make_str_count (struct aspath *as) { int i; char seperator; - + /* Check AS type validity. Set seperator for segment */ switch (seg->type) { @@ -554,7 +554,7 @@ aspath_make_str_count (struct aspath *as) XFREE (MTYPE_AS_STR, str_buf); return NULL; } - + /* We might need to increase str_buf, particularly if path has * differing segments types, our initial guesstimate above will * have been wrong. Need 10 chars for ASN, a seperator each and @@ -572,32 +572,32 @@ aspath_make_str_count (struct aspath *as) } #undef ASN_STR_LEN #undef SEGMENT_STR_LEN - + if (seg->type != AS_SEQUENCE) - len += snprintf (str_buf + len, str_size - len, - "%c", + len += snprintf (str_buf + len, str_size - len, + "%c", aspath_delimiter_char (seg->type, AS_SEG_START)); - + /* write out the ASNs, with their seperators, bar the last one*/ for (i = 0; i < seg->length; i++) { len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]); - + if (i < (seg->length - 1)) len += snprintf (str_buf + len, str_size - len, "%c", seperator); } - + if (seg->type != AS_SEQUENCE) - len += snprintf (str_buf + len, str_size - len, "%c", + len += snprintf (str_buf + len, str_size - len, "%c", aspath_delimiter_char (seg->type, AS_SEG_END)); if (seg->next) len += snprintf (str_buf + len, str_size - len, " "); - + seg = seg->next; } - + assert (len < str_size); - + str_buf[len] = '\0'; return str_buf; @@ -616,7 +616,7 @@ struct aspath * aspath_intern (struct aspath *aspath) { struct aspath *find; - + /* Assert this AS path structure is not interned. */ assert (aspath->refcnt == 0); @@ -660,7 +660,7 @@ aspath_hash_alloc (void *arg) /* New aspath structure is needed. */ aspath = aspath_dup (arg); - + /* Malformed AS path value. */ if (! aspath->str) { @@ -678,40 +678,40 @@ assegments_parse (struct stream *s, size_t length, int use32bit) struct assegment_header segh; struct assegment *seg, *prev = NULL, *head = NULL; size_t bytes = 0; - + /* empty aspath (ie iBGP or somesuch) */ if (length == 0) return NULL; - + if (BGP_DEBUG (as4, AS4_SEGMENT)) zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu", (unsigned long) length); /* basic checks */ if ( (STREAM_READABLE(s) < length) - || (STREAM_READABLE(s) < AS_HEADER_SIZE) + || (STREAM_READABLE(s) < AS_HEADER_SIZE) || (length % AS16_VALUE_SIZE )) return NULL; - + while ( (STREAM_READABLE(s) > AS_HEADER_SIZE) && (bytes < length)) { int i; int seg_size; - + /* softly softly, get the header first on its own */ segh.type = stream_getc (s); segh.length = stream_getc (s); - + seg_size = ASSEGMENT_SIZE(segh.length, use32bit); if (BGP_DEBUG (as4, AS4_SEGMENT)) zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d", segh.type, segh.length); - + /* check it.. */ if ( ((bytes + seg_size) > length) /* 1771bis 4.3b: seg length contains one or more */ - || (segh.length == 0) + || (segh.length == 0) /* Paranoia in case someone changes type of segment length. * Shift both values by 0x10 to make the comparison operate * on more, than 8 bits (otherwise it's a warning, bug #564). @@ -722,27 +722,27 @@ assegments_parse (struct stream *s, size_t length, int use32bit) assegment_free_all (head); return NULL; } - + /* now its safe to trust lengths */ seg = assegment_new (segh.type, segh.length); - + if (head) prev->next = seg; else /* it's the first segment */ head = prev = seg; - + for (i = 0; i < segh.length; i++) seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s); bytes += seg_size; - + if (BGP_DEBUG (as4, AS4_SEGMENT)) zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu", (unsigned long) bytes); - + prev = seg; } - + return assegment_normalise (head); } @@ -757,7 +757,7 @@ aspath_parse (struct stream *s, size_t length, int use32bit) /* If length is odd it's malformed AS path. */ /* Nit-picking: if (use32bit == 0) it is malformed if odd, - * otherwise its malformed when length is larger than 2 and (length-2) + * otherwise its malformed when length is larger than 2 and (length-2) * is not dividable by 4. * But... this time we're lazy */ @@ -766,17 +766,17 @@ aspath_parse (struct stream *s, size_t length, int use32bit) memset (&as, 0, sizeof (struct aspath)); as.segments = assegments_parse (s, length, use32bit); - + /* If already same aspath exist then return it. */ find = hash_get (ashash, &as, aspath_hash_alloc); - + /* aspath_hash_alloc dupes segments too. that probably could be * optimised out. */ assegment_free_all (as.segments); if (as.str) XFREE (MTYPE_AS_STR, as.str); - + if (! find) return NULL; find->refcnt++; @@ -789,7 +789,7 @@ assegment_data_put (struct stream *s, as_t *as, int num, int use32bit) { int i; assert (num <= AS_SEGMENT_MAX); - + for (i = 0; i < num; i++) if ( use32bit ) stream_putl (s, as[i]); @@ -819,10 +819,10 @@ aspath_put (struct stream *s, struct aspath *as, int use32bit ) { struct assegment *seg = as->segments; size_t bytes = 0; - + if (!seg || seg->length == 0) return 0; - + if (seg) { /* @@ -839,7 +839,7 @@ aspath_put (struct stream *s, struct aspath *as, int use32bit ) int written = 0; int asns_packed = 0; size_t lenp; - + /* Overlength segments have to be split up */ while ( (seg->length - written) > AS_SEGMENT_MAX) { @@ -848,12 +848,12 @@ aspath_put (struct stream *s, struct aspath *as, int use32bit ) written += AS_SEGMENT_MAX; bytes += ASSEGMENT_SIZE (written, use32bit); } - + /* write the final segment, probably is also the first */ lenp = assegment_header_put (s, seg->type, seg->length - written); - assegment_data_put (s, (seg->as + written), seg->length - written, + assegment_data_put (s, (seg->as + written), seg->length - written, use32bit); - + /* Sequence-type segments can be 'packed' together * Case of a segment which was overlength and split up * will be missed here, but that doesn't matter. @@ -868,18 +868,18 @@ aspath_put (struct stream *s, struct aspath *as, int use32bit ) * the segment list twice every time we write out * aspath's. */ - + /* Next segment's data can fit in this one */ assegment_data_put (s, next->as, next->length, use32bit); - + /* update the length of the segment header */ stream_putc_at (s, lenp, seg->length - written + next->length); asns_packed += next->length; - + next = next->next; } - - bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed, + + bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed, use32bit); seg = next; } @@ -900,18 +900,18 @@ aspath_snmp_pathseg (struct aspath *as, size_t *varlen) snmp_stream = stream_new (SNMP_PATHSEG_MAX); else stream_reset (snmp_stream); - + if (!as) { *varlen = 0; return NULL; } aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */ - + *varlen = stream_get_endp (snmp_stream); return stream_pnt(snmp_stream); } - + #define min(A,B) ((A) < (B) ? (A) : (B)) static struct assegment * @@ -943,13 +943,13 @@ aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset, for (i = 0; i < asset->length; i++) if (asset->as[i] == as) return asset; - + asset->length++; - asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as, + asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as, asset->length * AS_VALUE_SIZE); asset->as[asset->length - 1] = as; } - + return asset; } @@ -975,7 +975,7 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2) /* First of all check common leading sequence. */ while (seg1 && seg2) - { + { /* Check segment type. */ if (seg1->type != seg2->type) break; @@ -990,7 +990,7 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2) if (match) { struct assegment *seg = assegment_new (seg1->type, 0); - + seg = assegment_append_asns (seg, seg1->as, match); if (! aspath) @@ -1000,14 +1000,14 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2) } else prevseg->next = seg; - + prevseg = seg; } - if (match != minlen || match != seg1->length + if (match != minlen || match != seg1->length || seg1->length != seg2->length) break; - + seg1 = seg1->next; seg2 = seg2->next; } @@ -1021,7 +1021,7 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2) { for (i = from; i < seg1->length; i++) asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]); - + from = 0; seg1 = seg1->next; } @@ -1035,7 +1035,7 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2) from = 0; seg2 = seg2->next; } - + assegment_normalise (aspath->segments); aspath_str_update (aspath); return aspath; @@ -1043,13 +1043,13 @@ aspath_aggregate (struct aspath *as1, struct aspath *as2) /* When a BGP router receives an UPDATE with an MP_REACH_NLRI attribute, check the leftmost AS number in the AS_PATH attribute is - or not the peer's AS number. */ + or not the peer's AS number. */ int aspath_firstas_check (struct aspath *aspath, as_t asno) { if ( (aspath == NULL) || (aspath->segments == NULL) ) return 0; - + if (aspath->segments && (aspath->segments->type == AS_SEQUENCE) && (aspath->segments->as[0] == asno )) @@ -1067,17 +1067,17 @@ aspath_loop_check (struct aspath *aspath, as_t asno) if ( (aspath == NULL) || (aspath->segments == NULL) ) return 0; - + seg = aspath->segments; - + while (seg) { int i; - + for (i = 0; i < seg->length; i++) if (seg->as[i] == asno) count++; - + seg = seg->next; } return count; @@ -1088,16 +1088,16 @@ int aspath_private_as_check (struct aspath *aspath) { struct assegment *seg; - + if ( !(aspath && aspath->segments) ) return 0; - + seg = aspath->segments; while (seg) { int i; - + for (i = 0; i < seg->length; i++) { if ( (seg->as[i] < BGP_PRIVATE_AS_MIN) @@ -1155,11 +1155,11 @@ aspath_merge (struct aspath *as1, struct aspath *as2) return NULL; last = new = assegment_dup_all (as1->segments); - + /* find the last valid segment */ while (last && last->next) last = last->next; - + last->next = as2->segments; as2->segments = new; aspath_str_update (as2); @@ -1175,10 +1175,10 @@ aspath_prepend (struct aspath *as1, struct aspath *as2) if (! as1 || ! as2) return NULL; - + seg1 = as1->segments; seg2 = as2->segments; - + /* If as2 is empty, only need to dupe as1's chain onto as2 */ if (seg2 == NULL) { @@ -1186,11 +1186,11 @@ aspath_prepend (struct aspath *as1, struct aspath *as2) aspath_str_update (as2); return as2; } - + /* If as1 is empty AS, no prepending to do. */ if (seg1 == NULL) return as2; - + /* find the tail as1's segment chain. */ while (seg1 && seg1->next) seg1 = seg1->next; @@ -1205,35 +1205,35 @@ aspath_prepend (struct aspath *as1, struct aspath *as2) if (seg1->type == AS_SEQUENCE) { - /* We have two chains of segments, as1->segments and seg2, + /* We have two chains of segments, as1->segments and seg2, * and we have to attach them together, merging the attaching * segments together into one. - * + * * 1. dupe as1->segments onto head of as2 * 2. merge seg2's asns onto last segment of this new chain * 3. attach chain after seg2 */ - + /* dupe as1 onto as2's head */ seg1 = as2->segments = assegment_dup_all (as1->segments); - + /* refind the tail of as2, reusing seg1 */ while (seg1 && seg1->next) seg1 = seg1->next; - + /* merge the old head, seg2, into tail, seg1 */ seg1 = assegment_append_asns (seg1, seg2->as, seg2->length); - + /* bypass the merged seg2, and attach any chain after it to * chain descending from as2's head */ seg1->next = seg2->next; - + /* seg2 is now referenceless and useless*/ assegment_free (seg2); - + /* we've now prepended as1's segment chain to as2, merging - * the inbetween AS_SEQUENCE of seg2 in the process + * the inbetween AS_SEQUENCE of seg2 in the process */ aspath_str_update (as2); return as2; @@ -1244,7 +1244,7 @@ aspath_prepend (struct aspath *as1, struct aspath *as2) return aspath_merge (as1, as2); } /* XXX: Ermmm, what if as1 has multiple segments?? */ - + /* Not reached */ } @@ -1334,7 +1334,7 @@ aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type) { aspath->segments = assegment_new (type, 1); aspath->segments->as[0] = asno; - + if (assegment) assegment_free (assegment); @@ -1343,16 +1343,16 @@ aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type) if (assegment->type == type) aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1); - else + else { /* create new segment - * push it onto head of aspath's segment chain + * push it onto head of aspath's segment chain */ struct assegment *newsegment; - + newsegment = assegment_new (type, 1); newsegment->as[0] = asno; - + newsegment->next = assegment; aspath->segments = newsegment; } @@ -1394,7 +1394,7 @@ aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2) if (!(seg1 && seg2 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE))) return 0; - + if (seg1->as[0] == seg2->as[0]) return 1; @@ -1413,16 +1413,16 @@ aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path) struct assegment *seg, *newseg, *prevseg = NULL; struct aspath *newpath = NULL, *mergedpath; int hops, cpasns = 0; - + if (!aspath) return NULL; - + seg = aspath->segments; - + /* CONFEDs should get reconciled too.. */ hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath)) - aspath_count_hops (as4path); - + if (hops < 0) { if (BGP_DEBUG (as4, AS4)) @@ -1433,10 +1433,10 @@ aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path) */ hops = aspath_count_hops (aspath); } - + if (!hops) return aspath_dup (as4path); - + if ( BGP_DEBUG(as4, AS4)) zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now", aspath->str, as4path->str); @@ -1469,9 +1469,9 @@ aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path) cpasns = MIN(seg->length, hops); hops -= seg->length; } - + assert (cpasns <= seg->length); - + newseg = assegment_new (seg->type, 0); newseg = assegment_append_asns (newseg, seg->as, cpasns); @@ -1486,7 +1486,7 @@ aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path) prevseg = newseg; seg = seg->next; } - + /* We may be able to join some segments here, and we must * do this because... we want normalised aspaths in out hash * and we do not want to stumble in aspath_put. @@ -1495,11 +1495,11 @@ aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path) aspath_free (newpath); mergedpath->segments = assegment_normalise (mergedpath->segments); aspath_str_update (mergedpath); - + if ( BGP_DEBUG(as4, AS4)) zlog_debug ("[AS4] result of synthesizing is %s", mergedpath->str); - + return mergedpath; } @@ -1511,14 +1511,14 @@ aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspat { if (! (aspath1 && aspath2) ) return 0; - + if ( !(aspath1->segments && aspath2->segments) ) return 0; - + if ( (aspath1->segments->type != AS_CONFED_SEQUENCE) || (aspath2->segments->type != AS_CONFED_SEQUENCE) ) return 0; - + if (aspath1->segments->as[0] == aspath2->segments->as[0]) return 1; @@ -1536,18 +1536,18 @@ aspath_delete_confed_seq (struct aspath *aspath) return aspath; seg = aspath->segments; - - /* "if the first path segment of the AS_PATH is + + /* "if the first path segment of the AS_PATH is * of type AS_CONFED_SEQUENCE," */ if (aspath->segments->type != AS_CONFED_SEQUENCE) return aspath; - /* "... that segment and any immediately following segments - * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed + /* "... that segment and any immediately following segments + * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed * from the AS_PATH attribute," */ - while (seg && + while (seg && (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET)) { aspath->segments = seg->next; @@ -1574,7 +1574,7 @@ aspath_as_add (struct aspath *as, as_t asno) if (!seg) return; - + /* Last segment search procedure. */ while (seg->next) seg = seg->next; @@ -1599,6 +1599,9 @@ aspath_segment_add (struct aspath *as, int type) as->segments = new; } +/*------------------------------------------------------------------------------ + * Construct an interned empty AS Path + */ struct aspath * aspath_empty (void) { @@ -1619,9 +1622,9 @@ unsigned long aspath_count (void) { return ashash->count; -} - -/* +} + +/* Theoretically, one as path can have: One BGP packet size should be less than 4096. @@ -1686,15 +1689,15 @@ aspath_gettoken (const char *buf, enum as_token *token, u_long *asno) } /* Check actual AS value. */ - if (isdigit ((int) *p)) + if (isdigit ((int) *p)) { as_t asval; - + *token = as_token_asval; asval = (*p - '0'); p++; - - while (isdigit ((int) *p)) + + while (isdigit ((int) *p)) { asval *= 10; asval += (*p - '0'); @@ -1703,7 +1706,7 @@ aspath_gettoken (const char *buf, enum as_token *token, u_long *asno) *asno = asval; return p; } - + /* There is no match then return unknown token. */ *token = as_token_unknown; return p++; @@ -1774,7 +1777,7 @@ aspath_str2aspath (const char *str) return aspath; } - + /* Make hash value by raw aspath data. */ unsigned int aspath_key_make (void *p) @@ -1784,7 +1787,7 @@ aspath_key_make (void *p) if (!aspath->str) aspath_str_update (aspath); - + key = jhash (aspath->str, strlen(aspath->str), 2334325); return key; @@ -1796,14 +1799,14 @@ aspath_cmp (const void *arg1, const void *arg2) { const struct assegment *seg1 = ((const struct aspath *)arg1)->segments; const struct assegment *seg2 = ((const struct aspath *)arg2)->segments; - + while (seg1 || seg2) { int i; if ((!seg1 && seg2) || (seg1 && !seg2)) return 0; if (seg1->type != seg2->type) - return 0; + return 0; if (seg1->length != seg2->length) return 0; for (i = 0; i < seg1->length; i++) @@ -1827,11 +1830,11 @@ aspath_finish (void) { hash_free (ashash); ashash = NULL; - + if (snmp_stream) stream_free (snmp_stream); } - + /* return and as path value */ const char * aspath_print (struct aspath *as) @@ -1868,7 +1871,7 @@ aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty) void aspath_print_all_vty (struct vty *vty) { - hash_iterate (ashash, + hash_iterate (ashash, (void (*) (struct hash_backet *, void *)) aspath_show_all_iterator, vty); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 7fc9749e..e3ef01d7 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -493,7 +493,38 @@ bgp_attr_hash_alloc (void *p) return attr; } -/* Internet argument attribute. */ +/*------------------------------------------------------------------------------ + * Internet argument attribute. + * + * 1. "internalise" and increase reference count for each of: + * + * attr->aspath + * attr->community + * attr->extra->ecommunity + * attr->extra->cluster + * attr->extra->transit + * + * Noting that the reference count for each of these is zero if they have not + * yet been internalised. + * + * Each of these pointers is updated to point at either a new entry in the + * relevant attribute store, or at the existing entry. + * + * 2. "internalise" the complete attribute object and increase its reference + * count. + * + * If the attribute collection is new, then this function returns a pointer + * to a brand new attribute object, complete with a copy of the attr->extra. + * + * If the attribute collection is not new, then this function returns a + * pointer to the stored attribute object. + * + * In any event, the pointer returned != pointer passed in. + * + * NB: the incoming attr reference count is ignored. + * + * Note that the original attr object remains with its own attr->extra object. + */ struct attr * bgp_attr_intern (struct attr *attr) { @@ -547,8 +578,10 @@ bgp_attr_intern (struct attr *attr) return find; } - -/* Make network statement's attribute. */ +/* Make network statement's attribute. + * + * All elements are interned, but not the attribute set itself. + */ struct attr * bgp_attr_default_set (struct attr *attr, u_char origin) { @@ -641,7 +674,27 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, return new; } -/* Free bgp attribute and aspath. */ +/*------------------------------------------------------------------------------ + * Free bgp attribute and aspath. + * + * For all the elements of the given attributes: + * + * if the reference count != 0, decrement it + * if the reference count is now zero, remove from hash table and discard + * stored value. + * + * For the attribute object itself: + * + * decrement the reference count + * if the reference count is now zero, remove from hash table and discard + * stored value. + * + * So... do NOT do this to a set of attributes whose elements have not been + * interned ! + * + * Can do this to an attribute object which has not been interned, because its + * reference count SHOULD be zero. + */ void bgp_attr_unintern (struct attr *attr) { @@ -652,8 +705,7 @@ bgp_attr_unintern (struct attr *attr) struct cluster_list *cluster = NULL; struct transit *transit = NULL; - /* Decrement attribute reference. */ - attr->refcnt--; + /* Decrement attribute reference. */ aspath = attr->aspath; community = attr->community; if (attr->extra) @@ -663,16 +715,20 @@ bgp_attr_unintern (struct attr *attr) transit = attr->extra->transit; } - /* If reference becomes zero then free attribute object. */ - if (attr->refcnt == 0) + /* If reference becomes zero then free attribute object. */ + if (attr->refcnt != 0) { - ret = hash_release (attrhash, attr); - assert (ret != NULL); - bgp_attr_extra_free (attr); - XFREE (MTYPE_ATTR, attr); - } - - /* aspath refcount shoud be decrement. */ + --attr->refcnt ; + if (attr->refcnt == 0) + { + ret = hash_release (attrhash, attr); + assert (ret != NULL); + bgp_attr_extra_free (attr); + XFREE (MTYPE_ATTR, attr); + } ; + } ; + + /* aspath refcount should be decremented. */ if (aspath) aspath_unintern (aspath); if (community) @@ -685,21 +741,27 @@ bgp_attr_unintern (struct attr *attr) transit_unintern (transit); } +/*------------------------------------------------------------------------------ + * Release any element whose reference count is zero. + * + * This is used where attributes have been replaced, but not internalised, and + * which are no longer of interest -- typically where a route-map returns DENY. + */ void bgp_attr_flush (struct attr *attr) { - if (attr->aspath && ! attr->aspath->refcnt) + if (attr->aspath && (attr->aspath->refcnt == 0)) aspath_free (attr->aspath); - if (attr->community && ! attr->community->refcnt) + if (attr->community && (attr->community->refcnt == 0)) community_free (attr->community); if (attr->extra) { struct attr_extra *attre = attr->extra; - if (attre->ecommunity && ! attre->ecommunity->refcnt) + if (attre->ecommunity && (attre->ecommunity->refcnt == 0)) ecommunity_free (attre->ecommunity); - if (attre->cluster && ! attre->cluster->refcnt) + if (attre->cluster && (attre->cluster->refcnt == 0)) cluster_free (attre->cluster); - if (attre->transit && ! attre->transit->refcnt) + if (attre->transit && ! (attre->transit->refcnt == 0)) transit_free (attre->transit); } } @@ -1538,8 +1600,25 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, return 0; } -/* Read attribute of update packet. This function is called from - bgp_update() in bgpd.c. */ +/*------------------------------------------------------------------------------ + * Read attribute of update packet. + * + * This function is called from bgp_update() in bgpd.c. + * + * NB: expects the structures pointed to by: + * + * attr + * mp_update + * mp_withdraw + * + * to be zeroised on entry to this function. + * + * Any elements in attr or attr->extra will be internalised as they are set. + * (So their reference counts will *not* be zero.) + * + * However, the attr object itself is NOT internalised. + * (So its reference count will be zero.) + */ int bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw) diff --git a/bgpd/bgp_peer.h b/bgpd/bgp_peer.h index ab32117c..32d29d54 100644 --- a/bgpd/bgp_peer.h +++ b/bgpd/bgp_peer.h @@ -38,7 +38,8 @@ enum bgp_route_map_types RMAP_OUT = 1, RMAP_IMPORT = 2, RMAP_EXPORT = 3, - RMAP_MAX = 4, + RMAP_RS_IN = 4, + RMAP_MAX = 5, } ; /*============================================================================== @@ -416,15 +417,16 @@ struct peer bgp_notify notification ; /* The kind of route-map Flags. */ - u_char rmap_type; -#define PEER_RMAP_TYPE_IN (1 << 0) /* neighbor route-map in */ -#define PEER_RMAP_TYPE_OUT (1 << 1) /* neighbor route-map out */ -#define PEER_RMAP_TYPE_NETWORK (1 << 2) /* network route-map */ -#define PEER_RMAP_TYPE_REDISTRIBUTE (1 << 3) /* redistribute route-map */ + u_int16_t rmap_type; +#define PEER_RMAP_TYPE_IN (1 << 0) /* neighbor route-map in */ +#define PEER_RMAP_TYPE_OUT (1 << 1) /* neighbor route-map out */ +#define PEER_RMAP_TYPE_NETWORK (1 << 2) /* network route-map */ +#define PEER_RMAP_TYPE_REDISTRIBUTE (1 << 3) /* redistribute route-map */ #define PEER_RMAP_TYPE_DEFAULT (1 << 4) /* default-originate route-map */ -#define PEER_RMAP_TYPE_NOSET (1 << 5) /* not allow to set commands */ -#define PEER_RMAP_TYPE_IMPORT (1 << 6) /* neighbor route-map import */ -#define PEER_RMAP_TYPE_EXPORT (1 << 7) /* neighbor route-map export */ +#define PEER_RMAP_TYPE_NOSET (1 << 5) /* not allow to set commands */ +#define PEER_RMAP_TYPE_IMPORT (1 << 6) /* neighbor route-map import */ +#define PEER_RMAP_TYPE_EXPORT (1 << 7) /* neighbor route-map export */ +#define PEER_RMAP_TYPE_RS_IN (1 << 8) /* neighbor route-map rs-in */ } ; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index ca8bee8c..c29b628f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -670,121 +670,428 @@ bgp_cluster_filter (struct peer *peer, struct attr *attr) return 0; } -static int +/*------------------------------------------------------------------------------ + * Process given attributes against any in route-map. + * + * If the result is RMAP_PERMIT, then returns address of newly internalised + * version of the attributes. + * + * If the result is RMAP_DENY, then returns NULL. + * + * The structure pointed to by attr is untouched. + * + * NB: All the elements of the incoming attr must have been internalised. + * + * This is because a copy -- bgp_attr_dup() -- of those attributes is handed + * to the route-map. Any element of the attributes which is changed is + * overwritten by the route-map -- and if it has a 0 reference count, the + * element will be deleted. Unfortunately, that leaves a dangling reference + * in the original attr. + */ +static struct attr* bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { struct bgp_filter *filter; - struct bgp_info info; - route_map_result_t ret; + struct attr rmap_attr_s ; + struct attr* rmap_attr ; + struct attr* use_attr ; - filter = &peer->filter[afi][safi]; + rmap_attr = NULL ; - /* Apply default weight value. */ + /* Apply default weight value. */ if (peer->weight) - (bgp_attr_extra_get (attr))->weight = peer->weight; + { + rmap_attr = &rmap_attr_s ; + bgp_attr_dup (rmap_attr, attr) ; + + (bgp_attr_extra_get (rmap_attr))->weight = peer->weight; + } ; /* Route map apply. */ + filter = &peer->filter[afi][safi]; + if (ROUTE_MAP_IN_NAME (filter)) { - /* Duplicate current value to new strucutre for modification. */ - info.peer = peer; - info.attr = attr; + struct bgp_info info_s = { 0 } ; + route_map_result_t ret; + + if (rmap_attr == NULL) + { + rmap_attr = &rmap_attr_s ; + bgp_attr_dup (rmap_attr, attr) ; + } ; + + /* Duplicate current value to new structure for modification. */ + info_s.peer = peer; + info_s.attr = rmap_attr; SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN); - /* Apply BGP route map to the attribute. */ - ret = route_map_apply (ROUTE_MAP_IN (filter), p, RMAP_BGP, &info); + /* Apply BGP route map to the attribute. */ + ret = route_map_apply (ROUTE_MAP_IN (filter), p, RMAP_BGP, &info_s); peer->rmap_type = 0; if (ret == RMAP_DENYMATCH) - { - /* Free newly generated AS path and community by route-map. */ - bgp_attr_flush (attr); - return RMAP_DENY; - } + { + /* Discard any new elements set by the route-map -- these will have + * reference counts == 0. + * + * Discard any "extra" part of the duplicated attributes. + */ + bgp_attr_flush (rmap_attr); + bgp_attr_extra_free (rmap_attr); + + return NULL ; + } ; + } ; + + /* If the attributes may have changed, intern the result. + * + * Otherwise, intern the incoming stuff + */ + if (rmap_attr != NULL) + { + use_attr = bgp_attr_intern(rmap_attr) ; + + bgp_attr_extra_free (rmap_attr) ; + } + else + use_attr = bgp_attr_intern(attr) ; + + return use_attr ; +} ; + +/*------------------------------------------------------------------------------ + * Structure to capture route-server route. + * + * Main purpose of this is to do any required rs-in route-map once when + * updating a set of route server clients, and not at all if there are no + * route server clients for the given afi/safi. + */ +struct rs_route +{ + bool rs_in_applied ; /* whether rs-in applied yet */ + bool rs_in_deny ; /* answer when it has been */ + + /* The orig_attr MUST have all elements interned, but may or may not be + * interned itself. + */ + struct attr* orig_attr ; /* attributes before rs-in applied */ + + /* The rs_in_attr is interned when the pointer is set. + * + * The pointer is NULL if the rs-in has not been applied, and remains NULL + * if the answer is RMAP_DENY. + */ + struct attr* rs_in_attr ; /* attributes after rs-in applied */ + + /* The other attributes of the route */ + + struct peer* peer ; + + afi_t afi ; + safi_t safi ; + + struct prefix* p ; + + int type ; + int sub_type ; + + struct prefix_rd* prd ; + u_char* tag ; +}; + +/*------------------------------------------------------------------------------ + * Set up an rs_route object. + */ +static void +bgp_rs_route_init(struct rs_route* rt, afi_t afi, safi_t safi, + struct attr* attr, struct peer* peer, struct prefix* p, + int type, int sub_type, struct prefix_rd* prd, u_char* tag) +{ + rt->rs_in_applied = false ; + rt->rs_in_deny = 0 ; /* invalid while !rs_in_applied */ + rt->rs_in_attr = NULL ; /* nothing yet */ + + rt->orig_attr = attr ; + + rt->peer = peer ; + rt->afi = afi ; + rt->safi = safi ; + rt->p = p ; + rt->type = type ; + rt->sub_type = sub_type ; + rt->prd = prd ; + rt->tag = tag ; +} ; + +/*------------------------------------------------------------------------------ + * Reset an rs_route object. + * + * Discards any rs_in_attr and clears the rs_in_applied flag. + * + * Leaves everything else -- so can be reused pretty much as is. + */ +static void +bgp_rs_route_reset(struct rs_route* rt) +{ + if (rt->rs_in_attr != NULL) + { + bgp_attr_unintern(rt->rs_in_attr) ; + rt->rs_in_attr = NULL ; + } ; + + rt->rs_in_applied = false ; +} ; + +/*------------------------------------------------------------------------------ + * Process rt->orig_attr against any rs-in route-map. + * + * If the result is RMAP_PERMIT, then rt->rs_in_attr will be set to a newly + * internalised version of the attributes. + * + * If the result is RMAP_DENY, then rt->rs_in_attr is left NULL. + * + * The structure pointed to by rt->orig_attr is untouched. + * + * NB: All the elements of the incoming rt->orig_attr must have been + * internalised. + * + * This is because a copy -- bgp_attr_dup() -- of those attributes is handed + * to the route-map. Any element of the attributes which is changed is + * overwritten by the route-map -- and if it has a 0 reference count, the + * element will be deleted. Unfortunately, that leaves a dangling reference + * in the original rt->orig_attr. + * + * NB: must NOT be called more than once for the same "rt", hence the + * "rs_in_applied" flag. + */ +static void +bgp_rs_input_modifier (struct rs_route* rt) +{ + struct bgp_filter *filter; + + assert(! rt->rs_in_applied && (rt->rs_in_attr == NULL)) ; + + rt->rs_in_applied = true ; + + /* Route map apply. */ + filter = &rt->peer->filter[rt->afi][rt->safi]; + + if (ROUTE_MAP_RS_IN_NAME (filter)) + { + struct bgp_info info_s = { 0 } ; + route_map_result_t ret ; + struct attr* rmap_attr ; + struct attr rmap_attr_s ; + + rmap_attr = &rmap_attr_s ; + bgp_attr_dup(rmap_attr, rt->orig_attr) ; + + /* Duplicate current value to new structure for modification. */ + info_s.peer = rt->peer; + info_s.attr = rmap_attr ; + + SET_FLAG (rt->peer->rmap_type, PEER_RMAP_TYPE_RS_IN); + + /* Apply BGP route map to the attribute. */ + ret = route_map_apply(ROUTE_MAP_RS_IN(filter), rt->p, RMAP_BGP, &info_s) ; + + rt->peer->rmap_type = 0; + + if (ret == RMAP_DENYMATCH) + { + /* Discard any new elements set by the route-map -- these will have + * reference counts == 0. + */ + bgp_attr_flush (rmap_attr); + + rt->rs_in_deny = true ; /* NB: rs_in_attr is NULL */ + } + else + { + rt->rs_in_attr = bgp_attr_intern(rmap_attr) ; + rt->rs_in_deny = false ; + } ; + + /* Discard any "extra" part of the duplicated attributes. */ + bgp_attr_extra_free (rmap_attr); } - return RMAP_PERMIT; -} + else + { + /* Simply intern the original */ + rt->rs_in_attr = bgp_attr_intern(rt->orig_attr) ; + rt->rs_in_deny = false ; + } ; +} ; -static int -bgp_export_modifier (struct peer *rsclient, struct peer *peer, - struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) +/*------------------------------------------------------------------------------ + * Take the already interned client_attr, and if required apply the export + * route-map for the peer. + * + * If not DENY, returns interned client_attr, which may or may not have changed. + * + * If DENY, returns NULL and the client_attr will have been uninterned. + */ +static struct attr* +bgp_export_modifier (struct peer *rsclient, struct rs_route* rt, + struct attr* client_attr) { struct bgp_filter *filter; - struct bgp_info info; - route_map_result_t ret; - filter = &peer->filter[afi][safi]; + /* Route map apply. */ + filter = &rt->peer->filter[rt->afi][rt->safi]; - /* Route map apply. */ if (ROUTE_MAP_EXPORT_NAME (filter)) { - /* Duplicate current value to new strucutre for modification. */ - info.peer = rsclient; - info.attr = attr; + struct bgp_info info_s = { 0 } ; + struct attr rmap_attr_s ; + struct attr* rmap_attr ; + route_map_result_t ret; + + rmap_attr = &rmap_attr_s ; + bgp_attr_dup (rmap_attr, client_attr) ; + + /* Duplicate current value to new structure for modification. */ + info_s.peer = rsclient; + info_s.attr = rmap_attr ; SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_EXPORT); - /* Apply BGP route map to the attribute. */ - ret = route_map_apply (ROUTE_MAP_EXPORT (filter), p, RMAP_BGP, &info); + /* Apply BGP route map to the attribute. */ + ret = route_map_apply(ROUTE_MAP_EXPORT(filter), rt->p, RMAP_BGP, &info_s); rsclient->rmap_type = 0; if (ret == RMAP_DENYMATCH) { - /* Free newly generated AS path and community by route-map. */ - bgp_attr_flush (attr); - return RMAP_DENY; + /* Discard any new elements set by the route-map -- these will have + * reference counts == 0. + */ + bgp_attr_flush (rmap_attr); + + bgp_attr_unintern(client_attr) ; + + client_attr = NULL ; } - } - return RMAP_PERMIT; -} + else + { + /* Intern the result of the rmap and unintern the old version + * + * Done in this order so that any unchanged elements in rmap_attr + * gain a reference before they are released from the old interned + * attributes. + */ + struct attr* old_attr ; -static int -bgp_import_modifier (struct peer *rsclient, struct peer *peer, - struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) + old_attr = client_attr ; + client_attr = bgp_attr_intern(rmap_attr) ; + bgp_attr_unintern(old_attr) ; + } ; + + /* Discard any "extra" part of the duplicated attributes. */ + bgp_attr_extra_free (rmap_attr) ; + } ; + + return client_attr ; +} ; + +/*------------------------------------------------------------------------------ + * Take the already interned client_attr, and if required apply the import + * route-map for the route server client. + * + * If not DENY, returns interned client_attr, which may or may not have changed. + * + * If DENY, returns NULL and the client_attr will have been uninterned. + */ +static struct attr* +bgp_import_modifier (struct peer *rsclient, struct rs_route* rt, + struct attr* client_attr) { struct bgp_filter *filter; - struct bgp_info info; - route_map_result_t ret; + struct attr rmap_attr_s ; + struct attr* rmap_attr ; - filter = &rsclient->filter[afi][safi]; + rmap_attr = NULL ; - /* Apply default weight value. */ - if (peer->weight) - (bgp_attr_extra_get (attr))->weight = peer->weight; + /* Apply default weight value. */ + if (rt->peer->weight) + { + rmap_attr = &rmap_attr_s ; + bgp_attr_dup (rmap_attr, client_attr) ; + + (bgp_attr_extra_get (rmap_attr))->weight = rt->peer->weight; + } ; + + /* Route map apply. */ + filter = &rsclient->filter[rt->afi][rt->safi]; - /* Route map apply. */ if (ROUTE_MAP_IMPORT_NAME (filter)) { - /* Duplicate current value to new strucutre for modification. */ - info.peer = peer; - info.attr = attr; + struct bgp_info info_s = { 0 } ; + route_map_result_t ret ; + + if (rmap_attr == NULL) + { + rmap_attr = &rmap_attr_s ; + bgp_attr_dup (rmap_attr, client_attr) ; + } ; + + /* Duplicate current value to new structure for modification. */ + /* TODO: should this be rt->peer or rsclient ?? */ + info_s.peer = rt->peer; + info_s.attr = rmap_attr; - SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT); + SET_FLAG (rt->peer->rmap_type, PEER_RMAP_TYPE_IMPORT); /* Apply BGP route map to the attribute. */ - ret = route_map_apply (ROUTE_MAP_IMPORT (filter), p, RMAP_BGP, &info); + ret = route_map_apply(ROUTE_MAP_IMPORT(filter), rt->p, RMAP_BGP, &info_s); - peer->rmap_type = 0; + rt->peer->rmap_type = 0; if (ret == RMAP_DENYMATCH) { - /* Free newly generated AS path and community by route-map. */ - bgp_attr_flush (attr); - return RMAP_DENY; + /* Discard any new elements set by the route-map -- these will have + * reference counts == 0. + * + * Discard any "extra" part of the duplicated attributes. + */ + bgp_attr_flush (rmap_attr); + bgp_attr_extra_free (rmap_attr); + + bgp_attr_unintern(client_attr) ; + + return NULL ; } } - return RMAP_PERMIT; -} + + /* If the attributes may have changed, intern the new result and unintern the + * old version + * + * Done in this order so that any unchanged elements in rmap_attr gain + * an extra reference before they are released from the old interned + * attributes. + */ + if (rmap_attr != NULL) + { + struct attr* old_attr ; + + old_attr = client_attr ; + client_attr = bgp_attr_intern(rmap_attr) ; + bgp_attr_unintern(old_attr) ; + + bgp_attr_extra_free (rmap_attr) ; + } ; + + return client_attr ; +} ; static int bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { - int ret; char buf[SU_ADDRSTRLEN]; struct bgp_filter *filter; struct peer *from; @@ -1097,32 +1404,42 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, if (ROUTE_MAP_OUT_NAME (filter) || (ri->extra && ri->extra->suppress) ) { - struct bgp_info info; - struct attr dummy_attr = { 0 }; + struct bgp_info info_s = { 0 } ; + struct attr dummy_attr_s ; + struct attr* dummy_attr ; + route_map_result_t ret; - info.peer = peer; - info.attr = attr; + info_s.peer = peer; /* The route reflector is not allowed to modify the attributes of the reflected IBGP routes. */ if (peer_sort (from) == BGP_PEER_IBGP && peer_sort (peer) == BGP_PEER_IBGP) { - bgp_attr_dup (&dummy_attr, attr); - info.attr = &dummy_attr; + dummy_attr = &dummy_attr_s ; + bgp_attr_dup (dummy_attr, attr); + info_s.attr = dummy_attr; } + else + { + dummy_attr = NULL ; + info_s.attr = attr; + } ; SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT); if (ri->extra && ri->extra->suppress) - ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info); + ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info_s); else - ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info); + ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info_s); peer->rmap_type = 0; - if (dummy_attr.extra) - bgp_attr_extra_free (&dummy_attr); + if (dummy_attr != NULL) + { + bgp_attr_flush (dummy_attr) ; + bgp_attr_extra_free (dummy_attr) ; + } ; if (ret == RMAP_DENYMATCH) { @@ -1137,10 +1454,8 @@ static int bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { - int ret; char buf[SU_ADDRSTRLEN]; struct bgp_filter *filter; - struct bgp_info info; struct peer *from; struct bgp *bgp; @@ -1311,15 +1626,18 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, /* Route map & unsuppress-map apply. */ if (ROUTE_MAP_OUT_NAME (filter) || (ri->extra && ri->extra->suppress) ) { - info.peer = rsclient; - info.attr = attr; + struct bgp_info info_s = { 0 } ; + route_map_result_t ret; + + info_s.peer = rsclient; + info_s.attr = attr; SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_OUT); if (ri->extra && ri->extra->suppress) - ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info); + ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info_s); else - ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info); + ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info_s); rsclient->rmap_type = 0; @@ -1980,89 +2298,104 @@ bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, bgp_rib_remove (rn, ri, peer, afi, safi); } +/*------------------------------------------------------------------------------ + * Update the given RS Client's RIB with the given route from the given peer. + * + * The peer's rs-in route-map once for all the rsclients who are to receive + * the route. + * + * Then export and import route-maps for the peer and the rsclient respectively. + */ static void -bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, - struct attr *attr, struct peer *peer, struct prefix *p, int type, - int sub_type, struct prefix_rd *prd, u_char *tag) +bgp_update_rsclient (struct peer *rsclient, struct rs_route* rt) { - struct bgp_node *rn; + struct attr* client_attr ; struct bgp *bgp; - struct attr new_attr = { 0 }; - struct attr *attr_new; - struct attr *attr_new2; + struct bgp_node *rn; struct bgp_info *ri; - struct bgp_info *new; const char *reason; char buf[SU_ADDRSTRLEN]; - /* Do not insert announces from a rsclient into its own 'bgp_table'. */ - if (peer == rsclient) + /* Do not insert announces from a rsclient into its own 'bgp_table'. */ + if (rt->peer == rsclient) return; - bgp = peer->bgp; - rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, prd); + /* Apply rs_in policy. */ + if (!rt->rs_in_applied) + bgp_rs_input_modifier(rt) ; - /* Check previously received route. */ + client_attr = NULL ; /* no attributes, yet */ + + /* Find node for this route */ + bgp = rt->peer->bgp; + rn = bgp_afi_node_get (rsclient->rib[rt->afi][rt->safi], rt->afi, rt->safi, + rt->p, rt->prd); + + /* Check previously received route. */ for (ri = rn->info; ri; ri = ri->info_next) - if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) + if (ri->peer == rt->peer && ri->type == rt->type + && ri->sub_type == rt->sub_type) break; - /* AS path loop check. */ - if (aspath_loop_check (attr->aspath, rsclient->as) > peer->allowas_in[afi][safi]) + /* If rs-in denies the route, stop now */ + if (rt->rs_in_deny) + { + reason = "rs-in-policy;"; + goto filtered; + } ; + + /* AS path loop check. */ + if (aspath_loop_check (rt->rs_in_attr->aspath, rsclient->as) > + rt->peer->allowas_in[rt->afi][rt->safi]) { reason = "as-path contains our own AS;"; goto filtered; } - /* Route reflector originator ID check. */ - if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID) - && IPV4_ADDR_SAME (&rsclient->remote_id, &attr->extra->originator_id)) + /* Route reflector originator ID check. */ + if (rt->rs_in_attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID) + && IPV4_ADDR_SAME (&rsclient->remote_id, + &rt->rs_in_attr->extra->originator_id)) { reason = "originator is us;"; goto filtered; } - bgp_attr_dup (&new_attr, attr); + /* Need own internalised version of the rs_in attributes */ + client_attr = bgp_attr_intern(rt->rs_in_attr) ; - /* Apply export policy. */ - if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && - bgp_export_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY) + /* Apply export policy. */ + if (CHECK_FLAG(rt->peer->af_flags[rt->afi][rt->safi], + PEER_FLAG_RSERVER_CLIENT)) { - reason = "export-policy;"; - goto filtered; - } - - attr_new2 = bgp_attr_intern (&new_attr); + client_attr = bgp_export_modifier (rsclient, rt, client_attr) ; + if (client_attr == NULL) + { + reason = "export-policy;"; + goto filtered; + } ; + } ; /* Apply import policy. */ - if (bgp_import_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY) + client_attr = bgp_import_modifier (rsclient, rt, client_attr) ; + if (client_attr == NULL) { - bgp_attr_unintern (attr_new2); - reason = "import-policy;"; goto filtered; } - attr_new = bgp_attr_intern (&new_attr); - bgp_attr_unintern (attr_new2); - /* IPv4 unicast next hop check. */ - if (afi == AFI_IP && safi == SAFI_UNICAST) + if (rt->afi == AFI_IP && rt->safi == SAFI_UNICAST) { /* Next hop must not be 0.0.0.0 nor Class E address. */ - if (new_attr.nexthop.s_addr == 0 - || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000) + if (client_attr->nexthop.s_addr == 0 + || ntohl (client_attr->nexthop.s_addr) >= 0xe0000000) { - bgp_attr_unintern (attr_new); - reason = "martian next-hop;"; goto filtered; } } - /* new_attr isn't passed to any functions after here */ - bgp_attr_extra_free (&new_attr); - /* If the update is implicit withdraw. */ if (ri) { @@ -2070,109 +2403,101 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, /* Same attribute comes in. */ if (!CHECK_FLAG(ri->flags, BGP_INFO_REMOVED) - && attrhash_cmp (ri->attr, attr_new)) + && attrhash_cmp (ri->attr, client_attr)) { bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED); if (BGP_DEBUG (update, UPDATE_IN)) - zlog (peer->log, LOG_DEBUG, + zlog (rt->peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s...duplicate ignored", - peer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, rsclient->host); + rt->peer->host, + inet_ntop(rt->p->family, &rt->p->u.prefix, + buf, SU_ADDRSTRLEN), + rt->p->prefixlen, rsclient->host); - bgp_unlock_node (rn); - bgp_attr_unintern (attr_new); + /* Discard the duplicate interned attributes */ + bgp_attr_unintern (client_attr); - return; + /* Unlock node -- locked in bgp_afi_node_get() */ + bgp_unlock_node (rn); + return; /* FIN <<<<<<<<<<<<<<<<<<< */ } /* Withdraw/Announce before we fully processed the withdraw */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) bgp_info_restore (rn, ri); - /* Received Logging. */ - if (BGP_DEBUG (update, UPDATE_IN)) - zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s", - peer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, rsclient->host); - - /* The attribute is changed. */ + /* The attribute is changed. */ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); - /* Update to new attribute. */ + /* Discard the old attribute */ bgp_attr_unintern (ri->attr); - ri->attr = attr_new; - - /* Update MPLS tag. */ - if (safi == SAFI_MPLS_VPN) - memcpy ((bgp_info_extra_get (ri))->tag, tag, 3); + } + else + { + /* Make new BGP info. */ + ri = bgp_info_new (); + ri->type = rt->type; + ri->sub_type = rt->sub_type; + ri->peer = rt->peer; + ri->uptime = time (NULL); - bgp_info_set_flag (rn, ri, BGP_INFO_VALID); + /* Register new BGP information. */ + bgp_info_add (rn, ri); + } ; - /* Process change. */ - bgp_process (bgp, rn, afi, safi); - bgp_unlock_node (rn); + /* Set the new attributes and update any MPLS tag. + * + * Any old attributes have been discarded. + * + * Note that we are here passing responsibility for the client_attr to the + * ri entry. + */ + ri->attr = client_attr ; - return; - } + if (rt->safi == SAFI_MPLS_VPN) + memcpy ((bgp_info_extra_get (ri))->tag, rt->tag, 3); - /* Received Logging. */ + /* Received Logging. */ if (BGP_DEBUG (update, UPDATE_IN)) - { - zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s", - peer->host, - inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, rsclient->host); - } + zlog (rt->peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s", + rt->peer->host, + inet_ntop(rt->p->family, &rt->p->u.prefix, buf, SU_ADDRSTRLEN), + rt->p->prefixlen, rsclient->host); - /* Make new BGP info. */ - new = bgp_info_new (); - new->type = type; - new->sub_type = sub_type; - new->peer = peer; - new->attr = attr_new; - new->uptime = time (NULL); - - /* Update MPLS tag. */ - if (safi == SAFI_MPLS_VPN) - memcpy ((bgp_info_extra_get (new))->tag, tag, 3); - - bgp_info_set_flag (rn, new, BGP_INFO_VALID); - - /* Register new BGP information. */ - bgp_info_add (rn, new); + /* Process change. */ + bgp_info_set_flag (rn, ri, BGP_INFO_VALID); + bgp_process (bgp, rn, rt->afi, rt->safi); - /* route_node_get lock */ + /* Unlock node -- locked in bgp_afi_node_get() */ bgp_unlock_node (rn); - /* Process change. */ - bgp_process (bgp, rn, afi, safi); - - bgp_attr_extra_free (&new_attr); + return; /* FIN <<<<<<<<<<<<<<<<<<< */ - return; - - filtered: + /* Deal with route which has been filtered out. + * + * If there was a previous route, then remove it. + * + * If have an interned client attributes, then discard those. + */ + filtered: /* This BGP update is filtered. Log the reason then update BGP entry. */ if (BGP_DEBUG (update, UPDATE_IN)) - zlog (peer->log, LOG_DEBUG, + zlog (rt->peer->log, LOG_DEBUG, "%s rcvd UPDATE about %s/%d -- DENIED for RS-client %s due to: %s", - peer->host, - inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, rsclient->host, reason); + rt->peer->host, + inet_ntop (rt->p->family, &rt->p->u.prefix, buf, SU_ADDRSTRLEN), + rt->p->prefixlen, rsclient->host, reason); if (ri) - bgp_rib_remove (rn, ri, peer, afi, safi); + bgp_rib_remove (rn, ri, rt->peer, rt->afi, rt->safi); - bgp_unlock_node (rn); - - if (new_attr.extra) - bgp_attr_extra_free (&new_attr); + if (client_attr != NULL) + bgp_attr_unintern (client_attr); + bgp_unlock_node (rn); return; } @@ -2213,17 +2538,17 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, u_char *tag, int soft_reconfig) { - int ret; int aspath_loop_count = 0; struct bgp_node *rn; struct bgp *bgp; - struct attr new_attr = { 0 }; - struct attr *attr_new; + struct attr* use_attr ; struct bgp_info *ri; struct bgp_info *new; const char *reason; char buf[SU_ADDRSTRLEN]; + use_attr = NULL ; /* nothing to use, yet */ + bgp = peer->bgp; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); @@ -2284,21 +2609,20 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, } /* Apply incoming route-map. */ - bgp_attr_dup (&new_attr, attr); - - if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY) + use_attr = bgp_input_modifier(peer, p, attr, afi, safi) ; + if (use_attr == NULL) { reason = "route-map;"; goto filtered; } /* IPv4 unicast next hop check. */ - if (afi == AFI_IP && safi == SAFI_UNICAST) + if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) { /* If the peer is EBGP and nexthop is not on connected route, discard it. */ - if (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl == 1 - && ! bgp_nexthop_check_ebgp (afi, &new_attr) + if ((peer_sort (peer) == BGP_PEER_EBGP) && (peer->ttl == 1) + && ! bgp_nexthop_check_ebgp (afi, use_attr) && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) { reason = "non-connected next-hop;"; @@ -2307,17 +2631,15 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* Next hop must not be 0.0.0.0 nor Class E address. Next hop must not be my own address. */ - if (bgp_nexthop_self (afi, &new_attr) - || new_attr.nexthop.s_addr == 0 - || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000) + if (bgp_nexthop_self (afi, use_attr) + || (use_attr->nexthop.s_addr == 0) + || (ntohl (use_attr->nexthop.s_addr) >= 0xe0000000)) { reason = "martian next-hop;"; goto filtered; } } - attr_new = bgp_attr_intern (&new_attr); - /* If the update is implicit withdraw. */ if (ri) { @@ -2325,7 +2647,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* Same attribute comes in. */ if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED) - && attrhash_cmp (ri->attr, attr_new)) + && attrhash_cmp (ri->attr, use_attr)) { bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED); @@ -2362,10 +2684,9 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, } } - bgp_unlock_node (rn); - bgp_attr_unintern (attr_new); - bgp_attr_extra_free (&new_attr); + bgp_attr_unintern (use_attr); + bgp_unlock_node (rn); return 0; } @@ -2373,7 +2694,8 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { if (BGP_DEBUG (update, UPDATE_IN)) - zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d, flapped quicker than processing", + zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d, " + "flapped quicker than processing", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); @@ -2411,7 +2733,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* Update to new attribute. */ bgp_attr_unintern (ri->attr); - ri->attr = attr_new; + ri->attr = use_attr ; /* Update MPLS tag. */ if (safi == SAFI_MPLS_VPN) @@ -2421,12 +2743,12 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer_sort (peer) == BGP_PEER_EBGP) { + int ret ; /* Now we do normal update dampening. */ ret = bgp_damp_update (ri, rn, afi, safi); if (ret == BGP_DAMP_SUPPRESSED) { bgp_unlock_node (rn); - bgp_attr_extra_free (&new_attr); return 0; } } @@ -2451,9 +2773,8 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, bgp_aggregate_increment (bgp, p, ri, afi, safi); bgp_process (bgp, rn, afi, safi); - bgp_unlock_node (rn); - bgp_attr_extra_free (&new_attr); + bgp_unlock_node (rn); return 0; } @@ -2471,7 +2792,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, new->type = type; new->sub_type = sub_type; new->peer = peer; - new->attr = attr_new; + new->attr = use_attr; new->uptime = time (NULL); /* Update MPLS tag. */ @@ -2500,19 +2821,20 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, /* Register new BGP information. */ bgp_info_add (rn, new); - /* route_node_get lock */ - bgp_unlock_node (rn); - - bgp_attr_extra_free (&new_attr); - /* If maximum prefix count is configured and current prefix - count exeed it. */ + count exceeds it. */ if (bgp_maximum_prefix_overflow (peer, afi, safi, 0)) - return -1; + { + bgp_unlock_node (rn); + return -1; + } ; /* Process change. */ bgp_process (bgp, rn, afi, safi); + /* route_node_get lock */ + bgp_unlock_node (rn); + return 0; /* This BGP update is filtered. Log the reason then update BGP @@ -2525,13 +2847,13 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, reason); - if (ri) + if (ri != NULL) bgp_rib_remove (rn, ri, peer, afi, safi); - bgp_unlock_node (rn); - - bgp_attr_extra_free (&new_attr); + if (use_attr != NULL) + bgp_attr_unintern (use_attr); + bgp_unlock_node (rn); return 0; } @@ -2545,19 +2867,35 @@ bgp_update (struct peer *peer, struct prefix *p, struct attr *attr, struct bgp *bgp; int ret; + /* For all neighbors, update the main RIB */ ret = bgp_update_main (peer, p, attr, afi, safi, type, sub_type, prd, tag, soft_reconfig); + /* Update all Route-Server Client RIBs */ bgp = peer->bgp; - /* Process the update for each RS-client. */ - for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, rsclient)) + if (bgp->rsclient != NULL) { - if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) - bgp_update_rsclient (rsclient, afi, safi, attr, peer, p, type, - sub_type, prd, tag); - } + struct rs_route rt_s ; + + /* Prepare the rs_route object, ready to update all rs clients active + * in this afi/safi. + */ + bgp_rs_route_init(&rt_s, afi, safi, attr, peer, p, type, sub_type, + prd, tag) ; + /* Process the update for each RS-client. */ + for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, rsclient)) + if (CHECK_FLAG(rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) + bgp_update_rsclient (rsclient, &rt_s) ; + + /* Reset the rs_route object -- in particular discard any interned + * rs_in_attr which may have been created. + */ + bgp_rs_route_reset(&rt_s) ; + } ; + + /* Return result from bgp_update_main */ return ret; } @@ -2625,9 +2963,7 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) struct attr attr = { 0 }; struct aspath *aspath = { 0 }; struct prefix p; - struct bgp_info binfo; struct peer *from; - int ret = RMAP_DENYMATCH; if (!(afi == AFI_IP || afi == AFI_IP6)) return; @@ -2672,13 +3008,16 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) if (peer->default_rmap[afi][safi].name) { - binfo.peer = bgp->peer_self; - binfo.attr = &attr; + struct bgp_info info_s = { 0 } ; + route_map_result_t ret; + + info_s.peer = bgp->peer_self ; + info_s.attr = &attr; SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT); ret = route_map_apply (peer->default_rmap[afi][safi].map, &p, - RMAP_BGP, &binfo); + RMAP_BGP, &info_s); bgp->peer_self->rmap_type = 0; @@ -2780,16 +3119,34 @@ bgp_soft_reconfig_table_rsclient (struct peer *rsclient, afi_t afi, { struct bgp_node *rn; struct bgp_adj_in *ain; + struct rs_route rt_s ; if (! table) table = rsclient->bgp->rib[afi][safi]; + /* Prepare the rs_route object, setting all the parts common to all routes + * which are about to announce to the rs client. + */ + bgp_rs_route_init(&rt_s, afi, safi, NULL, NULL, NULL, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL) ; + + /* Announce everything in the table. */ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (ain = rn->adj_in; ain; ain = ain->adj_next) { - bgp_update_rsclient (rsclient, afi, safi, ain->attr, ain->peer, - &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL); - } + rt_s.orig_attr = ain->attr ; + rt_s.peer = ain->peer ; + rt_s.p = &rn->p ; + + bgp_update_rsclient (rsclient, &rt_s) ; + + /* Reset the rs_route object -- which discards any interned rs_in_attr + * which may have been created and clears the rs_in_applied flag. + * + * Leaves everything else ! + */ + bgp_rs_route_reset(&rt_s) ; + } ; } void @@ -3610,13 +3967,11 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, { struct bgp_node *rn; struct bgp_info *ri; - struct bgp_info *new; - struct bgp_info info; - struct attr *attr_new; - struct attr attr = {0 }; - struct attr new_attr = { .extra = 0 }; + struct attr static_attr_s ; + struct attr* static_attr ; + struct attr* client_attr ; + struct rs_route rt_s ; struct bgp *bgp; - int ret; char buf[SU_ADDRSTRLEN]; bgp = rsclient->bgp; @@ -3627,83 +3982,107 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, NULL); - bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); + /* Construct the static route attributes. + * + * Starts with an empty aspath, which is interned. No other elements are + * interned and the object itself is not interned. + */ + static_attr = &static_attr_s ; + bgp_attr_default_set (static_attr, BGP_ORIGIN_IGP); - attr.nexthop = bgp_static->igpnexthop; - attr.med = bgp_static->igpmetric; - attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + static_attr->nexthop = bgp_static->igpnexthop; + static_attr->med = bgp_static->igpmetric; + static_attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); if (bgp_static->ttl) { - attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT); - attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); - attr.pathlimit.as = 0; - attr.pathlimit.ttl = bgp_static->ttl; + static_attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT); + static_attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + static_attr->pathlimit.as = 0; + static_attr->pathlimit.ttl = bgp_static->ttl; } if (bgp_static->atomic) - attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + static_attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); - /* Apply network route-map for export to this rsclient. */ + /* Apply network route-map for export to this rsclient. + * + * Create interned attributes client_attr, either from route-map result, or + * from the static_attr. + */ if (bgp_static->rmap.name) { - struct attr attr_tmp = attr; - info.peer = rsclient; - info.attr = &attr_tmp; + struct bgp_info info_s = { 0 } ; + struct attr rmap_attr_s ; + struct attr* rmap_attr ; + route_map_result_t ret; + + rmap_attr = &rmap_attr_s ; + bgp_attr_dup(rmap_attr, static_attr) ; + + info_s.peer = rsclient ; + info_s.attr = rmap_attr ; SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_EXPORT); SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_NETWORK); - ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); + ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info_s); rsclient->rmap_type = 0; if (ret == RMAP_DENYMATCH) { - /* Free uninterned attribute. */ - bgp_attr_flush (&attr_tmp); + /* Free uninterned attribute. */ + bgp_attr_flush (rmap_attr) ; + bgp_attr_extra_free (rmap_attr); + + /* Unintern original. */ + aspath_unintern (static_attr->aspath); + bgp_attr_extra_free (static_attr); - /* Unintern original. */ - aspath_unintern (attr.aspath); bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); - bgp_attr_extra_free (&attr); return; - } - attr_new = bgp_attr_intern (&attr_tmp); + } ; + + client_attr = bgp_attr_intern(rmap_attr) ; + bgp_attr_extra_free (rmap_attr) ; } else - attr_new = bgp_attr_intern (&attr); + client_attr = bgp_attr_intern (static_attr) ; + + /* Have now finished with the static_attr */ + aspath_unintern (static_attr->aspath); + bgp_attr_extra_free (static_attr); - new_attr = *attr_new; + /* run the import route-map for the rsclient. */ + bgp_rs_route_init(&rt_s, afi, safi, NULL, bgp->peer_self, p, + ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL) ; SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); - if (bgp_import_modifier (rsclient, bgp->peer_self, p, &new_attr, afi, safi) - == RMAP_DENY) + client_attr = bgp_import_modifier (rsclient, &rt_s, client_attr) ; + + bgp->peer_self->rmap_type = 0; + + if (client_attr == NULL) { /* This BGP update is filtered. Log the reason then update BGP entry. */ if (BGP_DEBUG (update, UPDATE_IN)) - zlog (rsclient->log, LOG_DEBUG, - "Static UPDATE about %s/%d -- DENIED for RS-client %s due to: import-policy", - inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), - p->prefixlen, rsclient->host); + zlog (rsclient->log, LOG_DEBUG, + "Static UPDATE about %s/%d -- DENIED for RS-client %s due to: " + "import-policy", + inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), + p->prefixlen, rsclient->host); bgp->peer_self->rmap_type = 0; - bgp_attr_unintern (attr_new); - aspath_unintern (attr.aspath); - bgp_attr_extra_free (&attr); - bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); return; } - bgp->peer_self->rmap_type = 0; - - bgp_attr_unintern (attr_new); - attr_new = bgp_attr_intern (&new_attr); + /* Apply the client_attr */ for (ri = rn->info; ri; ri = ri->info_next) if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP @@ -3712,57 +4091,51 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, if (ri) { - if (attrhash_cmp (ri->attr, attr_new) && - !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) + if (attrhash_cmp (ri->attr, client_attr) && + !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { - bgp_unlock_node (rn); - bgp_attr_unintern (attr_new); - aspath_unintern (attr.aspath); - bgp_attr_extra_free (&attr); - return; - } + /* No point duplicating */ + bgp_attr_unintern (client_attr); + } else { - /* The attribute is changed. */ + /* The attribute is changed. */ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); - /* Rewrite BGP route information. */ + /* Rewrite BGP route information. */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) bgp_info_restore(rn, ri); + bgp_attr_unintern (ri->attr); - ri->attr = attr_new; + ri->attr = client_attr ; ri->uptime = time (NULL); - /* Process change. */ + /* Process change. */ bgp_process (bgp, rn, afi, safi); - bgp_unlock_node (rn); - aspath_unintern (attr.aspath); - bgp_attr_extra_free (&attr); - return; } - } - /* Make new BGP info. */ - new = bgp_info_new (); - new->type = ZEBRA_ROUTE_BGP; - new->sub_type = BGP_ROUTE_STATIC; - new->peer = bgp->peer_self; - SET_FLAG (new->flags, BGP_INFO_VALID); - new->attr = attr_new; - new->uptime = time (NULL); + bgp_unlock_node (rn); + return ; + } ; - /* Register new BGP information. */ - bgp_info_add (rn, new); + /* Make new BGP info. */ + ri = bgp_info_new (); + ri->type = rt_s.type ; + ri->sub_type = rt_s.sub_type ; + ri->peer = rt_s.peer ; + ri->attr = client_attr ; + ri->uptime = time (NULL); - /* route_node_get lock */ - bgp_unlock_node (rn); + SET_FLAG (ri->flags, BGP_INFO_VALID); - /* Process change. */ + /* Register new BGP information. */ + bgp_info_add (rn, ri); + + /* Process change. */ bgp_process (bgp, rn, afi, safi); - /* Unintern original. */ - aspath_unintern (attr.aspath); - bgp_attr_extra_free (&attr); + /* route_node_get lock */ + bgp_unlock_node (rn); } static void @@ -3772,10 +4145,8 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, struct bgp_node *rn; struct bgp_info *ri; struct bgp_info *new; - struct bgp_info info; struct attr attr = { 0 }; struct attr *attr_new; - int ret; assert (bgp_static); if (!bgp_static) @@ -3804,12 +4175,15 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, if (bgp_static->rmap.name) { struct attr attr_tmp = attr; - info.peer = bgp->peer_self; - info.attr = &attr_tmp; + struct bgp_info info_s = { 0 } ; + route_map_result_t ret; + + info_s.peer = bgp->peer_self; + info_s.attr = &attr_tmp; SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); - ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); + ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info_s); bgp->peer_self->rmap_type = 0; @@ -5819,13 +6193,11 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, struct listnode *node, *nnode; struct bgp_info *new; struct bgp_info *bi; - struct bgp_info info; struct bgp_node *bn; struct attr attr = { 0 }; struct attr attr_new = { 0 }; struct attr *new_attr; afi_t afi; - int ret; /* Make default attribute. */ bgp_attr_default_set (&attr, BGP_ORIGIN_INCOMPLETE); @@ -5850,13 +6222,16 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, /* Apply route-map. */ if (bgp->rmap[afi][type].map) { - info.peer = bgp->peer_self; - info.attr = &attr_new; + struct bgp_info info_s = { 0 } ; + route_map_result_t ret; + + info_s.peer = bgp->peer_self; + info_s.attr = &attr_new; SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE); ret = route_map_apply (bgp->rmap[afi][type].map, p, RMAP_BGP, - &info); + &info_s); bgp->peer_self->rmap_type = 0; @@ -6649,15 +7024,16 @@ bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router || type == bgp_show_type_flap_route_map) { struct route_map *rmap = output_arg; - struct bgp_info binfo; struct attr dummy_attr = { 0 }; - int ret; + struct bgp_info info_s = { 0 } ; + route_map_result_t ret; bgp_attr_dup (&dummy_attr, ri->attr); - binfo.peer = ri->peer; - binfo.attr = &dummy_attr; + info_s.peer = ri->peer; + info_s.attr = &dummy_attr; - ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &binfo); + /* TODO: check if routemap may be setting stuff */ + ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &info_s); bgp_attr_extra_free (&dummy_attr); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index e1e8f18d..0e082eed 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -152,18 +152,21 @@ struct bgp_static #define FILTER_LIST_OUT_NAME(F) ((F)->aslist[FILTER_OUT].name) #define FILTER_LIST_OUT_LIST(F) ((F)->aslist[FILTER_OUT].aslist) -#define ROUTE_MAP_IN_NAME(F) ((F)->map[RMAP_IN].name) -#define ROUTE_MAP_IN(F) ((F)->map[RMAP_IN].map) -#define ROUTE_MAP_OUT_NAME(F) ((F)->map[RMAP_OUT].name) -#define ROUTE_MAP_OUT(F) ((F)->map[RMAP_OUT].map) - -#define ROUTE_MAP_IMPORT_NAME(F) ((F)->map[RMAP_IMPORT].name) -#define ROUTE_MAP_IMPORT(F) ((F)->map[RMAP_IMPORT].map) -#define ROUTE_MAP_EXPORT_NAME(F) ((F)->map[RMAP_EXPORT].name) -#define ROUTE_MAP_EXPORT(F) ((F)->map[RMAP_EXPORT].map) - -#define UNSUPPRESS_MAP_NAME(F) ((F)->usmap.name) -#define UNSUPPRESS_MAP(F) ((F)->usmap.map) +#define ROUTE_MAP_IN_NAME(F) ((F)->map[RMAP_IN].name) +#define ROUTE_MAP_IN(F) ((F)->map[RMAP_IN].map) +#define ROUTE_MAP_OUT_NAME(F) ((F)->map[RMAP_OUT].name) +#define ROUTE_MAP_OUT(F) ((F)->map[RMAP_OUT].map) + +#define ROUTE_MAP_IMPORT_NAME(F) ((F)->map[RMAP_IMPORT].name) +#define ROUTE_MAP_IMPORT(F) ((F)->map[RMAP_IMPORT].map) +#define ROUTE_MAP_EXPORT_NAME(F) ((F)->map[RMAP_EXPORT].name) +#define ROUTE_MAP_EXPORT(F) ((F)->map[RMAP_EXPORT].map) + +#define ROUTE_MAP_RS_IN_NAME(F) ((F)->map[RMAP_RS_IN].name) +#define ROUTE_MAP_RS_IN(F) ((F)->map[RMAP_RS_IN].map) + +#define UNSUPPRESS_MAP_NAME(F) ((F)->usmap.name) +#define UNSUPPRESS_MAP(F) ((F)->usmap.map) enum bgp_clear_route_type { diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 2a5acb05..d99638b2 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3612,6 +3612,8 @@ peer_route_map_set_vty (struct vty *vty, const char *ip_str, direct = RMAP_IMPORT; else if (strncmp (direct_str, "e", 1) == 0) direct = RMAP_EXPORT; + else if (strncmp (direct_str, "r", 1) == 0) + direct = RMAP_RS_IN; ret = peer_route_map_set (peer, afi, safi, direct, name_str); @@ -3639,6 +3641,8 @@ peer_route_map_unset_vty (struct vty *vty, const char *ip_str, afi_t afi, direct = RMAP_IMPORT; else if (strncmp (direct_str, "e", 1) == 0) direct = RMAP_EXPORT; + else if (strncmp (direct_str, "r", 1) == 0) + direct = RMAP_RS_IN; ret = peer_route_map_unset (peer, afi, safi, direct); @@ -3647,12 +3651,13 @@ peer_route_map_unset_vty (struct vty *vty, const char *ip_str, afi_t afi, DEFUN (neighbor_route_map, neighbor_route_map_cmd, - NEIGHBOR_CMD2 "route-map WORD (in|out|import|export)", + NEIGHBOR_CMD2 "route-map WORD (in|rs-in|out|import|export)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Apply route map to neighbor\n" "Name of route map\n" "Apply map to incoming routes\n" + "Apply map to incoming Route-Server routes\n" "Apply map to outbound routes\n" "Apply map to routes going into a Route-Server client's table\n" "Apply map to routes coming from a Route-Server client") @@ -3663,13 +3668,14 @@ DEFUN (neighbor_route_map, DEFUN (no_neighbor_route_map, no_neighbor_route_map_cmd, - NO_NEIGHBOR_CMD2 "route-map WORD (in|out|import|export)", + NO_NEIGHBOR_CMD2 "route-map WORD (in|rs-in|out|import|export)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Apply route map to neighbor\n" "Name of route map\n" "Apply map to incoming routes\n" + "Apply map to incoming Route-Server routes\n" "Apply map to outbound routes\n" "Apply map to routes going into a Route-Server client's table\n" "Apply map to routes coming from a Route-Server client") @@ -7211,6 +7217,8 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi) || filter->aslist[FILTER_IN].name || filter->map[RMAP_IN].name) vty_out (vty, " Inbound path policy configured%s", VTY_NEWLINE); + if (filter->map[RMAP_RS_IN].name) + vty_out (vty, " RS-Inbound path policy configured%s", VTY_NEWLINE); if (filter->plist[FILTER_OUT].ref || filter->dlist[FILTER_OUT].name || filter->aslist[FILTER_OUT].name @@ -7264,6 +7272,11 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi) filter->map[RMAP_IN].map ? "*" : "", filter->map[RMAP_IN].name, VTY_NEWLINE); + if (filter->map[RMAP_RS_IN].name) + vty_out (vty, " Route map for RS incoming advertisements is %s%s%s", + filter->map[RMAP_RS_IN].map ? "*" : "", + filter->map[RMAP_RS_IN].name, + VTY_NEWLINE); if (filter->map[RMAP_OUT].name) vty_out (vty, " Route map for outgoing advertisements is %s%s%s", filter->map[RMAP_OUT].map ? "*" : "", diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index dfcc7ff0..30b882b6 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1064,7 +1064,7 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, /* Make peer's RIB point to group's RIB. */ peer->rib[afi][safi] = group->conf->rib[afi][safi]; - /* Import policy. */ + /* Import policy. */ if (pfilter->map[RMAP_IMPORT].name) free (pfilter->map[RMAP_IMPORT].name); @@ -1079,7 +1079,7 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, pfilter->map[RMAP_IMPORT].map = NULL; } - /* Export policy. */ + /* Export policy. */ if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) { pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); @@ -1128,8 +1128,10 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, pfilter->dlist[in].name = strdup (gfilter->dlist[in].name); pfilter->dlist[in].alist = gfilter->dlist[in].alist; } + if (! pfilter->plist[in].ref) prefix_list_copy_ref(&pfilter->plist[in].ref, gfilter->plist[in].ref) ; + if (gfilter->aslist[in].name && ! pfilter->aslist[in].name) { if (pfilter->aslist[in].name) @@ -1137,12 +1139,19 @@ peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, pfilter->aslist[in].name = strdup (gfilter->aslist[in].name); pfilter->aslist[in].aslist = gfilter->aslist[in].aslist; } + + /* main In policy */ if (gfilter->map[RMAP_IN].name && ! pfilter->map[RMAP_IN].name) { - if (pfilter->map[RMAP_IN].name) - free (pfilter->map[RMAP_IN].name); pfilter->map[RMAP_IN].name = strdup (gfilter->map[RMAP_IN].name); - pfilter->map[RMAP_IN].map = gfilter->map[RMAP_IN].map; + pfilter->map[RMAP_IN].map = gfilter->map[RMAP_IN].map; + } + + /* Route-Server In policy */ + if (gfilter->map[RMAP_RS_IN].name && ! pfilter->map[RMAP_RS_IN].name) + { + pfilter->map[RMAP_RS_IN].name = strdup (gfilter->map[RMAP_RS_IN].name); + pfilter->map[RMAP_RS_IN].map = gfilter->map[RMAP_RS_IN].map; } /* outbound filter apply */ @@ -3524,7 +3533,7 @@ peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct, return BGP_ERR_PEER_INACTIVE; if (direct != RMAP_IN && direct != RMAP_OUT && - direct != RMAP_IMPORT && direct != RMAP_EXPORT) + direct != RMAP_IMPORT && direct != RMAP_EXPORT && direct != RMAP_RS_IN) return BGP_ERR_INVALID_VALUE; if ( (direct == RMAP_OUT || direct == RMAP_IMPORT) @@ -3571,7 +3580,7 @@ peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct) return BGP_ERR_PEER_INACTIVE; if (direct != RMAP_IN && direct != RMAP_OUT && - direct != RMAP_IMPORT && direct != RMAP_EXPORT) + direct != RMAP_IMPORT && direct != RMAP_EXPORT && direct != RMAP_RS_IN) return BGP_ERR_INVALID_VALUE; if ( (direct == RMAP_OUT || direct == RMAP_IMPORT) @@ -3814,7 +3823,7 @@ int peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi, enum bgp_clear_type stype) { - if (peer->state == bgp_peer_pEstablished) + if (peer->state != bgp_peer_pEstablished) return 0; if (! peer->afc[afi][safi]) @@ -3974,16 +3983,26 @@ bgp_config_write_filter (struct vty *vty, struct peer *peer, || strcmp (filter->map[RMAP_IN].name, gfilter->map[RMAP_IN].name) != 0) vty_out (vty, " neighbor %s route-map %s in%s", addr, filter->map[RMAP_IN].name, VTY_NEWLINE); + + if (filter->map[RMAP_RS_IN].name) + if (! gfilter || ! gfilter->map[RMAP_RS_IN].name + || strcmp (filter->map[RMAP_RS_IN].name, + gfilter->map[RMAP_RS_IN].name) != 0) + vty_out (vty, " neighbor %s route-map %s rs-in%s", addr, + filter->map[RMAP_RS_IN].name, VTY_NEWLINE); + if (filter->map[RMAP_OUT].name && ! gfilter) vty_out (vty, " neighbor %s route-map %s out%s", addr, filter->map[RMAP_OUT].name, VTY_NEWLINE); + if (filter->map[RMAP_IMPORT].name && ! gfilter) vty_out (vty, " neighbor %s route-map %s import%s", addr, filter->map[RMAP_IMPORT].name, VTY_NEWLINE); + if (filter->map[RMAP_EXPORT].name) if (! gfilter || ! gfilter->map[RMAP_EXPORT].name - || strcmp (filter->map[RMAP_EXPORT].name, - gfilter->map[RMAP_EXPORT].name) != 0) + || strcmp (filter->map[RMAP_EXPORT].name, + gfilter->map[RMAP_EXPORT].name) != 0) vty_out (vty, " neighbor %s route-map %s export%s", addr, filter->map[RMAP_EXPORT].name, VTY_NEWLINE); diff --git a/configure.ac b/configure.ac index 3507a120..b34c69ff 100755 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ ## $Id$ AC_PREREQ(2.53) -AC_INIT(Quagga, 0.99.15ex02, [http://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.15ex03, [http://bugzilla.quagga.net]) AC_CONFIG_SRCDIR(lib/zebra.h) AC_CONFIG_MACRO_DIR([m4]) diff --git a/lib/memory.c b/lib/memory.c index 2e295566..c13404d2 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -203,18 +203,21 @@ zrealloc (enum MTYPE mtype, void *ptr, size_t size MEMORY_TRACKER_NAME) void zfree (enum MTYPE mtype, void *ptr) { - LOCK ; + if (ptr != NULL) + { + LOCK ; - assert(mstat.mt[mtype].alloc > 0) ; + assert(mstat.mt[mtype].alloc > 0) ; - mstat.mt[mtype].alloc--; + mstat.mt[mtype].alloc--; #ifdef MEMORY_TRACKER - mem_md_free(mtype, ptr) ; + mem_md_free(mtype, ptr) ; #endif - free (ptr); + free (ptr); - UNLOCK ; + UNLOCK ; + } ; } ; /*------------------------------------------------------------------------------ diff --git a/lib/routemap.h b/lib/routemap.h index 1402f5c8..5ff8e334 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * 02111-1307, USA. */ #ifndef _ZEBRA_ROUTEMAP_H @@ -30,7 +30,9 @@ enum route_map_type RMAP_ANY }; -typedef enum +typedef enum route_map_type route_map_type_t ; + +typedef enum { RMAP_MATCH, RMAP_DENYMATCH, @@ -78,7 +80,7 @@ struct route_map_rule_cmd const char *str; /* Function for value set or match. */ - route_map_result_t (*func_apply)(void *, struct prefix *, + route_map_result_t (*func_apply)(void *, struct prefix *, route_map_object_t, void *); /* Compile argument and return result as void *. */ @@ -115,7 +117,7 @@ struct route_map_index int pref; /* Route map type permit or deny. */ - enum route_map_type type; + enum route_map_type type; /* Do we follow old rules, or hop forward? */ route_map_end_t exitpolicy; @@ -166,7 +168,7 @@ extern int route_map_delete_match (struct route_map_index *index, const char *match_arg); /* Add route-map set statement to the route map. */ -extern int route_map_add_set (struct route_map_index *index, +extern int route_map_add_set (struct route_map_index *index, const char *set_name, const char *set_arg); |