summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroot <root@hestia.halldom.com>2010-07-28 01:04:21 +0100
committerroot <root@hestia.halldom.com>2010-07-28 01:04:21 +0100
commit5992b25ebee1ef68a6f0c9aaa9c67f9f7e6d74e9 (patch)
treea519f97cadd30fbb8f9219e464a3be5c679f0356
parent0f1365093f448e9503b618a5097eb8d6433e7710 (diff)
downloadquagga-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.c339
-rw-r--r--bgpd/bgp_attr.c123
-rw-r--r--bgpd/bgp_peer.h20
-rw-r--r--bgpd/bgp_route.c1024
-rw-r--r--bgpd/bgp_route.h27
-rw-r--r--bgpd/bgp_vty.c17
-rw-r--r--bgpd/bgpd.c39
-rwxr-xr-xconfigure.ac2
-rw-r--r--lib/memory.c15
-rw-r--r--lib/routemap.h12
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);