summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_attr.c
diff options
context:
space:
mode:
authorwhitespace / reindent <invalid@invalid.invalid>2017-07-17 14:03:14 +0200
committerwhitespace / reindent <invalid@invalid.invalid>2017-07-17 14:04:07 +0200
commitd62a17aedeb0eebdba98238874bb13d62c48dbf9 (patch)
tree3b319b1d61c8b85b4d1f06adf8b844bb8a9b5107 /bgpd/bgp_attr.c
parent*: add indent control files (diff)
downloadfrr-d62a17aedeb0eebdba98238874bb13d62c48dbf9.tar.xz
frr-d62a17aedeb0eebdba98238874bb13d62c48dbf9.zip
indent.py `git ls-files | pcregrep '\.[ch]$' | pcregrep -v '^(ldpd|babeld|nhrpd)/'` Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'bgpd/bgp_attr.c')
-rw-r--r--bgpd/bgp_attr.c6017
1 files changed, 2948 insertions, 3069 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index a22a7a5b4..79d215f1b 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -46,185 +46,169 @@
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_encap_types.h"
#if ENABLE_BGP_VNC
-# include "bgpd/rfapi/bgp_rfapi_cfg.h"
-# include "bgp_encap_types.h"
-# include "bgp_vnc_types.h"
+#include "bgpd/rfapi/bgp_rfapi_cfg.h"
+#include "bgp_encap_types.h"
+#include "bgp_vnc_types.h"
#endif
#include "bgp_encap_types.h"
#include "bgp_evpn.h"
/* Attribute strings for logging. */
-static const struct message attr_str [] =
-{
- { BGP_ATTR_ORIGIN, "ORIGIN" },
- { BGP_ATTR_AS_PATH, "AS_PATH" },
- { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
- { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
- { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
- { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
- { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
- { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
- { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
- { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" },
- { BGP_ATTR_DPA, "DPA" },
- { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
- { BGP_ATTR_RCID_PATH, "RCID_PATH" },
- { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
- { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
- { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
- { BGP_ATTR_AS4_PATH, "AS4_PATH" },
- { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
- { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
- { BGP_ATTR_ENCAP, "ENCAP" },
+static const struct message attr_str[] = {
+ {BGP_ATTR_ORIGIN, "ORIGIN"},
+ {BGP_ATTR_AS_PATH, "AS_PATH"},
+ {BGP_ATTR_NEXT_HOP, "NEXT_HOP"},
+ {BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC"},
+ {BGP_ATTR_LOCAL_PREF, "LOCAL_PREF"},
+ {BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE"},
+ {BGP_ATTR_AGGREGATOR, "AGGREGATOR"},
+ {BGP_ATTR_COMMUNITIES, "COMMUNITY"},
+ {BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID"},
+ {BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST"},
+ {BGP_ATTR_DPA, "DPA"},
+ {BGP_ATTR_ADVERTISER, "ADVERTISER"},
+ {BGP_ATTR_RCID_PATH, "RCID_PATH"},
+ {BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI"},
+ {BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI"},
+ {BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES"},
+ {BGP_ATTR_AS4_PATH, "AS4_PATH"},
+ {BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR"},
+ {BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT"},
+ {BGP_ATTR_ENCAP, "ENCAP"},
#if ENABLE_BGP_VNC
- { BGP_ATTR_VNC, "VNC" },
+ {BGP_ATTR_VNC, "VNC"},
#endif
- { BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" },
- { BGP_ATTR_PREFIX_SID, "PREFIX_SID" },
- { 0 }
-};
+ {BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY"},
+ {BGP_ATTR_PREFIX_SID, "PREFIX_SID"},
+ {0}};
static const struct message attr_flag_str[] =
-{
- { BGP_ATTR_FLAG_OPTIONAL, "Optional" },
- { BGP_ATTR_FLAG_TRANS, "Transitive" },
- { BGP_ATTR_FLAG_PARTIAL, "Partial" },
- /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
- { BGP_ATTR_FLAG_EXTLEN, "Extended Length" },
- { 0 }
-};
+ {
+ {BGP_ATTR_FLAG_OPTIONAL, "Optional"},
+ {BGP_ATTR_FLAG_TRANS, "Transitive"},
+ {BGP_ATTR_FLAG_PARTIAL, "Partial"},
+ /* bgp_attr_flags_diagnose() relies on this bit being last in
+ this list */
+ {BGP_ATTR_FLAG_EXTLEN, "Extended Length"},
+ {0}};
static struct hash *cluster_hash;
-static void *
-cluster_hash_alloc (void *p)
+static void *cluster_hash_alloc(void *p)
{
- const struct cluster_list *val = (const struct cluster_list *) p;
- struct cluster_list *cluster;
+ const struct cluster_list *val = (const struct cluster_list *)p;
+ struct cluster_list *cluster;
- cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
- cluster->length = val->length;
+ cluster = XMALLOC(MTYPE_CLUSTER, sizeof(struct cluster_list));
+ cluster->length = val->length;
- if (cluster->length)
- {
- cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
- memcpy (cluster->list, val->list, val->length);
- }
- else
- cluster->list = NULL;
+ if (cluster->length) {
+ cluster->list = XMALLOC(MTYPE_CLUSTER_VAL, val->length);
+ memcpy(cluster->list, val->list, val->length);
+ } else
+ cluster->list = NULL;
- cluster->refcnt = 0;
+ cluster->refcnt = 0;
- return cluster;
+ return cluster;
}
/* Cluster list related functions. */
-static struct cluster_list *
-cluster_parse (struct in_addr * pnt, int length)
+static struct cluster_list *cluster_parse(struct in_addr *pnt, int length)
{
- struct cluster_list tmp;
- struct cluster_list *cluster;
+ struct cluster_list tmp;
+ struct cluster_list *cluster;
- tmp.length = length;
- tmp.list = pnt;
+ tmp.length = length;
+ tmp.list = pnt;
- cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
- cluster->refcnt++;
- return cluster;
+ cluster = hash_get(cluster_hash, &tmp, cluster_hash_alloc);
+ cluster->refcnt++;
+ return cluster;
}
-int
-cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
+int cluster_loop_check(struct cluster_list *cluster, struct in_addr originator)
{
- int i;
-
- for (i = 0; i < cluster->length / 4; i++)
- if (cluster->list[i].s_addr == originator.s_addr)
- return 1;
- return 0;
+ int i;
+
+ for (i = 0; i < cluster->length / 4; i++)
+ if (cluster->list[i].s_addr == originator.s_addr)
+ return 1;
+ return 0;
}
-static unsigned int
-cluster_hash_key_make (void *p)
+static unsigned int cluster_hash_key_make(void *p)
{
- const struct cluster_list *cluster = p;
+ const struct cluster_list *cluster = p;
- return jhash(cluster->list, cluster->length, 0);
+ return jhash(cluster->list, cluster->length, 0);
}
-static int
-cluster_hash_cmp (const void *p1, const void *p2)
+static int cluster_hash_cmp(const void *p1, const void *p2)
{
- const struct cluster_list * cluster1 = p1;
- const struct cluster_list * cluster2 = p2;
+ const struct cluster_list *cluster1 = p1;
+ const struct cluster_list *cluster2 = p2;
- return (cluster1->length == cluster2->length &&
- memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
+ return (cluster1->length == cluster2->length
+ && memcmp(cluster1->list, cluster2->list, cluster1->length)
+ == 0);
}
-static void
-cluster_free (struct cluster_list *cluster)
+static void cluster_free(struct cluster_list *cluster)
{
- if (cluster->list)
- XFREE (MTYPE_CLUSTER_VAL, cluster->list);
- XFREE (MTYPE_CLUSTER, cluster);
+ if (cluster->list)
+ XFREE(MTYPE_CLUSTER_VAL, cluster->list);
+ XFREE(MTYPE_CLUSTER, cluster);
}
-static struct cluster_list *
-cluster_dup (struct cluster_list *cluster)
+static struct cluster_list *cluster_dup(struct cluster_list *cluster)
{
- struct cluster_list *new;
+ struct cluster_list *new;
+
+ new = XCALLOC(MTYPE_CLUSTER, sizeof(struct cluster_list));
+ new->length = cluster->length;
- new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
- new->length = cluster->length;
+ if (cluster->length) {
+ new->list = XMALLOC(MTYPE_CLUSTER_VAL, cluster->length);
+ memcpy(new->list, cluster->list, cluster->length);
+ } else
+ new->list = NULL;
- if (cluster->length)
- {
- new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
- memcpy (new->list, cluster->list, cluster->length);
- }
- else
- new->list = NULL;
-
- return new;
+ return new;
}
-static struct cluster_list *
-cluster_intern (struct cluster_list *cluster)
+static struct cluster_list *cluster_intern(struct cluster_list *cluster)
{
- struct cluster_list *find;
+ struct cluster_list *find;
- find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
- find->refcnt++;
+ find = hash_get(cluster_hash, cluster, cluster_hash_alloc);
+ find->refcnt++;
- return find;
+ return find;
}
-void
-cluster_unintern (struct cluster_list *cluster)
+void cluster_unintern(struct cluster_list *cluster)
{
- if (cluster->refcnt)
- cluster->refcnt--;
+ if (cluster->refcnt)
+ cluster->refcnt--;
- if (cluster->refcnt == 0)
- {
- hash_release (cluster_hash, cluster);
- cluster_free (cluster);
- }
+ if (cluster->refcnt == 0) {
+ hash_release(cluster_hash, cluster);
+ cluster_free(cluster);
+ }
}
-static void
-cluster_init (void)
+static void cluster_init(void)
{
- cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp, NULL);
+ cluster_hash =
+ hash_create(cluster_hash_key_make, cluster_hash_cmp, NULL);
}
-static void
-cluster_finish (void)
+static void cluster_finish(void)
{
- hash_clean (cluster_hash, (void (*)(void *))cluster_free);
- hash_free (cluster_hash);
- cluster_hash = NULL;
+ hash_clean(cluster_hash, (void (*)(void *))cluster_free);
+ hash_free(cluster_hash);
+ cluster_hash = NULL;
}
static struct hash *encap_hash = NULL;
@@ -232,56 +216,53 @@ static struct hash *encap_hash = NULL;
static struct hash *vnc_hash = NULL;
#endif
-struct bgp_attr_encap_subtlv *
-encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
+struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
{
- struct bgp_attr_encap_subtlv *new;
- struct bgp_attr_encap_subtlv *tail;
- struct bgp_attr_encap_subtlv *p;
+ struct bgp_attr_encap_subtlv *new;
+ struct bgp_attr_encap_subtlv *tail;
+ struct bgp_attr_encap_subtlv *p;
- for (p = orig, tail = new = NULL; p; p = p->next) {
- int size = sizeof(struct bgp_attr_encap_subtlv) - 1 + p->length;
- if (tail) {
- tail->next = XCALLOC(MTYPE_ENCAP_TLV, size);
- tail = tail->next;
- } else {
- tail = new = XCALLOC(MTYPE_ENCAP_TLV, size);
+ for (p = orig, tail = new = NULL; p; p = p->next) {
+ int size = sizeof(struct bgp_attr_encap_subtlv) - 1 + p->length;
+ if (tail) {
+ tail->next = XCALLOC(MTYPE_ENCAP_TLV, size);
+ tail = tail->next;
+ } else {
+ tail = new = XCALLOC(MTYPE_ENCAP_TLV, size);
+ }
+ assert(tail);
+ memcpy(tail, p, size);
+ tail->next = NULL;
}
- assert(tail);
- memcpy(tail, p, size);
- tail->next = NULL;
- }
- return new;
+ return new;
}
-static void
-encap_free(struct bgp_attr_encap_subtlv *p)
+static void encap_free(struct bgp_attr_encap_subtlv *p)
{
- struct bgp_attr_encap_subtlv *next;
- while (p) {
- next = p->next;
- p->next = NULL;
- XFREE(MTYPE_ENCAP_TLV, p);
- p = next;
- }
+ struct bgp_attr_encap_subtlv *next;
+ while (p) {
+ next = p->next;
+ p->next = NULL;
+ XFREE(MTYPE_ENCAP_TLV, p);
+ p = next;
+ }
}
-void
-bgp_attr_flush_encap(struct attr *attr)
+void bgp_attr_flush_encap(struct attr *attr)
{
- if (!attr)
- return;
+ if (!attr)
+ return;
- if (attr->encap_subtlvs) {
- encap_free(attr->encap_subtlvs);
- attr->encap_subtlvs = NULL;
- }
+ if (attr->encap_subtlvs) {
+ encap_free(attr->encap_subtlvs);
+ attr->encap_subtlvs = NULL;
+ }
#if ENABLE_BGP_VNC
- if (attr->vnc_subtlvs) {
- encap_free(attr->vnc_subtlvs);
- attr->vnc_subtlvs = NULL;
- }
+ if (attr->vnc_subtlvs) {
+ encap_free(attr->vnc_subtlvs);
+ attr->vnc_subtlvs = NULL;
+ }
#endif
}
@@ -293,240 +274,220 @@ bgp_attr_flush_encap(struct attr *attr)
*
* This algorithm could be made faster if needed
*/
-static int
-encap_same(struct bgp_attr_encap_subtlv *h1, struct bgp_attr_encap_subtlv *h2)
+static int encap_same(struct bgp_attr_encap_subtlv *h1,
+ struct bgp_attr_encap_subtlv *h2)
{
- struct bgp_attr_encap_subtlv *p;
- struct bgp_attr_encap_subtlv *q;
+ struct bgp_attr_encap_subtlv *p;
+ struct bgp_attr_encap_subtlv *q;
- if (h1 == h2)
- return 1;
- if (h1 == NULL || h2 == NULL)
- return 0;
+ if (h1 == h2)
+ return 1;
+ if (h1 == NULL || h2 == NULL)
+ return 0;
- for (p = h1; p; p = p->next) {
- for (q = h2; q; q = q->next) {
- if ((p->type == q->type) &&
- (p->length == q->length) &&
- !memcmp(p->value, q->value, p->length)) {
+ for (p = h1; p; p = p->next) {
+ for (q = h2; q; q = q->next) {
+ if ((p->type == q->type) && (p->length == q->length)
+ && !memcmp(p->value, q->value, p->length)) {
- break;
- }
+ break;
+ }
+ }
+ if (!q)
+ return 0;
}
- if (!q)
- return 0;
- }
- for (p = h2; p; p = p->next) {
- for (q = h1; q; q = q->next) {
- if ((p->type == q->type) &&
- (p->length == q->length) &&
- !memcmp(p->value, q->value, p->length)) {
+ for (p = h2; p; p = p->next) {
+ for (q = h1; q; q = q->next) {
+ if ((p->type == q->type) && (p->length == q->length)
+ && !memcmp(p->value, q->value, p->length)) {
- break;
- }
+ break;
+ }
+ }
+ if (!q)
+ return 0;
}
- if (!q)
- return 0;
- }
- return 1;
+ return 1;
}
-static void *
-encap_hash_alloc (void *p)
+static void *encap_hash_alloc(void *p)
{
- /* Encap structure is already allocated. */
- return p;
+ /* Encap structure is already allocated. */
+ return p;
}
-typedef enum
-{
- ENCAP_SUBTLV_TYPE,
+typedef enum {
+ ENCAP_SUBTLV_TYPE,
#if ENABLE_BGP_VNC
- VNC_SUBTLV_TYPE
+ VNC_SUBTLV_TYPE
#endif
} encap_subtlv_type;
static struct bgp_attr_encap_subtlv *
-encap_intern (struct bgp_attr_encap_subtlv *encap, encap_subtlv_type type)
+encap_intern(struct bgp_attr_encap_subtlv *encap, encap_subtlv_type type)
{
- struct bgp_attr_encap_subtlv *find;
- struct hash *hash = encap_hash;
+ struct bgp_attr_encap_subtlv *find;
+ struct hash *hash = encap_hash;
#if ENABLE_BGP_VNC
- if (type == VNC_SUBTLV_TYPE)
- hash = vnc_hash;
+ if (type == VNC_SUBTLV_TYPE)
+ hash = vnc_hash;
#endif
- find = hash_get (hash, encap, encap_hash_alloc);
- if (find != encap)
- encap_free (encap);
- find->refcnt++;
+ find = hash_get(hash, encap, encap_hash_alloc);
+ if (find != encap)
+ encap_free(encap);
+ find->refcnt++;
- return find;
+ return find;
}
-static void
-encap_unintern (struct bgp_attr_encap_subtlv **encapp, encap_subtlv_type type)
+static void encap_unintern(struct bgp_attr_encap_subtlv **encapp,
+ encap_subtlv_type type)
{
- struct bgp_attr_encap_subtlv *encap = *encapp;
- if (encap->refcnt)
- encap->refcnt--;
+ struct bgp_attr_encap_subtlv *encap = *encapp;
+ if (encap->refcnt)
+ encap->refcnt--;
- if (encap->refcnt == 0)
- {
- struct hash *hash = encap_hash;
+ if (encap->refcnt == 0) {
+ struct hash *hash = encap_hash;
#if ENABLE_BGP_VNC
- if (type == VNC_SUBTLV_TYPE)
- hash = vnc_hash;
+ if (type == VNC_SUBTLV_TYPE)
+ hash = vnc_hash;
#endif
- hash_release (hash, encap);
- encap_free (encap);
- *encapp = NULL;
- }
+ hash_release(hash, encap);
+ encap_free(encap);
+ *encapp = NULL;
+ }
}
-static unsigned int
-encap_hash_key_make (void *p)
+static unsigned int encap_hash_key_make(void *p)
{
- const struct bgp_attr_encap_subtlv * encap = p;
+ const struct bgp_attr_encap_subtlv *encap = p;
- return jhash(encap->value, encap->length, 0);
+ return jhash(encap->value, encap->length, 0);
}
-static int
-encap_hash_cmp (const void *p1, const void *p2)
+static int encap_hash_cmp(const void *p1, const void *p2)
{
- return encap_same((struct bgp_attr_encap_subtlv *)p1,
- (struct bgp_attr_encap_subtlv *)p2);
+ return encap_same((struct bgp_attr_encap_subtlv *)p1,
+ (struct bgp_attr_encap_subtlv *)p2);
}
-static void
-encap_init (void)
+static void encap_init(void)
{
- encap_hash = hash_create (encap_hash_key_make, encap_hash_cmp, NULL);
+ encap_hash = hash_create(encap_hash_key_make, encap_hash_cmp, NULL);
#if ENABLE_BGP_VNC
- vnc_hash = hash_create (encap_hash_key_make, encap_hash_cmp, NULL);
+ vnc_hash = hash_create(encap_hash_key_make, encap_hash_cmp, NULL);
#endif
}
-static void
-encap_finish (void)
+static void encap_finish(void)
{
- hash_clean (encap_hash, (void (*)(void *))encap_free);
- hash_free (encap_hash);
- encap_hash = NULL;
+ hash_clean(encap_hash, (void (*)(void *))encap_free);
+ hash_free(encap_hash);
+ encap_hash = NULL;
#if ENABLE_BGP_VNC
- hash_clean (vnc_hash, (void (*)(void *))encap_free);
- hash_free (vnc_hash);
- vnc_hash = NULL;
+ hash_clean(vnc_hash, (void (*)(void *))encap_free);
+ hash_free(vnc_hash);
+ vnc_hash = NULL;
#endif
}
-static bool
-overlay_index_same(const struct attr *a1, const struct attr *a2)
+static bool overlay_index_same(const struct attr *a1, const struct attr *a2)
{
- if(!a1 && a2)
- return false;
- if(!a2 && a1)
- return false;
- if(!a1 && !a2)
- return true;
- return !memcmp(&(a1->evpn_overlay), &(a2->evpn_overlay), sizeof(struct overlay_index));
+ if (!a1 && a2)
+ return false;
+ if (!a2 && a1)
+ return false;
+ if (!a1 && !a2)
+ return true;
+ return !memcmp(&(a1->evpn_overlay), &(a2->evpn_overlay),
+ sizeof(struct overlay_index));
}
/* Unknown transit attribute. */
static struct hash *transit_hash;
-static void
-transit_free (struct transit *transit)
+static void transit_free(struct transit *transit)
{
- if (transit->val)
- XFREE (MTYPE_TRANSIT_VAL, transit->val);
- XFREE (MTYPE_TRANSIT, transit);
+ if (transit->val)
+ XFREE(MTYPE_TRANSIT_VAL, transit->val);
+ XFREE(MTYPE_TRANSIT, transit);
}
-static struct transit *
-transit_dup (struct transit *transit)
+static struct transit *transit_dup(struct transit *transit)
{
- struct transit *new;
+ struct transit *new;
- new = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
- new->length = transit->length;
- if (new->length)
- {
- new->val = XMALLOC (MTYPE_TRANSIT_VAL, transit->length);
- memcpy (new->val, transit->val, transit->length);
- }
- else
- new->val = NULL;
+ new = XCALLOC(MTYPE_TRANSIT, sizeof(struct transit));
+ new->length = transit->length;
+ if (new->length) {
+ new->val = XMALLOC(MTYPE_TRANSIT_VAL, transit->length);
+ memcpy(new->val, transit->val, transit->length);
+ } else
+ new->val = NULL;
- return new;
+ return new;
}
-static void *
-transit_hash_alloc (void *p)
+static void *transit_hash_alloc(void *p)
{
- /* Transit structure is already allocated. */
- return p;
+ /* Transit structure is already allocated. */
+ return p;
}
-static struct transit *
-transit_intern (struct transit *transit)
+static struct transit *transit_intern(struct transit *transit)
{
- struct transit *find;
+ struct transit *find;
- find = hash_get (transit_hash, transit, transit_hash_alloc);
- if (find != transit)
- transit_free (transit);
- find->refcnt++;
+ find = hash_get(transit_hash, transit, transit_hash_alloc);
+ if (find != transit)
+ transit_free(transit);
+ find->refcnt++;
- return find;
+ return find;
}
-void
-transit_unintern (struct transit *transit)
+void transit_unintern(struct transit *transit)
{
- if (transit->refcnt)
- transit->refcnt--;
+ if (transit->refcnt)
+ transit->refcnt--;
- if (transit->refcnt == 0)
- {
- hash_release (transit_hash, transit);
- transit_free (transit);
- }
+ if (transit->refcnt == 0) {
+ hash_release(transit_hash, transit);
+ transit_free(transit);
+ }
}
-static unsigned int
-transit_hash_key_make (void *p)
+static unsigned int transit_hash_key_make(void *p)
{
- const struct transit * transit = p;
+ const struct transit *transit = p;
- return jhash(transit->val, transit->length, 0);
+ return jhash(transit->val, transit->length, 0);
}
-static int
-transit_hash_cmp (const void *p1, const void *p2)
+static int transit_hash_cmp(const void *p1, const void *p2)
{
- const struct transit * transit1 = p1;
- const struct transit * transit2 = p2;
+ const struct transit *transit1 = p1;
+ const struct transit *transit2 = p2;
- return (transit1->length == transit2->length &&
- memcmp (transit1->val, transit2->val, transit1->length) == 0);
+ return (transit1->length == transit2->length
+ && memcmp(transit1->val, transit2->val, transit1->length) == 0);
}
-static void
-transit_init (void)
+static void transit_init(void)
{
- transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp, NULL);
+ transit_hash =
+ hash_create(transit_hash_key_make, transit_hash_cmp, NULL);
}
-static void
-transit_finish (void)
+static void transit_finish(void)
{
- hash_clean (transit_hash, (void (*)(void *))transit_free);
- hash_free (transit_hash);
- transit_hash = NULL;
+ hash_clean(transit_hash, (void (*)(void *))transit_free);
+ hash_free(transit_hash);
+ transit_hash = NULL;
}
/* Attribute hash routines. */
@@ -536,295 +497,277 @@ static struct hash *attrhash;
* Though, not so shallow that it doesn't copy the contents
* of the attr_extra pointed to by 'extra'
*/
-void
-bgp_attr_dup (struct attr *new, struct attr *orig)
+void bgp_attr_dup(struct attr *new, struct attr *orig)
{
- *new = *orig;
+ *new = *orig;
}
-void
-bgp_attr_deep_dup (struct attr *new, struct attr *orig)
+void bgp_attr_deep_dup(struct attr *new, struct attr *orig)
{
- if (orig->aspath)
- new->aspath = aspath_dup(orig->aspath);
+ if (orig->aspath)
+ new->aspath = aspath_dup(orig->aspath);
- if (orig->community)
- new->community = community_dup(orig->community);
+ if (orig->community)
+ new->community = community_dup(orig->community);
- if (orig->ecommunity)
- new->ecommunity = ecommunity_dup(orig->ecommunity);
- if (orig->cluster)
- new->cluster = cluster_dup(orig->cluster);
- if (orig->transit)
- new->transit = transit_dup(orig->transit);
- if (orig->encap_subtlvs)
- new->encap_subtlvs = encap_tlv_dup(orig->encap_subtlvs);
+ if (orig->ecommunity)
+ new->ecommunity = ecommunity_dup(orig->ecommunity);
+ if (orig->cluster)
+ new->cluster = cluster_dup(orig->cluster);
+ if (orig->transit)
+ new->transit = transit_dup(orig->transit);
+ if (orig->encap_subtlvs)
+ new->encap_subtlvs = encap_tlv_dup(orig->encap_subtlvs);
#if ENABLE_BGP_VNC
- if (orig->vnc_subtlvs)
- new->vnc_subtlvs = encap_tlv_dup(orig->vnc_subtlvs);
+ if (orig->vnc_subtlvs)
+ new->vnc_subtlvs = encap_tlv_dup(orig->vnc_subtlvs);
#endif
}
-void
-bgp_attr_deep_free (struct attr *attr)
+void bgp_attr_deep_free(struct attr *attr)
{
- if (attr->aspath)
- aspath_free(attr->aspath);
+ if (attr->aspath)
+ aspath_free(attr->aspath);
- if (attr->community)
- community_free(attr->community);
+ if (attr->community)
+ community_free(attr->community);
- if (attr->ecommunity)
- ecommunity_free(&attr->ecommunity);
- if (attr->cluster)
- cluster_free(attr->cluster);
- if (attr->transit)
- transit_free(attr->transit);
- if (attr->encap_subtlvs)
- encap_free(attr->encap_subtlvs);
+ if (attr->ecommunity)
+ ecommunity_free(&attr->ecommunity);
+ if (attr->cluster)
+ cluster_free(attr->cluster);
+ if (attr->transit)
+ transit_free(attr->transit);
+ if (attr->encap_subtlvs)
+ encap_free(attr->encap_subtlvs);
#if ENABLE_BGP_VNC
- if (attr->vnc_subtlvs)
- encap_free(attr->vnc_subtlvs);
+ if (attr->vnc_subtlvs)
+ encap_free(attr->vnc_subtlvs);
#endif
}
-unsigned long int
-attr_count (void)
+unsigned long int attr_count(void)
{
- return attrhash->count;
+ return attrhash->count;
}
-unsigned long int
-attr_unknown_count (void)
+unsigned long int attr_unknown_count(void)
{
- return transit_hash->count;
+ return transit_hash->count;
}
-unsigned int
-attrhash_key_make (void *p)
+unsigned int attrhash_key_make(void *p)
{
- const struct attr *attr = (struct attr *) p;
- uint32_t key = 0;
+ const struct attr *attr = (struct attr *)p;
+ uint32_t key = 0;
#define MIX(val) key = jhash_1word(val, key)
- MIX(attr->origin);
- MIX(attr->nexthop.s_addr);
- MIX(attr->med);
- MIX(attr->local_pref);
-
- key += attr->origin;
- key += attr->nexthop.s_addr;
- key += attr->med;
- key += attr->local_pref;
-
- MIX(attr->aggregator_as);
- MIX(attr->aggregator_addr.s_addr);
- MIX(attr->weight);
- MIX(attr->mp_nexthop_global_in.s_addr);
- MIX(attr->originator_id.s_addr);
- MIX(attr->tag);
- MIX(attr->label);
- MIX(attr->label_index);
-
- if (attr->aspath)
- MIX(aspath_key_make (attr->aspath));
- if (attr->community)
- MIX(community_hash_make (attr->community));
-
- if (attr->lcommunity)
- MIX(lcommunity_hash_make (attr->lcommunity));
- if (attr->ecommunity)
- MIX(ecommunity_hash_make (attr->ecommunity));
- if (attr->cluster)
- MIX(cluster_hash_key_make (attr->cluster));
- if (attr->transit)
- MIX(transit_hash_key_make (attr->transit));
- if (attr->encap_subtlvs)
- MIX(encap_hash_key_make (attr->encap_subtlvs));
+ MIX(attr->origin);
+ MIX(attr->nexthop.s_addr);
+ MIX(attr->med);
+ MIX(attr->local_pref);
+
+ key += attr->origin;
+ key += attr->nexthop.s_addr;
+ key += attr->med;
+ key += attr->local_pref;
+
+ MIX(attr->aggregator_as);
+ MIX(attr->aggregator_addr.s_addr);
+ MIX(attr->weight);
+ MIX(attr->mp_nexthop_global_in.s_addr);
+ MIX(attr->originator_id.s_addr);
+ MIX(attr->tag);
+ MIX(attr->label);
+ MIX(attr->label_index);
+
+ if (attr->aspath)
+ MIX(aspath_key_make(attr->aspath));
+ if (attr->community)
+ MIX(community_hash_make(attr->community));
+
+ if (attr->lcommunity)
+ MIX(lcommunity_hash_make(attr->lcommunity));
+ if (attr->ecommunity)
+ MIX(ecommunity_hash_make(attr->ecommunity));
+ if (attr->cluster)
+ MIX(cluster_hash_key_make(attr->cluster));
+ if (attr->transit)
+ MIX(transit_hash_key_make(attr->transit));
+ if (attr->encap_subtlvs)
+ MIX(encap_hash_key_make(attr->encap_subtlvs));
#if ENABLE_BGP_VNC
- if (attr->vnc_subtlvs)
- MIX(encap_hash_key_make (attr->vnc_subtlvs));
+ if (attr->vnc_subtlvs)
+ MIX(encap_hash_key_make(attr->vnc_subtlvs));
#endif
- MIX(attr->mp_nexthop_len);
- key = jhash(attr->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key);
- key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key);
-
- return key;
-}
-
-int
-attrhash_cmp (const void *p1, const void *p2)
-{
- const struct attr * attr1 = p1;
- const struct attr * attr2 = p2;
-
- if (attr1->flag == attr2->flag
- && attr1->origin == attr2->origin
- && attr1->nexthop.s_addr == attr2->nexthop.s_addr
- && attr1->aspath == attr2->aspath
- && attr1->community == attr2->community
- && attr1->med == attr2->med
- && attr1->local_pref == attr2->local_pref
- && attr1->rmap_change_flags == attr2->rmap_change_flags)
- {
- if (attr1->aggregator_as == attr2->aggregator_as
- && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr
- && attr1->weight == attr2->weight
- && attr1->tag == attr2->tag
- && attr1->label_index == attr2->label_index
- && attr1->mp_nexthop_len == attr2->mp_nexthop_len
- && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global)
- && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local)
- && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in)
- && attr1->ecommunity == attr2->ecommunity
- && attr1->lcommunity == attr2->lcommunity
- && attr1->cluster == attr2->cluster
- && attr1->transit == attr2->transit
- && (attr1->encap_tunneltype == attr2->encap_tunneltype)
- && encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs)
+ MIX(attr->mp_nexthop_len);
+ key = jhash(attr->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key);
+ key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key);
+
+ return key;
+}
+
+int attrhash_cmp(const void *p1, const void *p2)
+{
+ const struct attr *attr1 = p1;
+ const struct attr *attr2 = p2;
+
+ if (attr1->flag == attr2->flag && attr1->origin == attr2->origin
+ && attr1->nexthop.s_addr == attr2->nexthop.s_addr
+ && attr1->aspath == attr2->aspath
+ && attr1->community == attr2->community && attr1->med == attr2->med
+ && attr1->local_pref == attr2->local_pref
+ && attr1->rmap_change_flags == attr2->rmap_change_flags) {
+ if (attr1->aggregator_as == attr2->aggregator_as
+ && attr1->aggregator_addr.s_addr
+ == attr2->aggregator_addr.s_addr
+ && attr1->weight == attr2->weight
+ && attr1->tag == attr2->tag
+ && attr1->label_index == attr2->label_index
+ && attr1->mp_nexthop_len == attr2->mp_nexthop_len
+ && IPV6_ADDR_SAME(&attr1->mp_nexthop_global,
+ &attr2->mp_nexthop_global)
+ && IPV6_ADDR_SAME(&attr1->mp_nexthop_local,
+ &attr2->mp_nexthop_local)
+ && IPV4_ADDR_SAME(&attr1->mp_nexthop_global_in,
+ &attr2->mp_nexthop_global_in)
+ && attr1->ecommunity == attr2->ecommunity
+ && attr1->lcommunity == attr2->lcommunity
+ && attr1->cluster == attr2->cluster
+ && attr1->transit == attr2->transit
+ && (attr1->encap_tunneltype == attr2->encap_tunneltype)
+ && encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs)
#if ENABLE_BGP_VNC
- && encap_same(attr1->vnc_subtlvs, attr2->vnc_subtlvs)
+ && encap_same(attr1->vnc_subtlvs, attr2->vnc_subtlvs)
#endif
- && IPV4_ADDR_SAME (&attr1->originator_id, &attr2->originator_id)
- && overlay_index_same(attr1, attr2))
- return 1;
- }
+ && IPV4_ADDR_SAME(&attr1->originator_id,
+ &attr2->originator_id)
+ && overlay_index_same(attr1, attr2))
+ return 1;
+ }
- return 0;
+ return 0;
}
-static void
-attrhash_init (void)
+static void attrhash_init(void)
{
- attrhash = hash_create (attrhash_key_make, attrhash_cmp, "BGP Attributes");
+ attrhash =
+ hash_create(attrhash_key_make, attrhash_cmp, "BGP Attributes");
}
/*
* special for hash_clean below
*/
-static void
-attr_vfree (void *attr)
+static void attr_vfree(void *attr)
{
- XFREE (MTYPE_ATTR, attr);
+ XFREE(MTYPE_ATTR, attr);
}
-static void
-attrhash_finish (void)
+static void attrhash_finish(void)
{
- hash_clean(attrhash, attr_vfree);
- hash_free (attrhash);
- attrhash = NULL;
+ hash_clean(attrhash, attr_vfree);
+ hash_free(attrhash);
+ attrhash = NULL;
}
-static void
-attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
+static void attr_show_all_iterator(struct hash_backet *backet, struct vty *vty)
{
- struct attr *attr = backet->data;
+ struct attr *attr = backet->data;
- vty_out (vty, "attr[%ld] nexthop %s\n", attr->refcnt,
- inet_ntoa(attr->nexthop));
+ vty_out(vty, "attr[%ld] nexthop %s\n", attr->refcnt,
+ inet_ntoa(attr->nexthop));
}
-void
-attr_show_all (struct vty *vty)
+void attr_show_all(struct vty *vty)
{
- hash_iterate (attrhash,
- (void (*)(struct hash_backet *, void *))
- attr_show_all_iterator,
- vty);
+ hash_iterate(attrhash, (void (*)(struct hash_backet *,
+ void *))attr_show_all_iterator,
+ vty);
}
-static void *
-bgp_attr_hash_alloc (void *p)
+static void *bgp_attr_hash_alloc(void *p)
{
- struct attr * val = (struct attr *) p;
- struct attr *attr;
+ struct attr *val = (struct attr *)p;
+ struct attr *attr;
- attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
- *attr = *val;
- if (val->encap_subtlvs) {
- val->encap_subtlvs = NULL;
- }
+ attr = XMALLOC(MTYPE_ATTR, sizeof(struct attr));
+ *attr = *val;
+ if (val->encap_subtlvs) {
+ val->encap_subtlvs = NULL;
+ }
#if ENABLE_BGP_VNC
- if (val->vnc_subtlvs) {
- val->vnc_subtlvs = NULL;
- }
+ if (val->vnc_subtlvs) {
+ val->vnc_subtlvs = NULL;
+ }
#endif
- attr->refcnt = 0;
- return attr;
+ attr->refcnt = 0;
+ return attr;
}
/* Internet argument attribute. */
-struct attr *
-bgp_attr_intern (struct attr *attr)
-{
- struct attr *find;
-
- /* Intern referenced strucutre. */
- if (attr->aspath)
- {
- if (! attr->aspath->refcnt)
- attr->aspath = aspath_intern (attr->aspath);
- else
- attr->aspath->refcnt++;
- }
- if (attr->community)
- {
- if (! attr->community->refcnt)
- attr->community = community_intern (attr->community);
- else
- attr->community->refcnt++;
- }
-
- if (attr->ecommunity)
- {
- if (! attr->ecommunity->refcnt)
- attr->ecommunity = ecommunity_intern (attr->ecommunity);
- else
- attr->ecommunity->refcnt++;
- }
- if (attr->lcommunity)
- {
- if (! attr->lcommunity->refcnt)
- attr->lcommunity = lcommunity_intern (attr->lcommunity);
- else
- attr->lcommunity->refcnt++;
- }
- if (attr->cluster)
- {
- if (! attr->cluster->refcnt)
- attr->cluster = cluster_intern (attr->cluster);
- else
- attr->cluster->refcnt++;
- }
- if (attr->transit)
- {
- if (! attr->transit->refcnt)
- attr->transit = transit_intern (attr->transit);
- else
- attr->transit->refcnt++;
- }
- if (attr->encap_subtlvs)
- {
- if (! attr->encap_subtlvs->refcnt)
- attr->encap_subtlvs = encap_intern (attr->encap_subtlvs, ENCAP_SUBTLV_TYPE);
- else
- attr->encap_subtlvs->refcnt++;
- }
+struct attr *bgp_attr_intern(struct attr *attr)
+{
+ struct attr *find;
+
+ /* Intern referenced strucutre. */
+ if (attr->aspath) {
+ if (!attr->aspath->refcnt)
+ attr->aspath = aspath_intern(attr->aspath);
+ else
+ attr->aspath->refcnt++;
+ }
+ if (attr->community) {
+ if (!attr->community->refcnt)
+ attr->community = community_intern(attr->community);
+ else
+ attr->community->refcnt++;
+ }
+
+ if (attr->ecommunity) {
+ if (!attr->ecommunity->refcnt)
+ attr->ecommunity = ecommunity_intern(attr->ecommunity);
+ else
+ attr->ecommunity->refcnt++;
+ }
+ if (attr->lcommunity) {
+ if (!attr->lcommunity->refcnt)
+ attr->lcommunity = lcommunity_intern(attr->lcommunity);
+ else
+ attr->lcommunity->refcnt++;
+ }
+ if (attr->cluster) {
+ if (!attr->cluster->refcnt)
+ attr->cluster = cluster_intern(attr->cluster);
+ else
+ attr->cluster->refcnt++;
+ }
+ if (attr->transit) {
+ if (!attr->transit->refcnt)
+ attr->transit = transit_intern(attr->transit);
+ else
+ attr->transit->refcnt++;
+ }
+ if (attr->encap_subtlvs) {
+ if (!attr->encap_subtlvs->refcnt)
+ attr->encap_subtlvs = encap_intern(attr->encap_subtlvs,
+ ENCAP_SUBTLV_TYPE);
+ else
+ attr->encap_subtlvs->refcnt++;
+ }
#if ENABLE_BGP_VNC
- if (attr->vnc_subtlvs)
- {
- if (! attr->vnc_subtlvs->refcnt)
- attr->vnc_subtlvs = encap_intern (attr->vnc_subtlvs, VNC_SUBTLV_TYPE);
- else
- attr->vnc_subtlvs->refcnt++;
- }
+ if (attr->vnc_subtlvs) {
+ if (!attr->vnc_subtlvs->refcnt)
+ attr->vnc_subtlvs = encap_intern(attr->vnc_subtlvs,
+ VNC_SUBTLV_TYPE);
+ else
+ attr->vnc_subtlvs->refcnt++;
+ }
#endif
-
- find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
- find->refcnt++;
- return find;
+ find = (struct attr *)hash_get(attrhash, attr, bgp_attr_hash_alloc);
+ find->refcnt++;
+
+ return find;
}
/**
@@ -836,211 +779,197 @@ bgp_attr_intern (struct attr *attr)
* after calling bgp_attr_refcount(). That would release the
* reference and could result in a free() of the attr object.
*/
-struct attr *
-bgp_attr_refcount (struct attr *attr)
+struct attr *bgp_attr_refcount(struct attr *attr)
{
- /* Intern referenced strucutre. */
- if (attr->aspath)
- attr->aspath->refcnt++;
+ /* Intern referenced strucutre. */
+ if (attr->aspath)
+ attr->aspath->refcnt++;
- if (attr->community)
- attr->community->refcnt++;
+ if (attr->community)
+ attr->community->refcnt++;
- if (attr->ecommunity)
- attr->ecommunity->refcnt++;
+ if (attr->ecommunity)
+ attr->ecommunity->refcnt++;
- if (attr->cluster)
- attr->cluster->refcnt++;
+ if (attr->cluster)
+ attr->cluster->refcnt++;
- if (attr->transit)
- attr->transit->refcnt++;
+ if (attr->transit)
+ attr->transit->refcnt++;
- if (attr->encap_subtlvs)
- attr->encap_subtlvs->refcnt++;
+ if (attr->encap_subtlvs)
+ attr->encap_subtlvs->refcnt++;
#if ENABLE_BGP_VNC
- if (attr->vnc_subtlvs)
- attr->vnc_subtlvs->refcnt++;
+ if (attr->vnc_subtlvs)
+ attr->vnc_subtlvs->refcnt++;
#endif
- attr->refcnt++;
- return attr;
+ attr->refcnt++;
+ return attr;
}
/* Make network statement's attribute. */
-struct attr *
-bgp_attr_default_set (struct attr *attr, u_char origin)
+struct attr *bgp_attr_default_set(struct attr *attr, u_char origin)
{
- memset (attr, 0, sizeof (struct attr));
-
- attr->origin = origin;
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
- attr->aspath = aspath_empty ();
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
- attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
- attr->tag = 0;
- attr->label_index = BGP_INVALID_LABEL_INDEX;
- attr->label = MPLS_INVALID_LABEL;
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
- attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
+ memset(attr, 0, sizeof(struct attr));
- return attr;
+ attr->origin = origin;
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
+ attr->aspath = aspath_empty();
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
+ attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
+ attr->tag = 0;
+ attr->label_index = BGP_INVALID_LABEL_INDEX;
+ attr->label = MPLS_INVALID_LABEL;
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+ attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
+
+ return attr;
}
/* Create the attributes for an aggregate */
-struct attr *
-bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
- struct aspath *aspath,
- struct community *community, int as_set,
- u_char atomic_aggregate)
-{
- struct attr attr;
- struct attr *new;
-
- memset (&attr, 0, sizeof (struct attr));
-
- /* Origin attribute. */
- attr.origin = origin;
- attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
-
- /* AS path attribute. */
- if (aspath)
- attr.aspath = aspath_intern (aspath);
- else
- attr.aspath = aspath_empty ();
- attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
-
- /* Next hop attribute. */
- attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
-
- if (community)
- {
- attr.community = community;
- attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
- }
-
- attr.label_index = BGP_INVALID_LABEL_INDEX;
- attr.label = MPLS_INVALID_LABEL;
- attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
- attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
- if (! as_set || atomic_aggregate)
- attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
- attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
- if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
- attr.aggregator_as = bgp->confed_id;
- else
- attr.aggregator_as = bgp->as;
- attr.aggregator_addr = bgp->router_id;
- attr.label_index = BGP_INVALID_LABEL_INDEX;
- attr.label = MPLS_INVALID_LABEL;
-
- new = bgp_attr_intern (&attr);
-
- aspath_unintern (&new->aspath);
- return new;
+struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, u_char origin,
+ struct aspath *aspath,
+ struct community *community, int as_set,
+ u_char atomic_aggregate)
+{
+ struct attr attr;
+ struct attr *new;
+
+ memset(&attr, 0, sizeof(struct attr));
+
+ /* Origin attribute. */
+ attr.origin = origin;
+ attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
+
+ /* AS path attribute. */
+ if (aspath)
+ attr.aspath = aspath_intern(aspath);
+ else
+ attr.aspath = aspath_empty();
+ attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
+
+ /* Next hop attribute. */
+ attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+
+ if (community) {
+ attr.community = community;
+ attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
+ }
+
+ attr.label_index = BGP_INVALID_LABEL_INDEX;
+ attr.label = MPLS_INVALID_LABEL;
+ attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
+ attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
+ if (!as_set || atomic_aggregate)
+ attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
+ attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
+ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
+ attr.aggregator_as = bgp->confed_id;
+ else
+ attr.aggregator_as = bgp->as;
+ attr.aggregator_addr = bgp->router_id;
+ attr.label_index = BGP_INVALID_LABEL_INDEX;
+ attr.label = MPLS_INVALID_LABEL;
+
+ new = bgp_attr_intern(&attr);
+
+ aspath_unintern(&new->aspath);
+ return new;
}
/* Unintern just the sub-components of the attr, but not the attr */
-void
-bgp_attr_unintern_sub (struct attr *attr)
-{
- /* aspath refcount shoud be decrement. */
- if (attr->aspath)
- aspath_unintern (&attr->aspath);
- UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH));
-
- if (attr->community)
- community_unintern (&attr->community);
- UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES));
-
- if (attr->ecommunity)
- ecommunity_unintern (&attr->ecommunity);
- UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES));
-
- if (attr->lcommunity)
- lcommunity_unintern (&attr->lcommunity);
- UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES));
-
- if (attr->cluster)
- cluster_unintern (attr->cluster);
- UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST));
-
- if (attr->transit)
- transit_unintern (attr->transit);
-
- if (attr->encap_subtlvs)
- encap_unintern (&attr->encap_subtlvs, ENCAP_SUBTLV_TYPE);
+void bgp_attr_unintern_sub(struct attr *attr)
+{
+ /* aspath refcount shoud be decrement. */
+ if (attr->aspath)
+ aspath_unintern(&attr->aspath);
+ UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH));
+
+ if (attr->community)
+ community_unintern(&attr->community);
+ UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES));
+
+ if (attr->ecommunity)
+ ecommunity_unintern(&attr->ecommunity);
+ UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES));
+
+ if (attr->lcommunity)
+ lcommunity_unintern(&attr->lcommunity);
+ UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES));
+
+ if (attr->cluster)
+ cluster_unintern(attr->cluster);
+ UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST));
+
+ if (attr->transit)
+ transit_unintern(attr->transit);
+
+ if (attr->encap_subtlvs)
+ encap_unintern(&attr->encap_subtlvs, ENCAP_SUBTLV_TYPE);
#if ENABLE_BGP_VNC
- if (attr->vnc_subtlvs)
- encap_unintern (&attr->vnc_subtlvs, VNC_SUBTLV_TYPE);
+ if (attr->vnc_subtlvs)
+ encap_unintern(&attr->vnc_subtlvs, VNC_SUBTLV_TYPE);
#endif
}
/* Free bgp attribute and aspath. */
-void
-bgp_attr_unintern (struct attr **pattr)
-{
- struct attr *attr = *pattr;
- struct attr *ret;
- struct attr tmp;
-
- /* Decrement attribute reference. */
- attr->refcnt--;
-
- tmp = *attr;
-
- /* If reference becomes zero then free attribute object. */
- if (attr->refcnt == 0)
- {
- ret = hash_release (attrhash, attr);
- assert (ret != NULL);
- XFREE (MTYPE_ATTR, attr);
- *pattr = NULL;
- }
-
- bgp_attr_unintern_sub (&tmp);
-}
-
-void
-bgp_attr_flush (struct attr *attr)
-{
- if (attr->aspath && ! attr->aspath->refcnt)
- {
- aspath_free (attr->aspath);
- attr->aspath = NULL;
- }
- if (attr->community && ! attr->community->refcnt)
- {
- community_free (attr->community);
- attr->community = NULL;
- }
-
- if (attr->ecommunity && ! attr->ecommunity->refcnt)
- ecommunity_free (&attr->ecommunity);
- if (attr->lcommunity && ! attr->lcommunity->refcnt)
- lcommunity_free (&attr->lcommunity);
- if (attr->cluster && ! attr->cluster->refcnt)
- {
- cluster_free (attr->cluster);
- attr->cluster = NULL;
- }
- if (attr->transit && ! attr->transit->refcnt)
- {
- transit_free (attr->transit);
- attr->transit = NULL;
- }
- if (attr->encap_subtlvs && ! attr->encap_subtlvs->refcnt)
- {
- encap_free(attr->encap_subtlvs);
- attr->encap_subtlvs = NULL;
- }
+void bgp_attr_unintern(struct attr **pattr)
+{
+ struct attr *attr = *pattr;
+ struct attr *ret;
+ struct attr tmp;
+
+ /* Decrement attribute reference. */
+ attr->refcnt--;
+
+ tmp = *attr;
+
+ /* If reference becomes zero then free attribute object. */
+ if (attr->refcnt == 0) {
+ ret = hash_release(attrhash, attr);
+ assert(ret != NULL);
+ XFREE(MTYPE_ATTR, attr);
+ *pattr = NULL;
+ }
+
+ bgp_attr_unintern_sub(&tmp);
+}
+
+void bgp_attr_flush(struct attr *attr)
+{
+ if (attr->aspath && !attr->aspath->refcnt) {
+ aspath_free(attr->aspath);
+ attr->aspath = NULL;
+ }
+ if (attr->community && !attr->community->refcnt) {
+ community_free(attr->community);
+ attr->community = NULL;
+ }
+
+ if (attr->ecommunity && !attr->ecommunity->refcnt)
+ ecommunity_free(&attr->ecommunity);
+ if (attr->lcommunity && !attr->lcommunity->refcnt)
+ lcommunity_free(&attr->lcommunity);
+ if (attr->cluster && !attr->cluster->refcnt) {
+ cluster_free(attr->cluster);
+ attr->cluster = NULL;
+ }
+ if (attr->transit && !attr->transit->refcnt) {
+ transit_free(attr->transit);
+ attr->transit = NULL;
+ }
+ if (attr->encap_subtlvs && !attr->encap_subtlvs->refcnt) {
+ encap_free(attr->encap_subtlvs);
+ attr->encap_subtlvs = NULL;
+ }
#if ENABLE_BGP_VNC
- if (attr->vnc_subtlvs && ! attr->vnc_subtlvs->refcnt)
- {
- encap_free(attr->vnc_subtlvs);
- attr->vnc_subtlvs = NULL;
- }
+ if (attr->vnc_subtlvs && !attr->vnc_subtlvs->refcnt) {
+ encap_free(attr->vnc_subtlvs);
+ attr->vnc_subtlvs = NULL;
+ }
#endif
}
@@ -1050,74 +979,72 @@ bgp_attr_flush (struct attr *attr)
* introduced by the sending neighbour.
*/
static bgp_attr_parse_ret_t
-bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
- bgp_size_t length)
-{
- struct peer *const peer = args->peer;
- const u_int8_t flags = args->flags;
- /* startp and length must be special-cased, as whether or not to
- * send the attribute data with the NOTIFY depends on the error,
- * the caller therefore signals this with the seperate length argument
- */
- u_char *notify_datap = (length > 0 ? args->startp : NULL);
-
- /* Only relax error handling for eBGP peers */
- if (peer->sort != BGP_PEER_EBGP)
- {
- bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
- notify_datap, length);
- return BGP_ATTR_PARSE_ERROR;
-
- }
-
- /* Adjust the stream getp to the end of the attribute, in case we can
- * still proceed but the caller hasn't read all the attribute.
- */
- stream_set_getp (BGP_INPUT (peer),
- (args->startp - STREAM_DATA (BGP_INPUT (peer)))
- + args->total);
-
- switch (args->type) {
- /* where an attribute is relatively inconsequential, e.g. it does not
- * affect route selection, and can be safely ignored, then any such
- * attributes which are malformed should just be ignored and the route
- * processed as normal.
- */
- case BGP_ATTR_AS4_AGGREGATOR:
- case BGP_ATTR_AGGREGATOR:
- case BGP_ATTR_ATOMIC_AGGREGATE:
- return BGP_ATTR_PARSE_PROCEED;
-
- /* Core attributes, particularly ones which may influence route
- * selection, should always cause session resets
- */
- case BGP_ATTR_ORIGIN:
- case BGP_ATTR_AS_PATH:
- case BGP_ATTR_NEXT_HOP:
- case BGP_ATTR_MULTI_EXIT_DISC:
- case BGP_ATTR_LOCAL_PREF:
- case BGP_ATTR_COMMUNITIES:
- case BGP_ATTR_ORIGINATOR_ID:
- case BGP_ATTR_CLUSTER_LIST:
- case BGP_ATTR_MP_REACH_NLRI:
- case BGP_ATTR_MP_UNREACH_NLRI:
- case BGP_ATTR_EXT_COMMUNITIES:
- bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
- notify_datap, length);
- return BGP_ATTR_PARSE_ERROR;
- }
-
- /* Partial optional attributes that are malformed should not cause
- * the whole session to be reset. Instead treat it as a withdrawal
- * of the routes, if possible.
- */
- if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
- && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
- && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
- return BGP_ATTR_PARSE_WITHDRAW;
-
- /* default to reset */
- return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
+bgp_attr_malformed(struct bgp_attr_parser_args *args, u_char subcode,
+ bgp_size_t length)
+{
+ struct peer *const peer = args->peer;
+ const u_int8_t flags = args->flags;
+ /* startp and length must be special-cased, as whether or not to
+ * send the attribute data with the NOTIFY depends on the error,
+ * the caller therefore signals this with the seperate length argument
+ */
+ u_char *notify_datap = (length > 0 ? args->startp : NULL);
+
+ /* Only relax error handling for eBGP peers */
+ if (peer->sort != BGP_PEER_EBGP) {
+ bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, subcode,
+ notify_datap, length);
+ return BGP_ATTR_PARSE_ERROR;
+ }
+
+ /* Adjust the stream getp to the end of the attribute, in case we can
+ * still proceed but the caller hasn't read all the attribute.
+ */
+ stream_set_getp(BGP_INPUT(peer),
+ (args->startp - STREAM_DATA(BGP_INPUT(peer)))
+ + args->total);
+
+ switch (args->type) {
+ /* where an attribute is relatively inconsequential, e.g. it does not
+ * affect route selection, and can be safely ignored, then any such
+ * attributes which are malformed should just be ignored and the route
+ * processed as normal.
+ */
+ case BGP_ATTR_AS4_AGGREGATOR:
+ case BGP_ATTR_AGGREGATOR:
+ case BGP_ATTR_ATOMIC_AGGREGATE:
+ return BGP_ATTR_PARSE_PROCEED;
+
+ /* Core attributes, particularly ones which may influence route
+ * selection, should always cause session resets
+ */
+ case BGP_ATTR_ORIGIN:
+ case BGP_ATTR_AS_PATH:
+ case BGP_ATTR_NEXT_HOP:
+ case BGP_ATTR_MULTI_EXIT_DISC:
+ case BGP_ATTR_LOCAL_PREF:
+ case BGP_ATTR_COMMUNITIES:
+ case BGP_ATTR_ORIGINATOR_ID:
+ case BGP_ATTR_CLUSTER_LIST:
+ case BGP_ATTR_MP_REACH_NLRI:
+ case BGP_ATTR_MP_UNREACH_NLRI:
+ case BGP_ATTR_EXT_COMMUNITIES:
+ bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, subcode,
+ notify_datap, length);
+ return BGP_ATTR_PARSE_ERROR;
+ }
+
+ /* Partial optional attributes that are malformed should not cause
+ * the whole session to be reset. Instead treat it as a withdrawal
+ * of the routes, if possible.
+ */
+ if (CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS)
+ && CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)
+ && CHECK_FLAG(flags, BGP_ATTR_FLAG_PARTIAL))
+ return BGP_ATTR_PARSE_WITHDRAW;
+
+ /* default to reset */
+ return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
}
/* Find out what is wrong with the path attribute flag bits and log the error.
@@ -1126,2504 +1053,2456 @@ bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
being diagnosed is defined by RFC as either a "well-known" or an "optional,
non-transitive" attribute. */
static void
-bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
- u_int8_t desired_flags /* how RFC says it must be */
-)
-{
- u_char seen = 0, i;
- u_char real_flags = args->flags;
- const u_int8_t attr_code = args->type;
-
- desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
- real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
- for (i = 0; i <= 2; i++) /* O,T,P, but not E */
- if
- (
- CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
- CHECK_FLAG (real_flags, attr_flag_str[i].key)
- )
- {
- zlog_err ("%s attribute must%s be flagged as \"%s\"",
- lookup_msg(attr_str, attr_code, NULL),
- CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
- attr_flag_str[i].str);
- seen = 1;
- }
- if (!seen)
- {
- zlog_debug ("Strange, %s called for attr %s, but no problem found with flags"
- " (real flags 0x%x, desired 0x%x)",
- __func__, lookup_msg(attr_str, attr_code, NULL),
- real_flags, desired_flags);
- }
+bgp_attr_flags_diagnose(struct bgp_attr_parser_args *args,
+ u_int8_t desired_flags /* how RFC says it must be */
+ )
+{
+ u_char seen = 0, i;
+ u_char real_flags = args->flags;
+ const u_int8_t attr_code = args->type;
+
+ desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
+ real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
+ for (i = 0; i <= 2; i++) /* O,T,P, but not E */
+ if (CHECK_FLAG(desired_flags, attr_flag_str[i].key)
+ != CHECK_FLAG(real_flags, attr_flag_str[i].key)) {
+ zlog_err("%s attribute must%s be flagged as \"%s\"",
+ lookup_msg(attr_str, attr_code, NULL),
+ CHECK_FLAG(desired_flags, attr_flag_str[i].key)
+ ? ""
+ : " not",
+ attr_flag_str[i].str);
+ seen = 1;
+ }
+ if (!seen) {
+ zlog_debug(
+ "Strange, %s called for attr %s, but no problem found with flags"
+ " (real flags 0x%x, desired 0x%x)",
+ __func__, lookup_msg(attr_str, attr_code, NULL),
+ real_flags, desired_flags);
+ }
}
/* Required flags for attributes. EXTLEN will be masked off when testing,
* as will PARTIAL for optional+transitive attributes.
*/
-const u_int8_t attr_flags_values [] = {
- [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
- [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
- [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
- [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
- [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
- [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
- [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
- [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
- [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
- [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
- [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
- [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
- [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
- [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
- [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
- [BGP_ATTR_LARGE_COMMUNITIES]= BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
- [BGP_ATTR_PREFIX_SID] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+const u_int8_t attr_flags_values[] = {
+ [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_AGGREGATOR] =
+ BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_COMMUNITIES] =
+ BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
+ [BGP_ATTR_EXT_COMMUNITIES] =
+ BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_AS4_PATH] =
+ BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_AS4_AGGREGATOR] =
+ BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_LARGE_COMMUNITIES] =
+ BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_PREFIX_SID] =
+ BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
};
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
-static int
-bgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
-{
- u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
- const u_int8_t flags = args->flags;
- const u_int8_t attr_code = args->type;
-
- /* there may be attributes we don't know about */
- if (attr_code > attr_flags_values_max)
- return 0;
- if (attr_flags_values[attr_code] == 0)
- return 0;
-
- /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
- * 1."
- */
- if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
- && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
- {
- zlog_err ("%s well-known attributes must have transitive flag set (%x)",
- lookup_msg(attr_str, attr_code, NULL), flags);
- return 1;
- }
-
- /* "For well-known attributes and for optional non-transitive attributes,
- * the Partial bit MUST be set to 0."
- */
- if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
- {
- if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
- {
- zlog_err ("%s well-known attribute "
- "must NOT have the partial flag set (%x)",
- lookup_msg(attr_str, attr_code, NULL), flags);
- return 1;
- }
- if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
- && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
- {
- zlog_err ("%s optional + transitive attribute "
- "must NOT have the partial flag set (%x)",
- lookup_msg(attr_str, attr_code, NULL), flags);
- return 1;
- }
- }
-
- /* Optional transitive attributes may go through speakers that don't
- * reocgnise them and set the Partial bit.
- */
- if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
- && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
- SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
-
- if ((flags & ~mask)
- == attr_flags_values[attr_code])
- return 0;
-
- bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
- return 1;
+static int bgp_attr_flag_invalid(struct bgp_attr_parser_args *args)
+{
+ u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
+ const u_int8_t flags = args->flags;
+ const u_int8_t attr_code = args->type;
+
+ /* there may be attributes we don't know about */
+ if (attr_code > attr_flags_values_max)
+ return 0;
+ if (attr_flags_values[attr_code] == 0)
+ return 0;
+
+ /* RFC4271, "For well-known attributes, the Transitive bit MUST be set
+ * to
+ * 1."
+ */
+ if (!CHECK_FLAG(BGP_ATTR_FLAG_OPTIONAL, flags)
+ && !CHECK_FLAG(BGP_ATTR_FLAG_TRANS, flags)) {
+ zlog_err(
+ "%s well-known attributes must have transitive flag set (%x)",
+ lookup_msg(attr_str, attr_code, NULL), flags);
+ return 1;
+ }
+
+ /* "For well-known attributes and for optional non-transitive
+ * attributes,
+ * the Partial bit MUST be set to 0."
+ */
+ if (CHECK_FLAG(flags, BGP_ATTR_FLAG_PARTIAL)) {
+ if (!CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)) {
+ zlog_err(
+ "%s well-known attribute "
+ "must NOT have the partial flag set (%x)",
+ lookup_msg(attr_str, attr_code, NULL), flags);
+ return 1;
+ }
+ if (CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)
+ && !CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS)) {
+ zlog_err(
+ "%s optional + transitive attribute "
+ "must NOT have the partial flag set (%x)",
+ lookup_msg(attr_str, attr_code, NULL), flags);
+ return 1;
+ }
+ }
+
+ /* Optional transitive attributes may go through speakers that don't
+ * reocgnise them and set the Partial bit.
+ */
+ if (CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)
+ && CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS))
+ SET_FLAG(mask, BGP_ATTR_FLAG_PARTIAL);
+
+ if ((flags & ~mask) == attr_flags_values[attr_code])
+ return 0;
+
+ bgp_attr_flags_diagnose(args, attr_flags_values[attr_code]);
+ return 1;
}
/* Get origin attribute of the update message. */
-static bgp_attr_parse_ret_t
-bgp_attr_origin (struct bgp_attr_parser_args *args)
-{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- /* If any recognized attribute has Attribute Length that conflicts
- with the expected length (based on the attribute type code), then
- the Error Subcode is set to Attribute Length Error. The Data
- field contains the erroneous attribute (type, length and
- value). */
- if (length != 1)
- {
- zlog_err ("Origin attribute length is not one %d", length);
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- args->total);
- }
-
- /* Fetch origin attribute. */
- attr->origin = stream_getc (BGP_INPUT (peer));
-
- /* If the ORIGIN attribute has an undefined value, then the Error
- Subcode is set to Invalid Origin Attribute. The Data field
- contains the unrecognized attribute (type, length and value). */
- if ((attr->origin != BGP_ORIGIN_IGP)
- && (attr->origin != BGP_ORIGIN_EGP)
- && (attr->origin != BGP_ORIGIN_INCOMPLETE))
- {
- zlog_err ("Origin attribute value is invalid %d", attr->origin);
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
- args->total);
- }
-
- /* Set oring attribute flag. */
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
-
- return 0;
+static bgp_attr_parse_ret_t bgp_attr_origin(struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ /* If any recognized attribute has Attribute Length that conflicts
+ with the expected length (based on the attribute type code), then
+ the Error Subcode is set to Attribute Length Error. The Data
+ field contains the erroneous attribute (type, length and
+ value). */
+ if (length != 1) {
+ zlog_err("Origin attribute length is not one %d", length);
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ /* Fetch origin attribute. */
+ attr->origin = stream_getc(BGP_INPUT(peer));
+
+ /* If the ORIGIN attribute has an undefined value, then the Error
+ Subcode is set to Invalid Origin Attribute. The Data field
+ contains the unrecognized attribute (type, length and value). */
+ if ((attr->origin != BGP_ORIGIN_IGP) && (attr->origin != BGP_ORIGIN_EGP)
+ && (attr->origin != BGP_ORIGIN_INCOMPLETE)) {
+ zlog_err("Origin attribute value is invalid %d", attr->origin);
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
+ args->total);
+ }
+
+ /* Set oring attribute flag. */
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
+
+ return 0;
}
/* Parse AS path information. This function is wrapper of
aspath_parse. */
-static int
-bgp_attr_aspath (struct bgp_attr_parser_args *args)
-{
- struct attr *const attr = args->attr;
- struct peer *const peer = args->peer;
- const bgp_size_t length = args->length;
-
- /*
- * peer with AS4 => will get 4Byte ASnums
- * otherwise, will get 16 Bit
- */
- attr->aspath = aspath_parse (peer->ibuf, length,
- CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
+static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
+{
+ struct attr *const attr = args->attr;
+ struct peer *const peer = args->peer;
+ const bgp_size_t length = args->length;
+
+ /*
+ * peer with AS4 => will get 4Byte ASnums
+ * otherwise, will get 16 Bit
+ */
+ attr->aspath = aspath_parse(peer->ibuf, length,
+ CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV));
+
+ /* In case of IBGP, length will be zero. */
+ if (!attr->aspath) {
+ zlog_err("Malformed AS path from %s, length is %d", peer->host,
+ length);
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+ 0);
+ }
- /* In case of IBGP, length will be zero. */
- if (! attr->aspath)
- {
- zlog_err ("Malformed AS path from %s, length is %d", peer->host, length);
- return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
- }
+ /* Set aspath attribute flag. */
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
+
+ return BGP_ATTR_PARSE_PROCEED;
+}
+
+static bgp_attr_parse_ret_t bgp_attr_aspath_check(struct peer *const peer,
+ struct attr *const attr)
+{
+ /* These checks were part of bgp_attr_aspath, but with
+ * as4 we should to check aspath things when
+ * aspath synthesizing with as4_path has already taken place.
+ * Otherwise we check ASPATH and use the synthesized thing, and that is
+ * not right.
+ * So do the checks later, i.e. here
+ */
+ struct bgp *bgp = peer->bgp;
+ struct aspath *aspath;
+
+ /* Confederation sanity check. */
+ if ((peer->sort == BGP_PEER_CONFED
+ && !aspath_left_confed_check(attr->aspath))
+ || (peer->sort == BGP_PEER_EBGP
+ && aspath_confed_check(attr->aspath))) {
+ zlog_err("Malformed AS path from %s", peer->host);
+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+ return BGP_ATTR_PARSE_ERROR;
+ }
- /* Set aspath attribute flag. */
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
+ /* First AS check for EBGP. */
+ if (bgp != NULL && bgp_flag_check(bgp, BGP_FLAG_ENFORCE_FIRST_AS)) {
+ if (peer->sort == BGP_PEER_EBGP
+ && !aspath_firstas_check(attr->aspath, peer->as)) {
+ zlog_err("%s incorrect first AS (must be %u)",
+ peer->host, peer->as);
+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_AS_PATH);
+ return BGP_ATTR_PARSE_ERROR;
+ }
+ }
- return BGP_ATTR_PARSE_PROCEED;
-}
+ /* local-as prepend */
+ if (peer->change_local_as
+ && !CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) {
+ aspath = aspath_dup(attr->aspath);
+ aspath = aspath_add_seq(aspath, peer->change_local_as);
+ aspath_unintern(&attr->aspath);
+ attr->aspath = aspath_intern(aspath);
+ }
-static bgp_attr_parse_ret_t
-bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
-{
- /* These checks were part of bgp_attr_aspath, but with
- * as4 we should to check aspath things when
- * aspath synthesizing with as4_path has already taken place.
- * Otherwise we check ASPATH and use the synthesized thing, and that is
- * not right.
- * So do the checks later, i.e. here
- */
- struct bgp *bgp = peer->bgp;
- struct aspath *aspath;
-
- /* Confederation sanity check. */
- if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
- (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
- {
- zlog_err ("Malformed AS path from %s", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH);
- return BGP_ATTR_PARSE_ERROR;
- }
-
- /* First AS check for EBGP. */
- if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
- {
- if (peer->sort == BGP_PEER_EBGP
- && ! aspath_firstas_check (attr->aspath, peer->as))
- {
- zlog_err ("%s incorrect first AS (must be %u)", peer->host, peer->as);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH);
- return BGP_ATTR_PARSE_ERROR;
- }
- }
-
- /* local-as prepend */
- if (peer->change_local_as &&
- ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
- {
- aspath = aspath_dup (attr->aspath);
- aspath = aspath_add_seq (aspath, peer->change_local_as);
- aspath_unintern (&attr->aspath);
- attr->aspath = aspath_intern (aspath);
- }
-
- return BGP_ATTR_PARSE_PROCEED;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Parse AS4 path information. This function is another wrapper of
aspath_parse. */
-static int
-bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
+static int bgp_attr_as4_path(struct bgp_attr_parser_args *args,
+ struct aspath **as4_path)
{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- *as4_path = aspath_parse (peer->ibuf, length, 1);
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
- /* In case of IBGP, length will be zero. */
- if (!*as4_path)
- {
- zlog_err ("Malformed AS4 path from %s, length is %d", peer->host, length);
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_MAL_AS_PATH,
- 0);
- }
+ *as4_path = aspath_parse(peer->ibuf, length, 1);
- /* Set aspath attribute flag. */
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
+ /* In case of IBGP, length will be zero. */
+ if (!*as4_path) {
+ zlog_err("Malformed AS4 path from %s, length is %d", peer->host,
+ length);
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+ 0);
+ }
- return BGP_ATTR_PARSE_PROCEED;
+ /* Set aspath attribute flag. */
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH);
+
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Nexthop attribute. */
-static bgp_attr_parse_ret_t
-bgp_attr_nexthop (struct bgp_attr_parser_args *args)
-{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- in_addr_t nexthop_h, nexthop_n;
-
- /* Check nexthop attribute length. */
- if (length != 4)
- {
- zlog_err ("Nexthop attribute length isn't four [%d]", length);
-
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- args->total);
- }
-
- /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
- attribute must result in a NOTIFICATION message (this is implemented below).
- At the same time, semantically incorrect NEXT_HOP is more likely to be just
- logged locally (this is implemented somewhere else). The UPDATE message
- gets ignored in any of these cases. */
- nexthop_n = stream_get_ipv4 (peer->ibuf);
- nexthop_h = ntohl (nexthop_n);
- if ((IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
- && !BGP_DEBUG (allow_martians, ALLOW_MARTIANS)) /* loopbacks may be used in testing */
- {
- char buf[INET_ADDRSTRLEN];
- inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN);
- zlog_err ("Martian nexthop %s", buf);
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
- args->total);
- }
-
- attr->nexthop.s_addr = nexthop_n;
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
-
- return BGP_ATTR_PARSE_PROCEED;
+static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ in_addr_t nexthop_h, nexthop_n;
+
+ /* Check nexthop attribute length. */
+ if (length != 4) {
+ zlog_err("Nexthop attribute length isn't four [%d]", length);
+
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
+ attribute must result in a NOTIFICATION message (this is implemented
+ below).
+ At the same time, semantically incorrect NEXT_HOP is more likely to
+ be just
+ logged locally (this is implemented somewhere else). The UPDATE
+ message
+ gets ignored in any of these cases. */
+ nexthop_n = stream_get_ipv4(peer->ibuf);
+ nexthop_h = ntohl(nexthop_n);
+ if ((IPV4_NET0(nexthop_h) || IPV4_NET127(nexthop_h)
+ || IPV4_CLASS_DE(nexthop_h))
+ && !BGP_DEBUG(
+ allow_martians,
+ ALLOW_MARTIANS)) /* loopbacks may be used in testing */
+ {
+ char buf[INET_ADDRSTRLEN];
+ inet_ntop(AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN);
+ zlog_err("Martian nexthop %s", buf);
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, args->total);
+ }
+
+ attr->nexthop.s_addr = nexthop_n;
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+
+ return BGP_ATTR_PARSE_PROCEED;
}
/* MED atrribute. */
-static bgp_attr_parse_ret_t
-bgp_attr_med (struct bgp_attr_parser_args *args)
+static bgp_attr_parse_ret_t bgp_attr_med(struct bgp_attr_parser_args *args)
{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- /* Length check. */
- if (length != 4)
- {
- zlog_err ("MED attribute length isn't four [%d]", length);
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- args->total);
- }
+ /* Length check. */
+ if (length != 4) {
+ zlog_err("MED attribute length isn't four [%d]", length);
- attr->med = stream_getl (peer->ibuf);
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ attr->med = stream_getl(peer->ibuf);
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
- return BGP_ATTR_PARSE_PROCEED;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Local preference attribute. */
static bgp_attr_parse_ret_t
-bgp_attr_local_pref (struct bgp_attr_parser_args *args)
-{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- /* Length check. */
- if (length != 4)
- {
- zlog_err ("LOCAL_PREF attribute length isn't 4 [%u]", length);
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- args->total);
- }
-
- /* If it is contained in an UPDATE message that is received from an
- external peer, then this attribute MUST be ignored by the
- receiving speaker. */
- if (peer->sort == BGP_PEER_EBGP)
- {
- stream_forward_getp (peer->ibuf, length);
- return BGP_ATTR_PARSE_PROCEED;
- }
-
- attr->local_pref = stream_getl (peer->ibuf);
-
- /* Set atomic aggregate flag. */
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
-
- return BGP_ATTR_PARSE_PROCEED;
+bgp_attr_local_pref(struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ /* Length check. */
+ if (length != 4) {
+ zlog_err("LOCAL_PREF attribute length isn't 4 [%u]", length);
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ /* If it is contained in an UPDATE message that is received from an
+ external peer, then this attribute MUST be ignored by the
+ receiving speaker. */
+ if (peer->sort == BGP_PEER_EBGP) {
+ stream_forward_getp(peer->ibuf, length);
+ return BGP_ATTR_PARSE_PROCEED;
+ }
+
+ attr->local_pref = stream_getl(peer->ibuf);
+
+ /* Set atomic aggregate flag. */
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
+
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Atomic aggregate. */
-static int
-bgp_attr_atomic (struct bgp_attr_parser_args *args)
+static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
{
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- /* Length check. */
- if (length != 0)
- {
- zlog_err ("ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- args->total);
- }
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ /* Length check. */
+ if (length != 0) {
+ zlog_err("ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
+ length);
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
- /* Set atomic aggregate flag. */
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
+ /* Set atomic aggregate flag. */
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
- return BGP_ATTR_PARSE_PROCEED;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Aggregator attribute */
-static int
-bgp_attr_aggregator (struct bgp_attr_parser_args *args)
-{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- int wantedlen = 6;
-
- /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
- if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
- wantedlen = 8;
-
- if (length != wantedlen)
- {
- zlog_err ("AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- args->total);
- }
-
- if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
- attr->aggregator_as = stream_getl (peer->ibuf);
- else
- attr->aggregator_as = stream_getw (peer->ibuf);
- attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
-
- /* Set atomic aggregate flag. */
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
-
- return BGP_ATTR_PARSE_PROCEED;
+static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ int wantedlen = 6;
+
+ /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
+ if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV))
+ wantedlen = 8;
+
+ if (length != wantedlen) {
+ zlog_err("AGGREGATOR attribute length isn't %u [%u]", wantedlen,
+ length);
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV))
+ attr->aggregator_as = stream_getl(peer->ibuf);
+ else
+ attr->aggregator_as = stream_getw(peer->ibuf);
+ attr->aggregator_addr.s_addr = stream_get_ipv4(peer->ibuf);
+
+ /* Set atomic aggregate flag. */
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
+
+ return BGP_ATTR_PARSE_PROCEED;
}
/* New Aggregator attribute */
static bgp_attr_parse_ret_t
-bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
- as_t *as4_aggregator_as,
- struct in_addr *as4_aggregator_addr)
-{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- if (length != 8)
- {
- zlog_err ("New Aggregator length is not 8 [%d]", length);
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- 0);
- }
-
- *as4_aggregator_as = stream_getl (peer->ibuf);
- as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
-
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
-
- return BGP_ATTR_PARSE_PROCEED;
+bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
+ as_t *as4_aggregator_as,
+ struct in_addr *as4_aggregator_addr)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ if (length != 8) {
+ zlog_err("New Aggregator length is not 8 [%d]", length);
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ 0);
+ }
+
+ *as4_aggregator_as = stream_getl(peer->ibuf);
+ as4_aggregator_addr->s_addr = stream_get_ipv4(peer->ibuf);
+
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR);
+
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
*/
static bgp_attr_parse_ret_t
-bgp_attr_munge_as4_attrs (struct peer *const peer,
- struct attr *const attr,
- struct aspath *as4_path, as_t as4_aggregator,
- struct in_addr *as4_aggregator_addr)
-{
- int ignore_as4_path = 0;
- struct aspath *newpath;
-
- if (!attr->aspath)
- {
- /* NULL aspath shouldn't be possible as bgp_attr_parse should have
- * checked that all well-known, mandatory attributes were present.
- *
- * Can only be a problem with peer itself - hard error
- */
- return BGP_ATTR_PARSE_ERROR;
- }
-
- if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
- {
- /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
- * if given.
- * It is worth a warning though, because the peer really
- * should not send them
- */
- if (BGP_DEBUG(as4, AS4))
- {
- if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
- zlog_debug ("[AS4] %s %s AS4_PATH",
- peer->host, "AS4 capable peer, yet it sent");
-
- if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
- zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
- peer->host, "AS4 capable peer, yet it sent");
- }
-
- return BGP_ATTR_PARSE_PROCEED;
- }
-
- /* We have a asn16 peer. First, look for AS4_AGGREGATOR
- * because that may override AS4_PATH
- */
- if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
- {
- if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
- {
- /* received both.
- * if the as_number in aggregator is not AS_TRANS,
- * then AS4_AGGREGATOR and AS4_PATH shall be ignored
- * and the Aggregator shall be taken as
- * info on the aggregating node, and the AS_PATH
- * shall be taken as the AS_PATH
- * otherwise
- * the Aggregator shall be ignored and the
- * AS4_AGGREGATOR shall be taken as the
- * Aggregating node and the AS_PATH is to be
- * constructed "as in all other cases"
- */
- if (attr->aggregator_as != BGP_AS_TRANS)
- {
- /* ignore */
- if ( BGP_DEBUG(as4, AS4))
- zlog_debug ("[AS4] %s BGP not AS4 capable peer"
- " send AGGREGATOR != AS_TRANS and"
- " AS4_AGGREGATOR, so ignore"
- " AS4_AGGREGATOR and AS4_PATH", peer->host);
- ignore_as4_path = 1;
- }
- else
- {
- /* "New_aggregator shall be taken as aggregator" */
- attr->aggregator_as = as4_aggregator;
- attr->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
- }
- }
- else
- {
- /* We received a AS4_AGGREGATOR but no AGGREGATOR.
- * That is bogus - but reading the conditions
- * we have to handle AS4_AGGREGATOR as if it were
- * AGGREGATOR in that case
- */
- if ( BGP_DEBUG(as4, AS4))
- zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
- " AS4_AGGREGATOR but no AGGREGATOR, will take"
- " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
- attr->aggregator_as = as4_aggregator;
- /* sweep it under the carpet and simulate a "good" AGGREGATOR */
- attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
- }
- }
-
- /* need to reconcile NEW_AS_PATH and AS_PATH */
- if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
- {
- newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
- aspath_unintern (&attr->aspath);
- attr->aspath = aspath_intern (newpath);
- }
- return BGP_ATTR_PARSE_PROCEED;
+bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
+ struct aspath *as4_path, as_t as4_aggregator,
+ struct in_addr *as4_aggregator_addr)
+{
+ int ignore_as4_path = 0;
+ struct aspath *newpath;
+
+ if (!attr->aspath) {
+ /* NULL aspath shouldn't be possible as bgp_attr_parse should
+ * have
+ * checked that all well-known, mandatory attributes were
+ * present.
+ *
+ * Can only be a problem with peer itself - hard error
+ */
+ return BGP_ATTR_PARSE_ERROR;
+ }
+
+ if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
+ /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
+ * if given.
+ * It is worth a warning though, because the peer really
+ * should not send them
+ */
+ if (BGP_DEBUG(as4, AS4)) {
+ if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
+ zlog_debug("[AS4] %s %s AS4_PATH", peer->host,
+ "AS4 capable peer, yet it sent");
+
+ if (attr->flag
+ & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
+ zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
+ peer->host,
+ "AS4 capable peer, yet it sent");
+ }
+
+ return BGP_ATTR_PARSE_PROCEED;
+ }
+
+ /* We have a asn16 peer. First, look for AS4_AGGREGATOR
+ * because that may override AS4_PATH
+ */
+ if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) {
+ if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) {
+ /* received both.
+ * if the as_number in aggregator is not AS_TRANS,
+ * then AS4_AGGREGATOR and AS4_PATH shall be ignored
+ * and the Aggregator shall be taken as
+ * info on the aggregating node, and the AS_PATH
+ * shall be taken as the AS_PATH
+ * otherwise
+ * the Aggregator shall be ignored and the
+ * AS4_AGGREGATOR shall be taken as the
+ * Aggregating node and the AS_PATH is to be
+ * constructed "as in all other cases"
+ */
+ if (attr->aggregator_as != BGP_AS_TRANS) {
+ /* ignore */
+ if (BGP_DEBUG(as4, AS4))
+ zlog_debug(
+ "[AS4] %s BGP not AS4 capable peer"
+ " send AGGREGATOR != AS_TRANS and"
+ " AS4_AGGREGATOR, so ignore"
+ " AS4_AGGREGATOR and AS4_PATH",
+ peer->host);
+ ignore_as4_path = 1;
+ } else {
+ /* "New_aggregator shall be taken as aggregator"
+ */
+ attr->aggregator_as = as4_aggregator;
+ attr->aggregator_addr.s_addr =
+ as4_aggregator_addr->s_addr;
+ }
+ } else {
+ /* We received a AS4_AGGREGATOR but no AGGREGATOR.
+ * That is bogus - but reading the conditions
+ * we have to handle AS4_AGGREGATOR as if it were
+ * AGGREGATOR in that case
+ */
+ if (BGP_DEBUG(as4, AS4))
+ zlog_debug(
+ "[AS4] %s BGP not AS4 capable peer send"
+ " AS4_AGGREGATOR but no AGGREGATOR, will take"
+ " it as if AGGREGATOR with AS_TRANS had been there",
+ peer->host);
+ attr->aggregator_as = as4_aggregator;
+ /* sweep it under the carpet and simulate a "good"
+ * AGGREGATOR */
+ attr->flag |= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR));
+ }
+ }
+
+ /* need to reconcile NEW_AS_PATH and AS_PATH */
+ if (!ignore_as4_path
+ && (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))) {
+ newpath = aspath_reconcile_as4(attr->aspath, as4_path);
+ aspath_unintern(&attr->aspath);
+ attr->aspath = aspath_intern(newpath);
+ }
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Community attribute. */
static bgp_attr_parse_ret_t
-bgp_attr_community (struct bgp_attr_parser_args *args)
-{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- if (length == 0)
- {
- attr->community = NULL;
- return BGP_ATTR_PARSE_PROCEED;
- }
-
- attr->community =
- community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
-
- /* XXX: fix community_parse to use stream API and remove this */
- stream_forward_getp (peer->ibuf, length);
-
- if (!attr->community)
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
- args->total);
-
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
-
- return BGP_ATTR_PARSE_PROCEED;
+bgp_attr_community(struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ if (length == 0) {
+ attr->community = NULL;
+ return BGP_ATTR_PARSE_PROCEED;
+ }
+
+ attr->community =
+ community_parse((u_int32_t *)stream_pnt(peer->ibuf), length);
+
+ /* XXX: fix community_parse to use stream API and remove this */
+ stream_forward_getp(peer->ibuf, length);
+
+ if (!attr->community)
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
+
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES);
+
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Originator ID attribute. */
static bgp_attr_parse_ret_t
-bgp_attr_originator_id (struct bgp_attr_parser_args *args)
+bgp_attr_originator_id(struct bgp_attr_parser_args *args)
{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- /* Length check. */
- if (length != 4)
- {
- zlog_err ("Bad originator ID length %d", length);
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- args->total);
- }
+ /* Length check. */
+ if (length != 4) {
+ zlog_err("Bad originator ID length %d", length);
- attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf);
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ attr->originator_id.s_addr = stream_get_ipv4(peer->ibuf);
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID);
- return BGP_ATTR_PARSE_PROCEED;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Cluster list attribute. */
static bgp_attr_parse_ret_t
-bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
+bgp_attr_cluster_list(struct bgp_attr_parser_args *args)
{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- /* Check length. */
- if (length % 4)
- {
- zlog_err ("Bad cluster list length %d", length);
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ /* Check length. */
+ if (length % 4) {
+ zlog_err("Bad cluster list length %d", length);
- return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- args->total);
- }
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ attr->cluster =
+ cluster_parse((struct in_addr *)stream_pnt(peer->ibuf), length);
- attr->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
-
- /* XXX: Fix cluster_parse to use stream API and then remove this */
- stream_forward_getp (peer->ibuf, length);
+ /* XXX: Fix cluster_parse to use stream API and then remove this */
+ stream_forward_getp(peer->ibuf, length);
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST);
- return BGP_ATTR_PARSE_PROCEED;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Multiprotocol reachability information parse. */
-int
-bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
- struct bgp_nlri *mp_update)
-{
- iana_afi_t pkt_afi;
- afi_t afi;
- safi_t pkt_safi, safi;
- bgp_size_t nlri_len;
- size_t start;
- struct stream *s;
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- /* Set end of packet. */
- s = BGP_INPUT(peer);
- start = stream_get_getp(s);
-
- /* safe to read statically sized header? */
+int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
+ struct bgp_nlri *mp_update)
+{
+ iana_afi_t pkt_afi;
+ afi_t afi;
+ safi_t pkt_safi, safi;
+ bgp_size_t nlri_len;
+ size_t start;
+ struct stream *s;
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ /* Set end of packet. */
+ s = BGP_INPUT(peer);
+ start = stream_get_getp(s);
+
+/* safe to read statically sized header? */
#define BGP_MP_REACH_MIN_SIZE 5
#define LEN_LEFT (length - (stream_get_getp(s) - start))
- if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
- {
- zlog_info ("%s: %s sent invalid length, %lu",
- __func__, peer->host, (unsigned long)length);
- return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
- }
-
- /* Load AFI, SAFI. */
- pkt_afi = stream_getw (s);
- pkt_safi = stream_getc (s);
-
- /* Convert AFI, SAFI to internal values, check. */
- if (bgp_map_afi_safi_iana2int (pkt_afi, pkt_safi, &afi, &safi))
- {
- /* Log if AFI or SAFI is unrecognized. This is not an error unless
- * the attribute is otherwise malformed.
- */
- if (bgp_debug_update(peer, NULL, NULL, 0))
- zlog_debug ("%s: MP_REACH received AFI %u or SAFI %u is unrecognized",
- peer->host, pkt_afi, pkt_safi);
- return BGP_ATTR_PARSE_ERROR;
- }
-
- /* Get nexthop length. */
- attr->mp_nexthop_len = stream_getc (s);
-
- if (LEN_LEFT < attr->mp_nexthop_len)
- {
- zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
- __func__, peer->host, attr->mp_nexthop_len);
- return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
- }
-
- /* Nexthop length check. */
- switch (attr->mp_nexthop_len)
- {
- case BGP_ATTR_NHLEN_IPV4:
- stream_get (&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
- /* Probably needed for RFC 2283 */
- if (attr->nexthop.s_addr == 0)
- memcpy(&attr->nexthop.s_addr, &attr->mp_nexthop_global_in, IPV4_MAX_BYTELEN);
- break;
- case BGP_ATTR_NHLEN_VPNV4:
- stream_getl (s); /* RD high */
- stream_getl (s); /* RD low */
- stream_get (&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
- break;
- case BGP_ATTR_NHLEN_IPV6_GLOBAL:
- case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
- if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL)
- {
- stream_getl (s); /* RD high */
- stream_getl (s); /* RD low */
- }
- stream_get (&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
- break;
- case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
- case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL:
- if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)
- {
- stream_getl (s); /* RD high */
- stream_getl (s); /* RD low */
- }
- stream_get (&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
- if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)
- {
- stream_getl (s); /* RD high */
- stream_getl (s); /* RD low */
- }
- stream_get (&attr->mp_nexthop_local, s, IPV6_MAX_BYTELEN);
- if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local))
+ if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE)) {
+ zlog_info("%s: %s sent invalid length, %lu", __func__,
+ peer->host, (unsigned long)length);
+ return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
+ }
+
+ /* Load AFI, SAFI. */
+ pkt_afi = stream_getw(s);
+ pkt_safi = stream_getc(s);
+
+ /* Convert AFI, SAFI to internal values, check. */
+ if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
+ /* Log if AFI or SAFI is unrecognized. This is not an error
+ * unless
+ * the attribute is otherwise malformed.
+ */
+ if (bgp_debug_update(peer, NULL, NULL, 0))
+ zlog_debug(
+ "%s: MP_REACH received AFI %u or SAFI %u is unrecognized",
+ peer->host, pkt_afi, pkt_safi);
+ return BGP_ATTR_PARSE_ERROR;
+ }
+
+ /* Get nexthop length. */
+ attr->mp_nexthop_len = stream_getc(s);
+
+ if (LEN_LEFT < attr->mp_nexthop_len) {
+ zlog_info(
+ "%s: %s, MP nexthop length, %u, goes past end of attribute",
+ __func__, peer->host, attr->mp_nexthop_len);
+ return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
+ }
+
+ /* Nexthop length check. */
+ switch (attr->mp_nexthop_len) {
+ case BGP_ATTR_NHLEN_IPV4:
+ stream_get(&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
+ /* Probably needed for RFC 2283 */
+ if (attr->nexthop.s_addr == 0)
+ memcpy(&attr->nexthop.s_addr,
+ &attr->mp_nexthop_global_in, IPV4_MAX_BYTELEN);
+ break;
+ case BGP_ATTR_NHLEN_VPNV4:
+ stream_getl(s); /* RD high */
+ stream_getl(s); /* RD low */
+ stream_get(&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
+ break;
+ case BGP_ATTR_NHLEN_IPV6_GLOBAL:
+ case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
+ if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL) {
+ stream_getl(s); /* RD high */
+ stream_getl(s); /* RD low */
+ }
+ stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
+ break;
+ case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
+ case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL:
+ if (attr->mp_nexthop_len
+ == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
+ stream_getl(s); /* RD high */
+ stream_getl(s); /* RD low */
+ }
+ stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
+ if (attr->mp_nexthop_len
+ == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
+ stream_getl(s); /* RD high */
+ stream_getl(s); /* RD low */
+ }
+ stream_get(&attr->mp_nexthop_local, s, IPV6_MAX_BYTELEN);
+ if (!IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local)) {
+ char buf1[INET6_ADDRSTRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+
+ if (bgp_debug_update(peer, NULL, NULL, 1))
+ zlog_debug(
+ "%s rcvd nexthops %s, %s -- ignoring non-LL value",
+ peer->host,
+ inet_ntop(AF_INET6,
+ &attr->mp_nexthop_global,
+ buf1, INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6,
+ &attr->mp_nexthop_local, buf2,
+ INET6_ADDRSTRLEN));
+
+ attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
+ }
+ break;
+ default:
+ zlog_info("%s: (%s) Wrong multiprotocol next hop length: %d",
+ __func__, peer->host, attr->mp_nexthop_len);
+ return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
+ }
+
+ if (!LEN_LEFT) {
+ zlog_info("%s: (%s) Failed to read SNPA and NLRI(s)", __func__,
+ peer->host);
+ return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
+ }
+
{
- char buf1[INET6_ADDRSTRLEN];
- char buf2[INET6_ADDRSTRLEN];
-
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug ("%s rcvd nexthops %s, %s -- ignoring non-LL value",
- peer->host,
- inet_ntop (AF_INET6, &attr->mp_nexthop_global,
- buf1, INET6_ADDRSTRLEN),
- inet_ntop (AF_INET6, &attr->mp_nexthop_local,
- buf2, INET6_ADDRSTRLEN));
-
- attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
- }
- break;
- default:
- zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
- __func__, peer->host, attr->mp_nexthop_len);
- return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
- }
-
- if (!LEN_LEFT)
- {
- zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
- __func__, peer->host);
- return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
- }
-
- {
- u_char val;
- if ((val = stream_getc (s)))
- zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
- peer->host, val);
- }
-
- /* must have nrli_len, what is left of the attribute */
- nlri_len = LEN_LEFT;
- if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
- {
- zlog_info ("%s: (%s) Failed to read NLRI",
- __func__, peer->host);
- return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
- }
-
- mp_update->afi = afi;
- mp_update->safi = safi;
- mp_update->nlri = stream_pnt (s);
- mp_update->length = nlri_len;
-
- stream_forward_getp (s, nlri_len);
-
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI);
-
- return BGP_ATTR_PARSE_PROCEED;
+ u_char val;
+ if ((val = stream_getc(s)))
+ zlog_warn(
+ "%s sent non-zero value, %u, for defunct SNPA-length field",
+ peer->host, val);
+ }
+
+ /* must have nrli_len, what is left of the attribute */
+ nlri_len = LEN_LEFT;
+ if ((!nlri_len) || (nlri_len > STREAM_READABLE(s))) {
+ zlog_info("%s: (%s) Failed to read NLRI", __func__, peer->host);
+ return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
+ }
+
+ mp_update->afi = afi;
+ mp_update->safi = safi;
+ mp_update->nlri = stream_pnt(s);
+ mp_update->length = nlri_len;
+
+ stream_forward_getp(s, nlri_len);
+
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI);
+
+ return BGP_ATTR_PARSE_PROCEED;
#undef LEN_LEFT
}
/* Multiprotocol unreachable parse */
-int
-bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
- struct bgp_nlri *mp_withdraw)
-{
- struct stream *s;
- iana_afi_t pkt_afi;
- afi_t afi;
- safi_t pkt_safi, safi;
- u_int16_t withdraw_len;
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- s = peer->ibuf;
-
-#define BGP_MP_UNREACH_MIN_SIZE 3
- if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
- return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
-
- pkt_afi = stream_getw (s);
- pkt_safi = stream_getc (s);
+int bgp_mp_unreach_parse(struct bgp_attr_parser_args *args,
+ struct bgp_nlri *mp_withdraw)
+{
+ struct stream *s;
+ iana_afi_t pkt_afi;
+ afi_t afi;
+ safi_t pkt_safi, safi;
+ u_int16_t withdraw_len;
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
- /* Convert AFI, SAFI to internal values, check. */
- if (bgp_map_afi_safi_iana2int (pkt_afi, pkt_safi, &afi, &safi))
- {
- /* Log if AFI or SAFI is unrecognized. This is not an error unless
- * the attribute is otherwise malformed.
- */
- if (bgp_debug_update(peer, NULL, NULL, 0))
- zlog_debug ("%s: MP_UNREACH received AFI %u or SAFI %u is unrecognized",
- peer->host, pkt_afi, pkt_safi);
- return BGP_ATTR_PARSE_ERROR;
- }
+ s = peer->ibuf;
- withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
+#define BGP_MP_UNREACH_MIN_SIZE 3
+ if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
+ return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
+
+ pkt_afi = stream_getw(s);
+ pkt_safi = stream_getc(s);
+
+ /* Convert AFI, SAFI to internal values, check. */
+ if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
+ /* Log if AFI or SAFI is unrecognized. This is not an error
+ * unless
+ * the attribute is otherwise malformed.
+ */
+ if (bgp_debug_update(peer, NULL, NULL, 0))
+ zlog_debug(
+ "%s: MP_UNREACH received AFI %u or SAFI %u is unrecognized",
+ peer->host, pkt_afi, pkt_safi);
+ return BGP_ATTR_PARSE_ERROR;
+ }
- mp_withdraw->afi = afi;
- mp_withdraw->safi = safi;
- mp_withdraw->nlri = stream_pnt (s);
- mp_withdraw->length = withdraw_len;
+ withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
- stream_forward_getp (s, withdraw_len);
+ mp_withdraw->afi = afi;
+ mp_withdraw->safi = safi;
+ mp_withdraw->nlri = stream_pnt(s);
+ mp_withdraw->length = withdraw_len;
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI);
+ stream_forward_getp(s, withdraw_len);
- return BGP_ATTR_PARSE_PROCEED;
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI);
+
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Large Community attribute. */
static bgp_attr_parse_ret_t
-bgp_attr_large_community (struct bgp_attr_parser_args *args)
-{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
-
- /*
- * Large community follows new attribute format.
- */
- if (length == 0)
- {
- attr->lcommunity = NULL;
- /* Empty extcomm doesn't seem to be invalid per se */
- return BGP_ATTR_PARSE_PROCEED;
- }
+bgp_attr_large_community(struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+
+ /*
+ * Large community follows new attribute format.
+ */
+ if (length == 0) {
+ attr->lcommunity = NULL;
+ /* Empty extcomm doesn't seem to be invalid per se */
+ return BGP_ATTR_PARSE_PROCEED;
+ }
- attr->lcommunity = lcommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
- /* XXX: fix ecommunity_parse to use stream API */
- stream_forward_getp (peer->ibuf, length);
+ attr->lcommunity =
+ lcommunity_parse((u_int8_t *)stream_pnt(peer->ibuf), length);
+ /* XXX: fix ecommunity_parse to use stream API */
+ stream_forward_getp(peer->ibuf, length);
- if (!attr->lcommunity)
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
- args->total);
+ if (!attr->lcommunity)
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES);
- return BGP_ATTR_PARSE_PROCEED;
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Extended Community attribute. */
static bgp_attr_parse_ret_t
-bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
-{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- const bgp_size_t length = args->length;
- u_char sticky = 0;
-
- if (length == 0)
- {
- attr->ecommunity = NULL;
- /* Empty extcomm doesn't seem to be invalid per se */
- return BGP_ATTR_PARSE_PROCEED;
- }
-
- attr->ecommunity = ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
- /* XXX: fix ecommunity_parse to use stream API */
- stream_forward_getp (peer->ibuf, length);
-
- if (!attr->ecommunity)
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
- args->total);
-
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
-
- /* Extract MAC mobility sequence number, if any. */
- attr->mm_seqnum = bgp_attr_mac_mobility_seqnum (attr, &sticky);
- attr->sticky = sticky;
-
- return BGP_ATTR_PARSE_PROCEED;
+bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+ u_char sticky = 0;
+
+ if (length == 0) {
+ attr->ecommunity = NULL;
+ /* Empty extcomm doesn't seem to be invalid per se */
+ return BGP_ATTR_PARSE_PROCEED;
+ }
+
+ attr->ecommunity =
+ ecommunity_parse((u_int8_t *)stream_pnt(peer->ibuf), length);
+ /* XXX: fix ecommunity_parse to use stream API */
+ stream_forward_getp(peer->ibuf, length);
+
+ if (!attr->ecommunity)
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
+
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
+
+ /* Extract MAC mobility sequence number, if any. */
+ attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky);
+ attr->sticky = sticky;
+
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Parse Tunnel Encap attribute in an UPDATE */
-static int
-bgp_attr_encap(
- uint8_t type,
- struct peer *peer, /* IN */
- bgp_size_t length, /* IN: attr's length field */
- struct attr *attr, /* IN: caller already allocated */
- u_char flag, /* IN: attr's flags field */
- u_char *startp)
-{
- bgp_size_t total;
- struct bgp_attr_encap_subtlv *stlv_last = NULL;
- uint16_t tunneltype = 0;
-
- total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
-
- if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
- || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
- {
- zlog_info ("Tunnel Encap attribute flag isn't optional and transitive %d", flag);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- startp, total);
- return -1;
- }
-
- if (BGP_ATTR_ENCAP == type) {
- /* read outer TLV type and length */
- uint16_t tlv_length;
-
- if (length < 4) {
- zlog_info ("Tunnel Encap attribute not long enough to contain outer T,L");
- bgp_notify_send_with_data(peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
- startp, total);
- return -1;
- }
- tunneltype = stream_getw (BGP_INPUT (peer));
- tlv_length = stream_getw (BGP_INPUT (peer));
- length -= 4;
-
- if (tlv_length != length) {
- zlog_info ("%s: tlv_length(%d) != length(%d)",
- __func__, tlv_length, length);
- }
- }
-
- while (length >= 4) {
- uint16_t subtype = 0;
- uint16_t sublength = 0;
- struct bgp_attr_encap_subtlv *tlv;
-
- if (BGP_ATTR_ENCAP == type) {
- subtype = stream_getc (BGP_INPUT (peer));
- sublength = stream_getc (BGP_INPUT (peer));
- length -= 2;
+static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */
+ bgp_size_t length, /* IN: attr's length field */
+ struct attr *attr, /* IN: caller already allocated */
+ u_char flag, /* IN: attr's flags field */
+ u_char *startp)
+{
+ bgp_size_t total;
+ struct bgp_attr_encap_subtlv *stlv_last = NULL;
+ uint16_t tunneltype = 0;
+
+ total = length + (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+
+ if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
+ || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) {
+ zlog_info(
+ "Tunnel Encap attribute flag isn't optional and transitive %d",
+ flag);
+ bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ startp, total);
+ return -1;
+ }
+
+ if (BGP_ATTR_ENCAP == type) {
+ /* read outer TLV type and length */
+ uint16_t tlv_length;
+
+ if (length < 4) {
+ zlog_info(
+ "Tunnel Encap attribute not long enough to contain outer T,L");
+ bgp_notify_send_with_data(
+ peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total);
+ return -1;
+ }
+ tunneltype = stream_getw(BGP_INPUT(peer));
+ tlv_length = stream_getw(BGP_INPUT(peer));
+ length -= 4;
+
+ if (tlv_length != length) {
+ zlog_info("%s: tlv_length(%d) != length(%d)", __func__,
+ tlv_length, length);
+ }
+ }
+
+ while (length >= 4) {
+ uint16_t subtype = 0;
+ uint16_t sublength = 0;
+ struct bgp_attr_encap_subtlv *tlv;
+
+ if (BGP_ATTR_ENCAP == type) {
+ subtype = stream_getc(BGP_INPUT(peer));
+ sublength = stream_getc(BGP_INPUT(peer));
+ length -= 2;
#if ENABLE_BGP_VNC
- } else {
- subtype = stream_getw (BGP_INPUT (peer));
- sublength = stream_getw (BGP_INPUT (peer));
- length -= 4;
+ } else {
+ subtype = stream_getw(BGP_INPUT(peer));
+ sublength = stream_getw(BGP_INPUT(peer));
+ length -= 4;
#endif
- }
-
- if (sublength > length) {
- zlog_info ("Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
- sublength, length);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
- startp, total);
- return -1;
- }
-
- /* alloc and copy sub-tlv */
- /* TBD make sure these are freed when attributes are released */
- tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+sublength);
- tlv->type = subtype;
- tlv->length = sublength;
- stream_get(tlv->value, peer->ibuf, sublength);
- length -= sublength;
-
- /* attach tlv to encap chain */
- if (BGP_ATTR_ENCAP == type) {
- for (stlv_last = attr->encap_subtlvs; stlv_last && stlv_last->next;
- stlv_last = stlv_last->next);
- if (stlv_last) {
- stlv_last->next = tlv;
- } else {
- attr->encap_subtlvs = tlv;
- }
+ }
+
+ if (sublength > length) {
+ zlog_info(
+ "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
+ sublength, length);
+ bgp_notify_send_with_data(
+ peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total);
+ return -1;
+ }
+
+ /* alloc and copy sub-tlv */
+ /* TBD make sure these are freed when attributes are released */
+ tlv = XCALLOC(MTYPE_ENCAP_TLV,
+ sizeof(struct bgp_attr_encap_subtlv) - 1
+ + sublength);
+ tlv->type = subtype;
+ tlv->length = sublength;
+ stream_get(tlv->value, peer->ibuf, sublength);
+ length -= sublength;
+
+ /* attach tlv to encap chain */
+ if (BGP_ATTR_ENCAP == type) {
+ for (stlv_last = attr->encap_subtlvs;
+ stlv_last && stlv_last->next;
+ stlv_last = stlv_last->next)
+ ;
+ if (stlv_last) {
+ stlv_last->next = tlv;
+ } else {
+ attr->encap_subtlvs = tlv;
+ }
#if ENABLE_BGP_VNC
- } else {
- for (stlv_last = attr->vnc_subtlvs; stlv_last && stlv_last->next;
- stlv_last = stlv_last->next);
- if (stlv_last) {
- stlv_last->next = tlv;
- } else {
- attr->vnc_subtlvs = tlv;
- }
+ } else {
+ for (stlv_last = attr->vnc_subtlvs;
+ stlv_last && stlv_last->next;
+ stlv_last = stlv_last->next)
+ ;
+ if (stlv_last) {
+ stlv_last->next = tlv;
+ } else {
+ attr->vnc_subtlvs = tlv;
+ }
#endif
- }
- stlv_last->next = tlv;
- }
+ }
+ stlv_last->next = tlv;
+ }
- if (BGP_ATTR_ENCAP == type) {
- attr->encap_tunneltype = tunneltype;
- }
+ if (BGP_ATTR_ENCAP == type) {
+ attr->encap_tunneltype = tunneltype;
+ }
- if (length) {
- /* spurious leftover data */
- zlog_info ("Tunnel Encap attribute length is bad: %d leftover octets", length);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
- startp, total);
- return -1;
- }
+ if (length) {
+ /* spurious leftover data */
+ zlog_info(
+ "Tunnel Encap attribute length is bad: %d leftover octets",
+ length);
+ bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ startp, total);
+ return -1;
+ }
- return 0;
+ return 0;
}
/* Prefix SID attribute
* draft-ietf-idr-bgp-prefix-sid-05
*/
static bgp_attr_parse_ret_t
-bgp_attr_prefix_sid (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_update)
-{
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- int type;
- int length;
- u_int32_t label_index;
- struct in6_addr ipv6_sid;
- u_int32_t srgb_base;
- u_int32_t srgb_range;
- int srgb_count;
-
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID);
-
- type = stream_getc (peer->ibuf);
- length = stream_getw (peer->ibuf);
-
- if (type == BGP_PREFIX_SID_LABEL_INDEX)
- {
- if (length != BGP_PREFIX_SID_LABEL_INDEX_LENGTH)
- {
- zlog_err ("Prefix SID label index length is %d instead of %d", length, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- args->total);
- }
-
- /* Ignore flags and reserved */
- stream_getc (peer->ibuf);
- stream_getw (peer->ibuf);
-
- /* Fetch the label index and see if it is valid. */
- label_index = stream_getl (peer->ibuf);
- if (label_index == BGP_INVALID_LABEL_INDEX)
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
- args->total);
-
- /* Store label index; subsequently, we'll check on address-family */
- attr->label_index = label_index;
-
- /*
- * Ignore the Label index attribute unless received for labeled-unicast
- * SAFI.
- */
- if (!mp_update->length || mp_update->safi != SAFI_LABELED_UNICAST)
- attr->label_index = BGP_INVALID_LABEL_INDEX;
- }
-
- /* Placeholder code for the IPv6 SID type */
- else if (type == BGP_PREFIX_SID_IPV6)
- {
- if (length != BGP_PREFIX_SID_IPV6_LENGTH)
- {
- zlog_err ("Prefix SID IPv6 length is %d instead of %d", length, BGP_PREFIX_SID_IPV6_LENGTH);
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- args->total);
- }
-
- /* Ignore reserved */
- stream_getc (peer->ibuf);
- stream_getw (peer->ibuf);
-
- stream_get (&ipv6_sid, peer->ibuf, 16);
- }
-
- /* Placeholder code for the Originator SRGB type */
- else if (type == BGP_PREFIX_SID_ORIGINATOR_SRGB)
- {
- /* Ignore flags */
- stream_getw (peer->ibuf);
-
- length -= 2;
-
- if (length % BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH)
- {
- zlog_err ("Prefix SID Originator SRGB length is %d, it must be a multiple of %d ",
- length, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH);
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- args->total);
- }
-
- srgb_count = length / BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH;
-
- for (int i = 0; i < srgb_count; i++)
- {
- stream_get (&srgb_base, peer->ibuf, 3);
- stream_get (&srgb_range, peer->ibuf, 3);
- }
- }
-
- return BGP_ATTR_PARSE_PROCEED;
+bgp_attr_prefix_sid(struct bgp_attr_parser_args *args,
+ struct bgp_nlri *mp_update)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ int type;
+ int length;
+ u_int32_t label_index;
+ struct in6_addr ipv6_sid;
+ u_int32_t srgb_base;
+ u_int32_t srgb_range;
+ int srgb_count;
+
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID);
+
+ type = stream_getc(peer->ibuf);
+ length = stream_getw(peer->ibuf);
+
+ if (type == BGP_PREFIX_SID_LABEL_INDEX) {
+ if (length != BGP_PREFIX_SID_LABEL_INDEX_LENGTH) {
+ zlog_err(
+ "Prefix SID label index length is %d instead of %d",
+ length, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ /* Ignore flags and reserved */
+ stream_getc(peer->ibuf);
+ stream_getw(peer->ibuf);
+
+ /* Fetch the label index and see if it is valid. */
+ label_index = stream_getl(peer->ibuf);
+ if (label_index == BGP_INVALID_LABEL_INDEX)
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+ args->total);
+
+ /* Store label index; subsequently, we'll check on
+ * address-family */
+ attr->label_index = label_index;
+
+ /*
+ * Ignore the Label index attribute unless received for
+ * labeled-unicast
+ * SAFI.
+ */
+ if (!mp_update->length
+ || mp_update->safi != SAFI_LABELED_UNICAST)
+ attr->label_index = BGP_INVALID_LABEL_INDEX;
+ }
+
+ /* Placeholder code for the IPv6 SID type */
+ else if (type == BGP_PREFIX_SID_IPV6) {
+ if (length != BGP_PREFIX_SID_IPV6_LENGTH) {
+ zlog_err("Prefix SID IPv6 length is %d instead of %d",
+ length, BGP_PREFIX_SID_IPV6_LENGTH);
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ /* Ignore reserved */
+ stream_getc(peer->ibuf);
+ stream_getw(peer->ibuf);
+
+ stream_get(&ipv6_sid, peer->ibuf, 16);
+ }
+
+ /* Placeholder code for the Originator SRGB type */
+ else if (type == BGP_PREFIX_SID_ORIGINATOR_SRGB) {
+ /* Ignore flags */
+ stream_getw(peer->ibuf);
+
+ length -= 2;
+
+ if (length % BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH) {
+ zlog_err(
+ "Prefix SID Originator SRGB length is %d, it must be a multiple of %d ",
+ length, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH);
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ srgb_count = length / BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH;
+
+ for (int i = 0; i < srgb_count; i++) {
+ stream_get(&srgb_base, peer->ibuf, 3);
+ stream_get(&srgb_range, peer->ibuf, 3);
+ }
+ }
+
+ return BGP_ATTR_PARSE_PROCEED;
}
/* BGP unknown attribute treatment. */
-static bgp_attr_parse_ret_t
-bgp_attr_unknown (struct bgp_attr_parser_args *args)
-{
- bgp_size_t total = args->total;
- struct transit *transit;
- struct peer *const peer = args->peer;
- struct attr *const attr = args->attr;
- u_char *const startp = args->startp;
- const u_char type = args->type;
- const u_char flag = args->flags;
- const bgp_size_t length = args->length;
-
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
- peer->host, type, length);
-
- /* Forward read pointer of input stream. */
- stream_forward_getp (peer->ibuf, length);
-
- /* If any of the mandatory well-known attributes are not recognized,
- then the Error Subcode is set to Unrecognized Well-known
- Attribute. The Data field contains the unrecognized attribute
- (type, length and value). */
- if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
- {
- return bgp_attr_malformed (args,
- BGP_NOTIFY_UPDATE_UNREC_ATTR,
- args->total);
- }
-
- /* Unrecognized non-transitive optional attributes must be quietly
- ignored and not passed along to other BGP peers. */
- if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
- return BGP_ATTR_PARSE_PROCEED;
-
- /* If a path with recognized transitive optional attribute is
- accepted and passed along to other BGP peers and the Partial bit
- in the Attribute Flags octet is set to 1 by some previous AS, it
- is not set back to 0 by the current AS. */
- SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
-
- /* Store transitive attribute to the end of attr->transit. */
- if (!attr->transit)
- attr->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
-
- transit = attr->transit;
-
- if (transit->val)
- transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
- transit->length + total);
- else
- transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
-
- memcpy (transit->val + transit->length, startp, total);
- transit->length += total;
-
- return BGP_ATTR_PARSE_PROCEED;
+static bgp_attr_parse_ret_t bgp_attr_unknown(struct bgp_attr_parser_args *args)
+{
+ bgp_size_t total = args->total;
+ struct transit *transit;
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ u_char *const startp = args->startp;
+ const u_char type = args->type;
+ const u_char flag = args->flags;
+ const bgp_size_t length = args->length;
+
+ if (bgp_debug_update(peer, NULL, NULL, 1))
+ zlog_debug(
+ "%s Unknown attribute is received (type %d, length %d)",
+ peer->host, type, length);
+
+ /* Forward read pointer of input stream. */
+ stream_forward_getp(peer->ibuf, length);
+
+ /* If any of the mandatory well-known attributes are not recognized,
+ then the Error Subcode is set to Unrecognized Well-known
+ Attribute. The Data field contains the unrecognized attribute
+ (type, length and value). */
+ if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) {
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_UNREC_ATTR,
+ args->total);
+ }
+
+ /* Unrecognized non-transitive optional attributes must be quietly
+ ignored and not passed along to other BGP peers. */
+ if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
+ return BGP_ATTR_PARSE_PROCEED;
+
+ /* If a path with recognized transitive optional attribute is
+ accepted and passed along to other BGP peers and the Partial bit
+ in the Attribute Flags octet is set to 1 by some previous AS, it
+ is not set back to 0 by the current AS. */
+ SET_FLAG(*startp, BGP_ATTR_FLAG_PARTIAL);
+
+ /* Store transitive attribute to the end of attr->transit. */
+ if (!attr->transit)
+ attr->transit = XCALLOC(MTYPE_TRANSIT, sizeof(struct transit));
+
+ transit = attr->transit;
+
+ if (transit->val)
+ transit->val = XREALLOC(MTYPE_TRANSIT_VAL, transit->val,
+ transit->length + total);
+ else
+ transit->val = XMALLOC(MTYPE_TRANSIT_VAL, total);
+
+ memcpy(transit->val + transit->length, startp, total);
+ transit->length += total;
+
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Well-known attribute check. */
-static int
-bgp_attr_check (struct peer *peer, struct attr *attr)
-{
- u_char type = 0;
-
- /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
- * empty UPDATE. */
- if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag)
- return BGP_ATTR_PARSE_PROCEED;
-
- /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
- to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
- are present, it should. Check for any other attribute being present
- instead.
- */
- if (attr->flag == ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI))
- return BGP_ATTR_PARSE_PROCEED;
-
- if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
- type = BGP_ATTR_ORIGIN;
-
- if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
- type = BGP_ATTR_AS_PATH;
-
- /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present and
- * NLRI is empty. We can't easily check NLRI empty here though.
- */
- if (!CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))
- && !CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI)))
- type = BGP_ATTR_NEXT_HOP;
-
- if (peer->sort == BGP_PEER_IBGP
- && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
- type = BGP_ATTR_LOCAL_PREF;
-
- if (type)
- {
- zlog_warn ("%s Missing well-known attribute %s.", peer->host,
- lookup_msg(attr_str, type, NULL));
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MISS_ATTR,
- &type, 1);
- return BGP_ATTR_PARSE_ERROR;
- }
- return BGP_ATTR_PARSE_PROCEED;
+static int bgp_attr_check(struct peer *peer, struct attr *attr)
+{
+ u_char type = 0;
+
+ /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
+ * empty UPDATE. */
+ if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag)
+ return BGP_ATTR_PARSE_PROCEED;
+
+ /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
+ to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
+ are present, it should. Check for any other attribute being present
+ instead.
+ */
+ if (attr->flag == ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI))
+ return BGP_ATTR_PARSE_PROCEED;
+
+ if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN)))
+ type = BGP_ATTR_ORIGIN;
+
+ if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
+ type = BGP_ATTR_AS_PATH;
+
+ /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present
+ * and
+ * NLRI is empty. We can't easily check NLRI empty here though.
+ */
+ if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))
+ && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)))
+ type = BGP_ATTR_NEXT_HOP;
+
+ if (peer->sort == BGP_PEER_IBGP
+ && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)))
+ type = BGP_ATTR_LOCAL_PREF;
+
+ if (type) {
+ zlog_warn("%s Missing well-known attribute %s.", peer->host,
+ lookup_msg(attr_str, type, NULL));
+ bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MISS_ATTR, &type,
+ 1);
+ return BGP_ATTR_PARSE_ERROR;
+ }
+ return BGP_ATTR_PARSE_PROCEED;
}
/* Read attribute of update packet. This function is called from
bgp_update_receive() in bgp_packet.c. */
-bgp_attr_parse_ret_t
-bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
- struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
-{
- int ret;
- u_char flag = 0;
- u_char type = 0;
- bgp_size_t length;
- u_char *startp, *endp;
- u_char *attr_endp;
- u_char seen[BGP_ATTR_BITMAP_SIZE];
- /* we need the as4_path only until we have synthesized the as_path with it */
- /* same goes for as4_aggregator */
- struct aspath *as4_path = NULL;
- as_t as4_aggregator = 0;
- struct in_addr as4_aggregator_addr = { .s_addr = 0 };
-
- /* Initialize bitmap. */
- memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
-
- /* End pointer of BGP attribute. */
- endp = BGP_INPUT_PNT (peer) + size;
-
- /* Get attributes to the end of attribute length. */
- while (BGP_INPUT_PNT (peer) < endp)
- {
- /* Check remaining length check.*/
- if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
- {
- /* XXX warning: long int format, int arg (arg 5) */
- zlog_warn ("%s: error BGP attribute length %lu is smaller than min len",
- peer->host,
- (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
-
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return BGP_ATTR_PARSE_ERROR;
- }
-
- /* Fetch attribute flag and type. */
- startp = BGP_INPUT_PNT (peer);
- /* "The lower-order four bits of the Attribute Flags octet are
- unused. They MUST be zero when sent and MUST be ignored when
- received." */
- flag = 0xF0 & stream_getc (BGP_INPUT (peer));
- type = stream_getc (BGP_INPUT (peer));
-
- /* Check whether Extended-Length applies and is in bounds */
- if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
- && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
- {
- zlog_warn ("%s: Extended length set, but just %lu bytes of attr header",
- peer->host,
- (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
-
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- return BGP_ATTR_PARSE_ERROR;
- }
-
- /* Check extended attribue length bit. */
- if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
- length = stream_getw (BGP_INPUT (peer));
- else
- length = stream_getc (BGP_INPUT (peer));
-
- /* If any attribute appears more than once in the UPDATE
- message, then the Error Subcode is set to Malformed Attribute
- List. */
-
- if (CHECK_BITMAP (seen, type))
- {
- zlog_warn ("%s: error BGP attribute type %d appears twice in a message",
- peer->host, type);
+bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
+ bgp_size_t size, struct bgp_nlri *mp_update,
+ struct bgp_nlri *mp_withdraw)
+{
+ int ret;
+ u_char flag = 0;
+ u_char type = 0;
+ bgp_size_t length;
+ u_char *startp, *endp;
+ u_char *attr_endp;
+ u_char seen[BGP_ATTR_BITMAP_SIZE];
+ /* we need the as4_path only until we have synthesized the as_path with
+ * it */
+ /* same goes for as4_aggregator */
+ struct aspath *as4_path = NULL;
+ as_t as4_aggregator = 0;
+ struct in_addr as4_aggregator_addr = {.s_addr = 0};
+
+ /* Initialize bitmap. */
+ memset(seen, 0, BGP_ATTR_BITMAP_SIZE);
+
+ /* End pointer of BGP attribute. */
+ endp = BGP_INPUT_PNT(peer) + size;
+
+ /* Get attributes to the end of attribute length. */
+ while (BGP_INPUT_PNT(peer) < endp) {
+ /* Check remaining length check.*/
+ if (endp - BGP_INPUT_PNT(peer) < BGP_ATTR_MIN_LEN) {
+ /* XXX warning: long int format, int arg (arg 5) */
+ zlog_warn(
+ "%s: error BGP attribute length %lu is smaller than min len",
+ peer->host,
+ (unsigned long)(endp
+ - STREAM_PNT(BGP_INPUT(peer))));
+
+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ return BGP_ATTR_PARSE_ERROR;
+ }
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
- return BGP_ATTR_PARSE_ERROR;
- }
+ /* Fetch attribute flag and type. */
+ startp = BGP_INPUT_PNT(peer);
+ /* "The lower-order four bits of the Attribute Flags octet are
+ unused. They MUST be zero when sent and MUST be ignored when
+ received." */
+ flag = 0xF0 & stream_getc(BGP_INPUT(peer));
+ type = stream_getc(BGP_INPUT(peer));
+
+ /* Check whether Extended-Length applies and is in bounds */
+ if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN)
+ && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) {
+ zlog_warn(
+ "%s: Extended length set, but just %lu bytes of attr header",
+ peer->host,
+ (unsigned long)(endp
+ - STREAM_PNT(BGP_INPUT(peer))));
+
+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ return BGP_ATTR_PARSE_ERROR;
+ }
- /* Set type to bitmap to check duplicate attribute. `type' is
- unsigned char so it never overflow bitmap range. */
+ /* Check extended attribue length bit. */
+ if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN))
+ length = stream_getw(BGP_INPUT(peer));
+ else
+ length = stream_getc(BGP_INPUT(peer));
- SET_BITMAP (seen, type);
+ /* If any attribute appears more than once in the UPDATE
+ message, then the Error Subcode is set to Malformed Attribute
+ List. */
- /* Overflow check. */
- attr_endp = BGP_INPUT_PNT (peer) + length;
+ if (CHECK_BITMAP(seen, type)) {
+ zlog_warn(
+ "%s: error BGP attribute type %d appears twice in a message",
+ peer->host, type);
- if (attr_endp > endp)
- {
- zlog_warn ("%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp);
- bgp_notify_send_with_data (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
- startp, attr_endp - startp);
- return BGP_ATTR_PARSE_ERROR;
- }
-
- struct bgp_attr_parser_args attr_args = {
- .peer = peer,
- .length = length,
- .attr = attr,
- .type = type,
- .flags = flag,
- .startp = startp,
- .total = attr_endp - startp,
- };
-
-
- /* If any recognized attribute has Attribute Flags that conflict
- with the Attribute Type Code, then the Error Subcode is set to
- Attribute Flags Error. The Data field contains the erroneous
- attribute (type, length and value). */
- if (bgp_attr_flag_invalid (&attr_args))
- {
- bgp_attr_parse_ret_t ret;
- ret = bgp_attr_malformed (&attr_args,
- BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
- attr_args.total);
- if (ret == BGP_ATTR_PARSE_PROCEED)
- continue;
- return ret;
- }
-
- /* OK check attribute and store it's value. */
- switch (type)
- {
- case BGP_ATTR_ORIGIN:
- ret = bgp_attr_origin (&attr_args);
- break;
- case BGP_ATTR_AS_PATH:
- ret = bgp_attr_aspath (&attr_args);
- break;
- case BGP_ATTR_AS4_PATH:
- ret = bgp_attr_as4_path (&attr_args, &as4_path);
- break;
- case BGP_ATTR_NEXT_HOP:
- ret = bgp_attr_nexthop (&attr_args);
- break;
- case BGP_ATTR_MULTI_EXIT_DISC:
- ret = bgp_attr_med (&attr_args);
- break;
- case BGP_ATTR_LOCAL_PREF:
- ret = bgp_attr_local_pref (&attr_args);
- break;
- case BGP_ATTR_ATOMIC_AGGREGATE:
- ret = bgp_attr_atomic (&attr_args);
- break;
- case BGP_ATTR_AGGREGATOR:
- ret = bgp_attr_aggregator (&attr_args);
- break;
- case BGP_ATTR_AS4_AGGREGATOR:
- ret = bgp_attr_as4_aggregator (&attr_args,
- &as4_aggregator,
- &as4_aggregator_addr);
- break;
- case BGP_ATTR_COMMUNITIES:
- ret = bgp_attr_community (&attr_args);
- break;
- case BGP_ATTR_LARGE_COMMUNITIES:
- ret = bgp_attr_large_community (&attr_args);
- break;
- case BGP_ATTR_ORIGINATOR_ID:
- ret = bgp_attr_originator_id (&attr_args);
- break;
- case BGP_ATTR_CLUSTER_LIST:
- ret = bgp_attr_cluster_list (&attr_args);
- break;
- case BGP_ATTR_MP_REACH_NLRI:
- ret = bgp_mp_reach_parse (&attr_args, mp_update);
- break;
- case BGP_ATTR_MP_UNREACH_NLRI:
- ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
- break;
- case BGP_ATTR_EXT_COMMUNITIES:
- ret = bgp_attr_ext_communities (&attr_args);
- break;
+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
+ return BGP_ATTR_PARSE_ERROR;
+ }
+
+ /* Set type to bitmap to check duplicate attribute. `type' is
+ unsigned char so it never overflow bitmap range. */
+
+ SET_BITMAP(seen, type);
+
+ /* Overflow check. */
+ attr_endp = BGP_INPUT_PNT(peer) + length;
+
+ if (attr_endp > endp) {
+ zlog_warn(
+ "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p",
+ peer->host, type, length, size, attr_endp,
+ endp);
+ bgp_notify_send_with_data(
+ peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, startp,
+ attr_endp - startp);
+ return BGP_ATTR_PARSE_ERROR;
+ }
+
+ struct bgp_attr_parser_args attr_args = {
+ .peer = peer,
+ .length = length,
+ .attr = attr,
+ .type = type,
+ .flags = flag,
+ .startp = startp,
+ .total = attr_endp - startp,
+ };
+
+
+ /* If any recognized attribute has Attribute Flags that conflict
+ with the Attribute Type Code, then the Error Subcode is set
+ to
+ Attribute Flags Error. The Data field contains the erroneous
+ attribute (type, length and value). */
+ if (bgp_attr_flag_invalid(&attr_args)) {
+ bgp_attr_parse_ret_t ret;
+ ret = bgp_attr_malformed(
+ &attr_args, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+ attr_args.total);
+ if (ret == BGP_ATTR_PARSE_PROCEED)
+ continue;
+ return ret;
+ }
+
+ /* OK check attribute and store it's value. */
+ switch (type) {
+ case BGP_ATTR_ORIGIN:
+ ret = bgp_attr_origin(&attr_args);
+ break;
+ case BGP_ATTR_AS_PATH:
+ ret = bgp_attr_aspath(&attr_args);
+ break;
+ case BGP_ATTR_AS4_PATH:
+ ret = bgp_attr_as4_path(&attr_args, &as4_path);
+ break;
+ case BGP_ATTR_NEXT_HOP:
+ ret = bgp_attr_nexthop(&attr_args);
+ break;
+ case BGP_ATTR_MULTI_EXIT_DISC:
+ ret = bgp_attr_med(&attr_args);
+ break;
+ case BGP_ATTR_LOCAL_PREF:
+ ret = bgp_attr_local_pref(&attr_args);
+ break;
+ case BGP_ATTR_ATOMIC_AGGREGATE:
+ ret = bgp_attr_atomic(&attr_args);
+ break;
+ case BGP_ATTR_AGGREGATOR:
+ ret = bgp_attr_aggregator(&attr_args);
+ break;
+ case BGP_ATTR_AS4_AGGREGATOR:
+ ret = bgp_attr_as4_aggregator(&attr_args,
+ &as4_aggregator,
+ &as4_aggregator_addr);
+ break;
+ case BGP_ATTR_COMMUNITIES:
+ ret = bgp_attr_community(&attr_args);
+ break;
+ case BGP_ATTR_LARGE_COMMUNITIES:
+ ret = bgp_attr_large_community(&attr_args);
+ break;
+ case BGP_ATTR_ORIGINATOR_ID:
+ ret = bgp_attr_originator_id(&attr_args);
+ break;
+ case BGP_ATTR_CLUSTER_LIST:
+ ret = bgp_attr_cluster_list(&attr_args);
+ break;
+ case BGP_ATTR_MP_REACH_NLRI:
+ ret = bgp_mp_reach_parse(&attr_args, mp_update);
+ break;
+ case BGP_ATTR_MP_UNREACH_NLRI:
+ ret = bgp_mp_unreach_parse(&attr_args, mp_withdraw);
+ break;
+ case BGP_ATTR_EXT_COMMUNITIES:
+ ret = bgp_attr_ext_communities(&attr_args);
+ break;
#if ENABLE_BGP_VNC
- case BGP_ATTR_VNC:
+ case BGP_ATTR_VNC:
#endif
- case BGP_ATTR_ENCAP:
- ret = bgp_attr_encap (type, peer, length, attr, flag, startp);
- break;
- case BGP_ATTR_PREFIX_SID:
- ret = bgp_attr_prefix_sid (&attr_args, mp_update);
- break;
- default:
- ret = bgp_attr_unknown (&attr_args);
- break;
+ case BGP_ATTR_ENCAP:
+ ret = bgp_attr_encap(type, peer, length, attr, flag,
+ startp);
+ break;
+ case BGP_ATTR_PREFIX_SID:
+ ret = bgp_attr_prefix_sid(&attr_args, mp_update);
+ break;
+ default:
+ ret = bgp_attr_unknown(&attr_args);
+ break;
+ }
+
+ if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS) {
+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
+ ret = BGP_ATTR_PARSE_ERROR;
+ }
+
+ /* If hard error occured immediately return to the caller. */
+ if (ret == BGP_ATTR_PARSE_ERROR) {
+ zlog_warn("%s: Attribute %s, parse error", peer->host,
+ lookup_msg(attr_str, type, NULL));
+ if (as4_path)
+ aspath_unintern(&as4_path);
+ return ret;
+ }
+ if (ret == BGP_ATTR_PARSE_WITHDRAW) {
+
+ zlog_warn(
+ "%s: Attribute %s, parse error - treating as withdrawal",
+ peer->host, lookup_msg(attr_str, type, NULL));
+ if (as4_path)
+ aspath_unintern(&as4_path);
+ return ret;
+ }
+
+ /* Check the fetched length. */
+ if (BGP_INPUT_PNT(peer) != attr_endp) {
+ zlog_warn("%s: BGP attribute %s, fetch error",
+ peer->host, lookup_msg(attr_str, type, NULL));
+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ if (as4_path)
+ aspath_unintern(&as4_path);
+ return BGP_ATTR_PARSE_ERROR;
+ }
}
-
- if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS)
- {
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
- ret = BGP_ATTR_PARSE_ERROR;
- }
-
- /* If hard error occured immediately return to the caller. */
- if (ret == BGP_ATTR_PARSE_ERROR)
- {
- zlog_warn ("%s: Attribute %s, parse error",
- peer->host,
- lookup_msg(attr_str, type, NULL));
- if (as4_path)
- aspath_unintern (&as4_path);
- return ret;
- }
- if (ret == BGP_ATTR_PARSE_WITHDRAW)
- {
-
- zlog_warn ("%s: Attribute %s, parse error - treating as withdrawal",
- peer->host,
- lookup_msg(attr_str, type, NULL));
- if (as4_path)
- aspath_unintern (&as4_path);
- return ret;
- }
-
- /* Check the fetched length. */
- if (BGP_INPUT_PNT (peer) != attr_endp)
+
+ /* Check final read pointer is same as end pointer. */
+ if (BGP_INPUT_PNT(peer) != endp) {
+ zlog_warn("%s: BGP attribute %s, length mismatch", peer->host,
+ lookup_msg(attr_str, type, NULL));
+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
+ if (as4_path)
+ aspath_unintern(&as4_path);
+ return BGP_ATTR_PARSE_ERROR;
+ }
+
+ /* Check all mandatory well-known attributes are present */
{
- zlog_warn ("%s: BGP attribute %s, fetch error",
- peer->host, lookup_msg(attr_str, type, NULL));
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- if (as4_path)
- aspath_unintern (&as4_path);
- return BGP_ATTR_PARSE_ERROR;
- }
- }
-
- /* Check final read pointer is same as end pointer. */
- if (BGP_INPUT_PNT (peer) != endp)
- {
- zlog_warn ("%s: BGP attribute %s, length mismatch",
- peer->host, lookup_msg(attr_str, type, NULL));
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
- if (as4_path)
- aspath_unintern (&as4_path);
- return BGP_ATTR_PARSE_ERROR;
- }
-
- /* Check all mandatory well-known attributes are present */
- {
- bgp_attr_parse_ret_t ret;
- if ((ret = bgp_attr_check (peer, attr)) < 0)
- {
- if (as4_path)
- aspath_unintern (&as4_path);
- return ret;
- }
- }
-
- /*
- * At this place we can see whether we got AS4_PATH and/or
- * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
- * We can not do this before we've read all attributes because
- * the as4 handling does not say whether AS4_PATH has to be sent
- * after AS_PATH or not - and when AS4_AGGREGATOR will be send
- * in relationship to AGGREGATOR.
- * So, to be defensive, we are not relying on any order and read
- * all attributes first, including these 32bit ones, and now,
- * afterwards, we look what and if something is to be done for as4.
- *
- * It is possible to not have AS_PATH, e.g. GR EoR and sole
- * MP_UNREACH_NLRI.
- */
- /* actually... this doesn't ever return failure currently, but
- * better safe than sorry */
- if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))
- && bgp_attr_munge_as4_attrs (peer, attr, as4_path,
- as4_aggregator, &as4_aggregator_addr))
- {
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_MAL_ATTR);
- if (as4_path)
- aspath_unintern (&as4_path);
- return BGP_ATTR_PARSE_ERROR;
- }
-
- /* At this stage, we have done all fiddling with as4, and the
- * resulting info is in attr->aggregator resp. attr->aspath
- * so we can chuck as4_aggregator and as4_path alltogether in
- * order to save memory
- */
- if (as4_path)
- {
- aspath_unintern (&as4_path); /* unintern - it is in the hash */
- /* The flag that we got this is still there, but that does not
- * do any trouble
- */
- }
- /*
- * The "rest" of the code does nothing with as4_aggregator.
- * there is no memory attached specifically which is not part
- * of the attr.
- * so ignoring just means do nothing.
- */
- /*
- * Finally do the checks on the aspath we did not do yet
- * because we waited for a potentially synthesized aspath.
- */
- if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
- {
- ret = bgp_attr_aspath_check (peer, attr);
- if (ret != BGP_ATTR_PARSE_PROCEED)
- return ret;
- }
- /* Finally intern unknown attribute. */
- if (attr->transit)
- attr->transit = transit_intern (attr->transit);
- if (attr->encap_subtlvs)
- attr->encap_subtlvs = encap_intern (attr->encap_subtlvs, ENCAP_SUBTLV_TYPE);
+ bgp_attr_parse_ret_t ret;
+ if ((ret = bgp_attr_check(peer, attr)) < 0) {
+ if (as4_path)
+ aspath_unintern(&as4_path);
+ return ret;
+ }
+ }
+
+ /*
+ * At this place we can see whether we got AS4_PATH and/or
+ * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
+ * We can not do this before we've read all attributes because
+ * the as4 handling does not say whether AS4_PATH has to be sent
+ * after AS_PATH or not - and when AS4_AGGREGATOR will be send
+ * in relationship to AGGREGATOR.
+ * So, to be defensive, we are not relying on any order and read
+ * all attributes first, including these 32bit ones, and now,
+ * afterwards, we look what and if something is to be done for as4.
+ *
+ * It is possible to not have AS_PATH, e.g. GR EoR and sole
+ * MP_UNREACH_NLRI.
+ */
+ /* actually... this doesn't ever return failure currently, but
+ * better safe than sorry */
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))
+ && bgp_attr_munge_as4_attrs(peer, attr, as4_path, as4_aggregator,
+ &as4_aggregator_addr)) {
+ bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
+ BGP_NOTIFY_UPDATE_MAL_ATTR);
+ if (as4_path)
+ aspath_unintern(&as4_path);
+ return BGP_ATTR_PARSE_ERROR;
+ }
+
+ /* At this stage, we have done all fiddling with as4, and the
+ * resulting info is in attr->aggregator resp. attr->aspath
+ * so we can chuck as4_aggregator and as4_path alltogether in
+ * order to save memory
+ */
+ if (as4_path) {
+ aspath_unintern(&as4_path); /* unintern - it is in the hash */
+ /* The flag that we got this is still there, but that does not
+ * do any trouble
+ */
+ }
+ /*
+ * The "rest" of the code does nothing with as4_aggregator.
+ * there is no memory attached specifically which is not part
+ * of the attr.
+ * so ignoring just means do nothing.
+ */
+ /*
+ * Finally do the checks on the aspath we did not do yet
+ * because we waited for a potentially synthesized aspath.
+ */
+ if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) {
+ ret = bgp_attr_aspath_check(peer, attr);
+ if (ret != BGP_ATTR_PARSE_PROCEED)
+ return ret;
+ }
+ /* Finally intern unknown attribute. */
+ if (attr->transit)
+ attr->transit = transit_intern(attr->transit);
+ if (attr->encap_subtlvs)
+ attr->encap_subtlvs =
+ encap_intern(attr->encap_subtlvs, ENCAP_SUBTLV_TYPE);
#if ENABLE_BGP_VNC
- if (attr->vnc_subtlvs)
- attr->vnc_subtlvs = encap_intern (attr->vnc_subtlvs, VNC_SUBTLV_TYPE);
+ if (attr->vnc_subtlvs)
+ attr->vnc_subtlvs =
+ encap_intern(attr->vnc_subtlvs, VNC_SUBTLV_TYPE);
#endif
- return BGP_ATTR_PARSE_PROCEED;
-}
-
-size_t
-bgp_packet_mpattr_start (struct stream *s, struct peer *peer,
- afi_t afi, safi_t safi,
- struct bpacket_attr_vec_arr *vecarr,
- struct attr *attr)
-{
- size_t sizep;
- iana_afi_t pkt_afi;
- safi_t pkt_safi;
- afi_t nh_afi;
-
- /* Set extended bit always to encode the attribute length as 2 bytes */
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
- sizep = stream_get_endp (s);
- stream_putw (s, 0); /* Marker: Attribute length. */
-
-
- /* Convert AFI, SAFI to values for packet. */
- bgp_map_afi_safi_int2iana (afi, safi, &pkt_afi, &pkt_safi);
-
- stream_putw (s, pkt_afi); /* AFI */
- stream_putc (s, pkt_safi); /* SAFI */
-
- /* Nexthop AFI */
- if (afi == AFI_IP && safi == SAFI_UNICAST)
- {
- nh_afi = peer_cap_enhe (peer, afi, safi) ? AFI_IP6 : AFI_IP;
- }
- else if (safi == SAFI_LABELED_UNICAST)
- nh_afi = afi;
- else
- nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
-
- /* Nexthop */
- bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
- switch (nh_afi)
- {
- case AFI_IP:
- switch (safi)
- {
- case SAFI_UNICAST:
- case SAFI_MULTICAST:
- case SAFI_LABELED_UNICAST:
- stream_putc (s, 4);
- stream_put_ipv4 (s, attr->nexthop.s_addr);
- break;
- case SAFI_MPLS_VPN:
- stream_putc (s, 12);
- stream_putl (s, 0); /* RD = 0, per RFC */
- stream_putl (s, 0);
- stream_put (s, &attr->mp_nexthop_global_in, 4);
- break;
- case SAFI_ENCAP:
- case SAFI_EVPN:
- stream_putc (s, 4);
- stream_put (s, &attr->mp_nexthop_global_in, 4);
- break;
+ return BGP_ATTR_PARSE_PROCEED;
+}
+
+size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
+ safi_t safi, struct bpacket_attr_vec_arr *vecarr,
+ struct attr *attr)
+{
+ size_t sizep;
+ iana_afi_t pkt_afi;
+ safi_t pkt_safi;
+ afi_t nh_afi;
+
+ /* Set extended bit always to encode the attribute length as 2 bytes */
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
+ sizep = stream_get_endp(s);
+ stream_putw(s, 0); /* Marker: Attribute length. */
+
+
+ /* Convert AFI, SAFI to values for packet. */
+ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
+
+ stream_putw(s, pkt_afi); /* AFI */
+ stream_putc(s, pkt_safi); /* SAFI */
+
+ /* Nexthop AFI */
+ if (afi == AFI_IP && safi == SAFI_UNICAST) {
+ nh_afi = peer_cap_enhe(peer, afi, safi) ? AFI_IP6 : AFI_IP;
+ } else if (safi == SAFI_LABELED_UNICAST)
+ nh_afi = afi;
+ else
+ nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
+
+ /* Nexthop */
+ bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s, attr);
+ switch (nh_afi) {
+ case AFI_IP:
+ switch (safi) {
+ case SAFI_UNICAST:
+ case SAFI_MULTICAST:
+ case SAFI_LABELED_UNICAST:
+ stream_putc(s, 4);
+ stream_put_ipv4(s, attr->nexthop.s_addr);
+ break;
+ case SAFI_MPLS_VPN:
+ stream_putc(s, 12);
+ stream_putl(s, 0); /* RD = 0, per RFC */
+ stream_putl(s, 0);
+ stream_put(s, &attr->mp_nexthop_global_in, 4);
+ break;
+ case SAFI_ENCAP:
+ case SAFI_EVPN:
+ stream_putc(s, 4);
+ stream_put(s, &attr->mp_nexthop_global_in, 4);
+ break;
+ default:
+ break;
+ }
+ break;
+ case AFI_IP6:
+ switch (safi) {
+ case SAFI_UNICAST:
+ case SAFI_MULTICAST:
+ case SAFI_LABELED_UNICAST:
+ case SAFI_EVPN: {
+ if (attr->mp_nexthop_len
+ == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
+ stream_putc(s,
+ BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL);
+ stream_put(s, &attr->mp_nexthop_global,
+ IPV6_MAX_BYTELEN);
+ stream_put(s, &attr->mp_nexthop_local,
+ IPV6_MAX_BYTELEN);
+ } else {
+ stream_putc(s, IPV6_MAX_BYTELEN);
+ stream_put(s, &attr->mp_nexthop_global,
+ IPV6_MAX_BYTELEN);
+ }
+ } break;
+ case SAFI_MPLS_VPN: {
+ if (attr->mp_nexthop_len
+ == BGP_ATTR_NHLEN_IPV6_GLOBAL) {
+ stream_putc(s, 24);
+ stream_putl(s, 0); /* RD = 0, per RFC */
+ stream_putl(s, 0);
+ stream_put(s, &attr->mp_nexthop_global,
+ IPV6_MAX_BYTELEN);
+ } else if (attr->mp_nexthop_len
+ == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
+ stream_putc(s, 48);
+ stream_putl(s, 0); /* RD = 0, per RFC */
+ stream_putl(s, 0);
+ stream_put(s, &attr->mp_nexthop_global,
+ IPV6_MAX_BYTELEN);
+ stream_putl(s, 0); /* RD = 0, per RFC */
+ stream_putl(s, 0);
+ stream_put(s, &attr->mp_nexthop_local,
+ IPV6_MAX_BYTELEN);
+ }
+ } break;
+ case SAFI_ENCAP:
+ stream_putc(s, IPV6_MAX_BYTELEN);
+ stream_put(s, &attr->mp_nexthop_global,
+ IPV6_MAX_BYTELEN);
+ break;
+ default:
+ break;
+ }
+ break;
default:
- break;
- }
- break;
- case AFI_IP6:
- switch (safi)
- {
- case SAFI_UNICAST:
- case SAFI_MULTICAST:
- case SAFI_LABELED_UNICAST:
- case SAFI_EVPN:
- {
- if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
- stream_putc (s, BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL);
- stream_put (s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN);
- stream_put (s, &attr->mp_nexthop_local, IPV6_MAX_BYTELEN);
- } else {
- stream_putc (s, IPV6_MAX_BYTELEN);
- stream_put (s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN);
- }
- }
- break;
- case SAFI_MPLS_VPN:
- {
- if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) {
- stream_putc (s, 24);
- stream_putl (s, 0); /* RD = 0, per RFC */
- stream_putl (s, 0);
- stream_put (s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN);
- } else if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
- stream_putc (s, 48);
- stream_putl (s, 0); /* RD = 0, per RFC */
- stream_putl (s, 0);
- stream_put (s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN);
- stream_putl (s, 0); /* RD = 0, per RFC */
- stream_putl (s, 0);
- stream_put (s, &attr->mp_nexthop_local, IPV6_MAX_BYTELEN);
- }
- }
- break;
- case SAFI_ENCAP:
- stream_putc (s, IPV6_MAX_BYTELEN);
- stream_put (s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN);
- break;
- default:
- break;
- }
- break;
- default:
- zlog_err ("Bad nexthop when sening to %s, AFI %u SAFI %u nhlen %d",
- peer->host, afi, safi, attr->mp_nexthop_len);
- break;
- }
-
- /* SNPA */
- stream_putc (s, 0);
- return sizep;
-}
-
-void
-bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
- struct prefix *p, struct prefix_rd *prd,
- mpls_label_t *label, int addpath_encode,
- u_int32_t addpath_tx_id, struct attr *attr)
-{
- if (safi == SAFI_MPLS_VPN)
- {
- if (addpath_encode)
- stream_putl(s, addpath_tx_id);
- /* Label, RD, Prefix write. */
- stream_putc (s, p->prefixlen + 88);
- stream_put (s, label, BGP_LABEL_BYTES);
- stream_put (s, prd->val, 8);
- stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
- }
- else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
- {
- /* EVPN prefix - contents depend on type */
- bgp_evpn_encode_prefix (s, p, prd, label, attr,
- addpath_encode, addpath_tx_id);
- }
- else if (safi == SAFI_LABELED_UNICAST)
- {
- /* Prefix write with label. */
- stream_put_labeled_prefix(s, p, label);
- }
- else
- stream_put_prefix_addpath (s, p, addpath_encode, addpath_tx_id);
-}
-
-size_t
-bgp_packet_mpattr_prefix_size (afi_t afi, safi_t safi, struct prefix *p)
-{
- int size = PSIZE (p->prefixlen);
- if (safi == SAFI_MPLS_VPN)
- size += 88;
- else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
- size += 232; // TODO: Maximum possible for type-2, type-3 and type-5
- return size;
+ zlog_err(
+ "Bad nexthop when sening to %s, AFI %u SAFI %u nhlen %d",
+ peer->host, afi, safi, attr->mp_nexthop_len);
+ break;
+ }
+
+ /* SNPA */
+ stream_putc(s, 0);
+ return sizep;
+}
+
+void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
+ struct prefix *p, struct prefix_rd *prd,
+ mpls_label_t *label, int addpath_encode,
+ u_int32_t addpath_tx_id, struct attr *attr)
+{
+ if (safi == SAFI_MPLS_VPN) {
+ if (addpath_encode)
+ stream_putl(s, addpath_tx_id);
+ /* Label, RD, Prefix write. */
+ stream_putc(s, p->prefixlen + 88);
+ stream_put(s, label, BGP_LABEL_BYTES);
+ stream_put(s, prd->val, 8);
+ stream_put(s, &p->u.prefix, PSIZE(p->prefixlen));
+ } else if (afi == AFI_L2VPN && safi == SAFI_EVPN) {
+ /* EVPN prefix - contents depend on type */
+ bgp_evpn_encode_prefix(s, p, prd, label, attr, addpath_encode,
+ addpath_tx_id);
+ } else if (safi == SAFI_LABELED_UNICAST) {
+ /* Prefix write with label. */
+ stream_put_labeled_prefix(s, p, label);
+ } else
+ stream_put_prefix_addpath(s, p, addpath_encode, addpath_tx_id);
+}
+
+size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, struct prefix *p)
+{
+ int size = PSIZE(p->prefixlen);
+ if (safi == SAFI_MPLS_VPN)
+ size += 88;
+ else if (afi == AFI_L2VPN && safi == SAFI_EVPN)
+ size += 232; // TODO: Maximum possible for type-2, type-3 and
+ // type-5
+ return size;
}
/*
* Encodes the tunnel encapsulation attribute,
- * and with ENABLE_BGP_VNC the VNC attribute which uses
+ * and with ENABLE_BGP_VNC the VNC attribute which uses
* almost the same TLV format
*/
-static void
-bgp_packet_mpattr_tea(
- struct bgp *bgp,
- struct peer *peer,
- struct stream *s,
- struct attr *attr,
- uint8_t attrtype)
-{
- unsigned int attrlenfield = 0;
- unsigned int attrhdrlen = 0;
- struct bgp_attr_encap_subtlv *subtlvs;
- struct bgp_attr_encap_subtlv *st;
- const char *attrname;
-
- if (!attr ||
- (attrtype == BGP_ATTR_ENCAP &&
- (!attr->encap_tunneltype ||
- attr->encap_tunneltype == BGP_ENCAP_TYPE_MPLS)))
- return;
-
- switch (attrtype) {
+static void bgp_packet_mpattr_tea(struct bgp *bgp, struct peer *peer,
+ struct stream *s, struct attr *attr,
+ uint8_t attrtype)
+{
+ unsigned int attrlenfield = 0;
+ unsigned int attrhdrlen = 0;
+ struct bgp_attr_encap_subtlv *subtlvs;
+ struct bgp_attr_encap_subtlv *st;
+ const char *attrname;
+
+ if (!attr || (attrtype == BGP_ATTR_ENCAP
+ && (!attr->encap_tunneltype
+ || attr->encap_tunneltype == BGP_ENCAP_TYPE_MPLS)))
+ return;
+
+ switch (attrtype) {
case BGP_ATTR_ENCAP:
- attrname = "Tunnel Encap";
- subtlvs = attr->encap_subtlvs;
- if (subtlvs == NULL) /* nothing to do */
- return;
- /*
- * The tunnel encap attr has an "outer" tlv.
- * T = tunneltype,
- * L = total length of subtlvs,
- * V = concatenated subtlvs.
- */
- attrlenfield = 2 + 2; /* T + L */
- attrhdrlen = 1 + 1; /* subTLV T + L */
- break;
+ attrname = "Tunnel Encap";
+ subtlvs = attr->encap_subtlvs;
+ if (subtlvs == NULL) /* nothing to do */
+ return;
+ /*
+ * The tunnel encap attr has an "outer" tlv.
+ * T = tunneltype,
+ * L = total length of subtlvs,
+ * V = concatenated subtlvs.
+ */
+ attrlenfield = 2 + 2; /* T + L */
+ attrhdrlen = 1 + 1; /* subTLV T + L */
+ break;
#if ENABLE_BGP_VNC
case BGP_ATTR_VNC:
- attrname = "VNC";
- subtlvs = attr->vnc_subtlvs;
- if (subtlvs == NULL) /* nothing to do */
- return;
- attrlenfield = 0; /* no outer T + L */
- attrhdrlen = 2 + 2; /* subTLV T + L */
- break;
+ attrname = "VNC";
+ subtlvs = attr->vnc_subtlvs;
+ if (subtlvs == NULL) /* nothing to do */
+ return;
+ attrlenfield = 0; /* no outer T + L */
+ attrhdrlen = 2 + 2; /* subTLV T + L */
+ break;
#endif
default:
- assert(0);
- }
-
- /* compute attr length */
- for (st = subtlvs; st; st = st->next) {
- attrlenfield += (attrhdrlen + st->length);
- }
-
- if (attrlenfield > 0xffff) {
- zlog_info ("%s attribute is too long (length=%d), can't send it",
- attrname,
- attrlenfield);
- return;
- }
-
- if (attrlenfield > 0xff) {
- /* 2-octet length field */
- stream_putc (s,
- BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, attrtype);
- stream_putw (s, attrlenfield & 0xffff);
- } else {
- /* 1-octet length field */
- stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL);
- stream_putc (s, attrtype);
- stream_putc (s, attrlenfield & 0xff);
- }
-
- if (attrtype == BGP_ATTR_ENCAP) {
- /* write outer T+L */
- stream_putw(s, attr->encap_tunneltype);
- stream_putw(s, attrlenfield - 4);
- }
-
- /* write each sub-tlv */
- for (st = subtlvs; st; st = st->next) {
- if (attrtype == BGP_ATTR_ENCAP) {
- stream_putc (s, st->type);
- stream_putc (s, st->length);
+ assert(0);
+ }
+
+ /* compute attr length */
+ for (st = subtlvs; st; st = st->next) {
+ attrlenfield += (attrhdrlen + st->length);
+ }
+
+ if (attrlenfield > 0xffff) {
+ zlog_info("%s attribute is too long (length=%d), can't send it",
+ attrname, attrlenfield);
+ return;
+ }
+
+ if (attrlenfield > 0xff) {
+ /* 2-octet length field */
+ stream_putc(s,
+ BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, attrtype);
+ stream_putw(s, attrlenfield & 0xffff);
+ } else {
+ /* 1-octet length field */
+ stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL);
+ stream_putc(s, attrtype);
+ stream_putc(s, attrlenfield & 0xff);
+ }
+
+ if (attrtype == BGP_ATTR_ENCAP) {
+ /* write outer T+L */
+ stream_putw(s, attr->encap_tunneltype);
+ stream_putw(s, attrlenfield - 4);
+ }
+
+ /* write each sub-tlv */
+ for (st = subtlvs; st; st = st->next) {
+ if (attrtype == BGP_ATTR_ENCAP) {
+ stream_putc(s, st->type);
+ stream_putc(s, st->length);
#if ENABLE_BGP_VNC
- } else {
- stream_putw (s, st->type);
- stream_putw (s, st->length);
+ } else {
+ stream_putw(s, st->type);
+ stream_putw(s, st->length);
#endif
- }
- stream_put (s, st->value, st->length);
- }
+ }
+ stream_put(s, st->value, st->length);
+ }
}
-void
-bgp_packet_mpattr_end (struct stream *s, size_t sizep)
+void bgp_packet_mpattr_end(struct stream *s, size_t sizep)
{
- /* Set MP attribute length. Don't count the (2) bytes used to encode
- the attr length */
- stream_putw_at (s, sizep, (stream_get_endp (s) - sizep) - 2);
+ /* Set MP attribute length. Don't count the (2) bytes used to encode
+ the attr length */
+ stream_putw_at(s, sizep, (stream_get_endp(s) - sizep) - 2);
}
/* Make attribute packet. */
-bgp_size_t
-bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
- struct stream *s, struct attr *attr,
- struct bpacket_attr_vec_arr *vecarr,
- struct prefix *p, afi_t afi, safi_t safi,
- struct peer *from, struct prefix_rd *prd, mpls_label_t *label,
- int addpath_encode,
- u_int32_t addpath_tx_id)
-{
- size_t cp;
- size_t aspath_sizep;
- struct aspath *aspath;
- int send_as4_path = 0;
- int send_as4_aggregator = 0;
- int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
-
- if (! bgp)
- bgp = peer->bgp;
-
- /* Remember current pointer. */
- cp = stream_get_endp (s);
-
- if (p && !((afi == AFI_IP && safi == SAFI_UNICAST) &&
- !peer_cap_enhe(peer, afi, safi)))
- {
- size_t mpattrlen_pos = 0;
-
- mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi, vecarr, attr);
- bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
- addpath_encode, addpath_tx_id, attr);
- bgp_packet_mpattr_end(s, mpattrlen_pos);
- }
-
- /* Origin attribute. */
- stream_putc (s, BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_ORIGIN);
- stream_putc (s, 1);
- stream_putc (s, attr->origin);
-
- /* AS path attribute. */
-
- /* If remote-peer is EBGP */
- if (peer->sort == BGP_PEER_EBGP
- && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
- || attr->aspath->segments == NULL)
- && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
- {
- aspath = aspath_dup (attr->aspath);
-
- /* Even though we may not be configured for confederations we may have
- * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
- aspath = aspath_delete_confed_seq (aspath);
-
- if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
- {
- /* Stuff our path CONFED_ID on the front */
- aspath = aspath_add_seq (aspath, bgp->confed_id);
+bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
+ struct stream *s, struct attr *attr,
+ struct bpacket_attr_vec_arr *vecarr,
+ struct prefix *p, afi_t afi, safi_t safi,
+ struct peer *from, struct prefix_rd *prd,
+ mpls_label_t *label, int addpath_encode,
+ u_int32_t addpath_tx_id)
+{
+ size_t cp;
+ size_t aspath_sizep;
+ struct aspath *aspath;
+ int send_as4_path = 0;
+ int send_as4_aggregator = 0;
+ int use32bit = (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
+
+ if (!bgp)
+ bgp = peer->bgp;
+
+ /* Remember current pointer. */
+ cp = stream_get_endp(s);
+
+ if (p
+ && !((afi == AFI_IP && safi == SAFI_UNICAST)
+ && !peer_cap_enhe(peer, afi, safi))) {
+ size_t mpattrlen_pos = 0;
+
+ mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi,
+ vecarr, attr);
+ bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
+ addpath_encode, addpath_tx_id, attr);
+ bgp_packet_mpattr_end(s, mpattrlen_pos);
}
- else
- {
- if (peer->change_local_as) {
- /* If replace-as is specified, we only use the change_local_as when
- advertising routes. */
- if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) {
- aspath = aspath_add_seq (aspath, peer->local_as);
- }
- aspath = aspath_add_seq (aspath, peer->change_local_as);
- } else {
- aspath = aspath_add_seq (aspath, peer->local_as);
- }
- }
- }
- else if (peer->sort == BGP_PEER_CONFED)
- {
- /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
- aspath = aspath_dup (attr->aspath);
- aspath = aspath_add_confed_seq (aspath, peer->local_as);
- }
- else
- aspath = attr->aspath;
-
- /* If peer is not AS4 capable, then:
- * - send the created AS_PATH out as AS4_PATH (optional, transitive),
- * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
- * types are in it (i.e. exclude them if they are there)
- * AND do this only if there is at least one asnum > 65535 in the path!
- * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
- * all ASnums > 65535 to BGP_AS_TRANS
- */
-
- stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_AS_PATH);
- aspath_sizep = stream_get_endp (s);
- stream_putw (s, 0);
- stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
-
- /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
- * in the path
- */
- if (!use32bit && aspath_has_as4 (aspath))
- send_as4_path = 1; /* we'll do this later, at the correct place */
-
- /* Nexthop attribute. */
- if (afi == AFI_IP && safi == SAFI_UNICAST && !peer_cap_enhe(peer, afi, safi))
- {
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))
- {
- stream_putc (s, BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_NEXT_HOP);
- bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
- stream_putc (s, 4);
- stream_put_ipv4 (s, attr->nexthop.s_addr);
- }
- else if (peer_cap_enhe(from, afi, safi))
- {
- /*
- * Likely this is the case when an IPv4 prefix was received with
- * Extended Next-hop capability and now being advertised to
- * non-ENHE peers.
- * Setting the mandatory (ipv4) next-hop attribute here to enable
- * implicit next-hop self with correct (ipv4 address family).
- */
- stream_putc (s, BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_NEXT_HOP);
- bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, NULL);
- stream_putc (s, 4);
- stream_put_ipv4 (s, 0);
- }
- }
-
- /* MED attribute. */
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC) ||
- bgp->maxmed_active)
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
- stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
- stream_putc (s, 4);
- stream_putl (s, (bgp->maxmed_active ? bgp->maxmed_value : attr->med));
- }
-
- /* Local preference. */
- if (peer->sort == BGP_PEER_IBGP ||
- peer->sort == BGP_PEER_CONFED)
- {
- stream_putc (s, BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_LOCAL_PREF);
- stream_putc (s, 4);
- stream_putl (s, attr->local_pref);
- }
-
- /* Atomic aggregate. */
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
- {
- stream_putc (s, BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
- stream_putc (s, 0);
- }
-
- /* Aggregator. */
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
- {
- /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_AGGREGATOR);
-
- if (use32bit)
- {
- /* AS4 capable peer */
- stream_putc (s, 8);
- stream_putl (s, attr->aggregator_as);
- }
- else
- {
- /* 2-byte AS peer */
- stream_putc (s, 6);
-
- /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
- if ( attr->aggregator_as > 65535 )
- {
- stream_putw (s, BGP_AS_TRANS);
-
- /* we have to send AS4_AGGREGATOR, too.
- * we'll do that later in order to send attributes in ascending
- * order.
- */
- send_as4_aggregator = 1;
- }
- else
- stream_putw (s, (u_int16_t) attr->aggregator_as);
- }
- stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
- }
-
- /* Community attribute. */
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
- && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
- {
- if (attr->community->size * 4 > 255)
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_COMMUNITIES);
- stream_putw (s, attr->community->size * 4);
+
+ /* Origin attribute. */
+ stream_putc(s, BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_ORIGIN);
+ stream_putc(s, 1);
+ stream_putc(s, attr->origin);
+
+ /* AS path attribute. */
+
+ /* If remote-peer is EBGP */
+ if (peer->sort == BGP_PEER_EBGP
+ && (!CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_AS_PATH_UNCHANGED)
+ || attr->aspath->segments == NULL)
+ && (!CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_RSERVER_CLIENT))) {
+ aspath = aspath_dup(attr->aspath);
+
+ /* Even though we may not be configured for confederations we
+ * may have
+ * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
+ aspath = aspath_delete_confed_seq(aspath);
+
+ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) {
+ /* Stuff our path CONFED_ID on the front */
+ aspath = aspath_add_seq(aspath, bgp->confed_id);
+ } else {
+ if (peer->change_local_as) {
+ /* If replace-as is specified, we only use the
+ change_local_as when
+ advertising routes. */
+ if (!CHECK_FLAG(
+ peer->flags,
+ PEER_FLAG_LOCAL_AS_REPLACE_AS)) {
+ aspath = aspath_add_seq(aspath,
+ peer->local_as);
+ }
+ aspath = aspath_add_seq(aspath,
+ peer->change_local_as);
+ } else {
+ aspath = aspath_add_seq(aspath, peer->local_as);
+ }
+ }
+ } else if (peer->sort == BGP_PEER_CONFED) {
+ /* A confed member, so we need to do the AS_CONFED_SEQUENCE
+ * thing */
+ aspath = aspath_dup(attr->aspath);
+ aspath = aspath_add_confed_seq(aspath, peer->local_as);
+ } else
+ aspath = attr->aspath;
+
+ /* If peer is not AS4 capable, then:
+ * - send the created AS_PATH out as AS4_PATH (optional, transitive),
+ * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path
+ * segment
+ * types are in it (i.e. exclude them if they are there)
+ * AND do this only if there is at least one asnum > 65535 in the
+ * path!
+ * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and
+ * change
+ * all ASnums > 65535 to BGP_AS_TRANS
+ */
+
+ stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_AS_PATH);
+ aspath_sizep = stream_get_endp(s);
+ stream_putw(s, 0);
+ stream_putw_at(s, aspath_sizep, aspath_put(s, aspath, use32bit));
+
+ /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
+ * in the path
+ */
+ if (!use32bit && aspath_has_as4(aspath))
+ send_as4_path =
+ 1; /* we'll do this later, at the correct place */
+
+ /* Nexthop attribute. */
+ if (afi == AFI_IP && safi == SAFI_UNICAST
+ && !peer_cap_enhe(peer, afi, safi)) {
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
+ stream_putc(s, BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_NEXT_HOP);
+ bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s,
+ attr);
+ stream_putc(s, 4);
+ stream_put_ipv4(s, attr->nexthop.s_addr);
+ } else if (peer_cap_enhe(from, afi, safi)) {
+ /*
+ * Likely this is the case when an IPv4 prefix was
+ * received with
+ * Extended Next-hop capability and now being advertised
+ * to
+ * non-ENHE peers.
+ * Setting the mandatory (ipv4) next-hop attribute here
+ * to enable
+ * implicit next-hop self with correct (ipv4 address
+ * family).
+ */
+ stream_putc(s, BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_NEXT_HOP);
+ bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s,
+ NULL);
+ stream_putc(s, 4);
+ stream_put_ipv4(s, 0);
+ }
}
- else
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_COMMUNITIES);
- stream_putc (s, attr->community->size * 4);
- }
- stream_put (s, attr->community->val, attr->community->size * 4);
- }
-
- /*
- * Large Community attribute.
- */
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)
- && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)))
- {
- if (attr->lcommunity->size * 12 > 255)
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
- stream_putw (s, attr->lcommunity->size * 12);
- }
- else
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
- stream_putc (s, attr->lcommunity->size * 12);
- }
- stream_put (s, attr->lcommunity->val, attr->lcommunity->size * 12);
- }
-
- /* Route Reflector. */
- if (peer->sort == BGP_PEER_IBGP
- && from
- && from->sort == BGP_PEER_IBGP)
- {
- /* Originator ID. */
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
- stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
- stream_putc (s, 4);
-
- if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
- stream_put_in_addr (s, &attr->originator_id);
- else
- stream_put_in_addr (s, &from->remote_id);
-
- /* Cluster list. */
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
- stream_putc (s, BGP_ATTR_CLUSTER_LIST);
-
- if (attr->cluster)
- {
- stream_putc (s, attr->cluster->length + 4);
- /* If this peer configuration's parent BGP has cluster_id. */
- if (bgp->config & BGP_CONFIG_CLUSTER_ID)
- stream_put_in_addr (s, &bgp->cluster_id);
- else
- stream_put_in_addr (s, &bgp->router_id);
- stream_put (s, attr->cluster->list,
- attr->cluster->length);
- }
- else
- {
- stream_putc (s, 4);
- /* If this peer configuration's parent BGP has cluster_id. */
- if (bgp->config & BGP_CONFIG_CLUSTER_ID)
- stream_put_in_addr (s, &bgp->cluster_id);
- else
- stream_put_in_addr (s, &bgp->router_id);
- }
- }
-
- /* Extended Communities attribute. */
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
- && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
- {
- if (peer->sort == BGP_PEER_IBGP
- || peer->sort == BGP_PEER_CONFED)
- {
- if (attr->ecommunity->size * 8 > 255)
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
- stream_putw (s, attr->ecommunity->size * 8);
- }
- else
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
- stream_putc (s, attr->ecommunity->size * 8);
- }
- stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8);
- }
- else
- {
- u_int8_t *pnt;
- int tbit;
- int ecom_tr_size = 0;
- int i;
-
- for (i = 0; i < attr->ecommunity->size; i++)
- {
- pnt = attr->ecommunity->val + (i * 8);
- tbit = *pnt;
-
- if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
- continue;
-
- ecom_tr_size++;
- }
-
- if (ecom_tr_size)
- {
- if (ecom_tr_size * 8 > 255)
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
- stream_putw (s, ecom_tr_size * 8);
+
+ /* MED attribute. */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)
+ || bgp->maxmed_active) {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
+ stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
+ stream_putc(s, 4);
+ stream_putl(s, (bgp->maxmed_active ? bgp->maxmed_value
+ : attr->med));
+ }
+
+ /* Local preference. */
+ if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) {
+ stream_putc(s, BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_LOCAL_PREF);
+ stream_putc(s, 4);
+ stream_putl(s, attr->local_pref);
+ }
+
+ /* Atomic aggregate. */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) {
+ stream_putc(s, BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE);
+ stream_putc(s, 0);
+ }
+
+ /* Aggregator. */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) {
+ /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_AGGREGATOR);
+
+ if (use32bit) {
+ /* AS4 capable peer */
+ stream_putc(s, 8);
+ stream_putl(s, attr->aggregator_as);
+ } else {
+ /* 2-byte AS peer */
+ stream_putc(s, 6);
+
+ /* Is ASN representable in 2-bytes? Or must AS_TRANS be
+ * used? */
+ if (attr->aggregator_as > 65535) {
+ stream_putw(s, BGP_AS_TRANS);
+
+ /* we have to send AS4_AGGREGATOR, too.
+ * we'll do that later in order to send
+ * attributes in ascending
+ * order.
+ */
+ send_as4_aggregator = 1;
+ } else
+ stream_putw(s, (u_int16_t)attr->aggregator_as);
+ }
+ stream_put_ipv4(s, attr->aggregator_addr.s_addr);
+ }
+
+ /* Community attribute. */
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
+ && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
+ if (attr->community->size * 4 > 255) {
+ stream_putc(s,
+ BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_COMMUNITIES);
+ stream_putw(s, attr->community->size * 4);
+ } else {
+ stream_putc(s,
+ BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_COMMUNITIES);
+ stream_putc(s, attr->community->size * 4);
}
- else
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
- stream_putc (s, ecom_tr_size * 8);
+ stream_put(s, attr->community->val, attr->community->size * 4);
+ }
+
+ /*
+ * Large Community attribute.
+ */
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SEND_LARGE_COMMUNITY)
+ && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
+ if (attr->lcommunity->size * 12 > 255) {
+ stream_putc(s,
+ BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
+ stream_putw(s, attr->lcommunity->size * 12);
+ } else {
+ stream_putc(s,
+ BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
+ stream_putc(s, attr->lcommunity->size * 12);
}
+ stream_put(s, attr->lcommunity->val,
+ attr->lcommunity->size * 12);
+ }
- for (i = 0; i < attr->ecommunity->size; i++)
- {
- pnt = attr->ecommunity->val + (i * 8);
- tbit = *pnt;
+ /* Route Reflector. */
+ if (peer->sort == BGP_PEER_IBGP && from
+ && from->sort == BGP_PEER_IBGP) {
+ /* Originator ID. */
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
+ stream_putc(s, BGP_ATTR_ORIGINATOR_ID);
+ stream_putc(s, 4);
+
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
+ stream_put_in_addr(s, &attr->originator_id);
+ else
+ stream_put_in_addr(s, &from->remote_id);
+
+ /* Cluster list. */
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
+ stream_putc(s, BGP_ATTR_CLUSTER_LIST);
+
+ if (attr->cluster) {
+ stream_putc(s, attr->cluster->length + 4);
+ /* If this peer configuration's parent BGP has
+ * cluster_id. */
+ if (bgp->config & BGP_CONFIG_CLUSTER_ID)
+ stream_put_in_addr(s, &bgp->cluster_id);
+ else
+ stream_put_in_addr(s, &bgp->router_id);
+ stream_put(s, attr->cluster->list,
+ attr->cluster->length);
+ } else {
+ stream_putc(s, 4);
+ /* If this peer configuration's parent BGP has
+ * cluster_id. */
+ if (bgp->config & BGP_CONFIG_CLUSTER_ID)
+ stream_put_in_addr(s, &bgp->cluster_id);
+ else
+ stream_put_in_addr(s, &bgp->router_id);
+ }
+ }
- if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
- continue;
+ /* Extended Communities attribute. */
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
+ && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) {
+ if (peer->sort == BGP_PEER_IBGP
+ || peer->sort == BGP_PEER_CONFED) {
+ if (attr->ecommunity->size * 8 > 255) {
+ stream_putc(s,
+ BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
+ stream_putw(s, attr->ecommunity->size * 8);
+ } else {
+ stream_putc(s,
+ BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
+ stream_putc(s, attr->ecommunity->size * 8);
+ }
+ stream_put(s, attr->ecommunity->val,
+ attr->ecommunity->size * 8);
+ } else {
+ u_int8_t *pnt;
+ int tbit;
+ int ecom_tr_size = 0;
+ int i;
+
+ for (i = 0; i < attr->ecommunity->size; i++) {
+ pnt = attr->ecommunity->val + (i * 8);
+ tbit = *pnt;
+
+ if (CHECK_FLAG(tbit,
+ ECOMMUNITY_FLAG_NON_TRANSITIVE))
+ continue;
+
+ ecom_tr_size++;
+ }
+
+ if (ecom_tr_size) {
+ if (ecom_tr_size * 8 > 255) {
+ stream_putc(
+ s,
+ BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s,
+ BGP_ATTR_EXT_COMMUNITIES);
+ stream_putw(s, ecom_tr_size * 8);
+ } else {
+ stream_putc(
+ s,
+ BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s,
+ BGP_ATTR_EXT_COMMUNITIES);
+ stream_putc(s, ecom_tr_size * 8);
+ }
+
+ for (i = 0; i < attr->ecommunity->size; i++) {
+ pnt = attr->ecommunity->val + (i * 8);
+ tbit = *pnt;
+
+ if (CHECK_FLAG(
+ tbit,
+ ECOMMUNITY_FLAG_NON_TRANSITIVE))
+ continue;
+
+ stream_put(s, pnt, 8);
+ }
+ }
+ }
+ }
- stream_put (s, pnt, 8);
+ /* Label index attribute. */
+ if (safi == SAFI_LABELED_UNICAST) {
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
+ u_int32_t label_index;
+
+ label_index = attr->label_index;
+
+ if (label_index != BGP_INVALID_LABEL_INDEX) {
+ stream_putc(s,
+ BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_PREFIX_SID);
+ stream_putc(s, 10);
+ stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
+ stream_putw(s,
+ BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
+ stream_putc(s, 0); // reserved
+ stream_putw(s, 0); // flags
+ stream_putl(s, label_index);
+ }
}
- }
- }
- }
-
- /* Label index attribute. */
- if (safi == SAFI_LABELED_UNICAST)
- {
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID))
- {
- u_int32_t label_index;
-
- label_index = attr->label_index;
-
- if (label_index != BGP_INVALID_LABEL_INDEX)
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_PREFIX_SID);
- stream_putc (s, 10);
- stream_putc (s, BGP_PREFIX_SID_LABEL_INDEX);
- stream_putw (s, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
- stream_putc (s, 0); // reserved
- stream_putw (s, 0); // flags
- stream_putl (s, label_index);
- }
- }
- }
-
- if ( send_as4_path )
- {
- /* If the peer is NOT As4 capable, AND */
- /* there are ASnums > 65535 in path THEN
- * give out AS4_PATH */
-
- /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
- * path segments!
- * Hm, I wonder... confederation things *should* only be at
- * the beginning of an aspath, right? Then we should use
- * aspath_delete_confed_seq for this, because it is already
- * there! (JK)
- * Folks, talk to me: what is reasonable here!?
- */
- aspath = aspath_delete_confed_seq (aspath);
-
- stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_AS4_PATH);
- aspath_sizep = stream_get_endp (s);
- stream_putw (s, 0);
- stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
- }
-
- if (aspath != attr->aspath)
- aspath_free (aspath);
-
- if ( send_as4_aggregator )
- {
- /* send AS4_AGGREGATOR, at this place */
- /* this section of code moved here in order to ensure the correct
- * *ascending* order of attributes
- */
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
- stream_putc (s, 8);
- stream_putl (s, attr->aggregator_as);
- stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
- }
-
- if (((afi == AFI_IP || afi == AFI_IP6) &&
- (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN)) ||
- (afi == AFI_L2VPN && safi == SAFI_EVPN))
- {
- /* Tunnel Encap attribute */
- bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP);
+ }
+
+ if (send_as4_path) {
+ /* If the peer is NOT As4 capable, AND */
+ /* there are ASnums > 65535 in path THEN
+ * give out AS4_PATH */
+
+ /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
+ * path segments!
+ * Hm, I wonder... confederation things *should* only be at
+ * the beginning of an aspath, right? Then we should use
+ * aspath_delete_confed_seq for this, because it is already
+ * there! (JK)
+ * Folks, talk to me: what is reasonable here!?
+ */
+ aspath = aspath_delete_confed_seq(aspath);
+
+ stream_putc(s,
+ BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_AS4_PATH);
+ aspath_sizep = stream_get_endp(s);
+ stream_putw(s, 0);
+ stream_putw_at(s, aspath_sizep, aspath_put(s, aspath, 1));
+ }
+
+ if (aspath != attr->aspath)
+ aspath_free(aspath);
+
+ if (send_as4_aggregator) {
+ /* send AS4_AGGREGATOR, at this place */
+ /* this section of code moved here in order to ensure the
+ * correct
+ * *ascending* order of attributes
+ */
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_AS4_AGGREGATOR);
+ stream_putc(s, 8);
+ stream_putl(s, attr->aggregator_as);
+ stream_put_ipv4(s, attr->aggregator_addr.s_addr);
+ }
+
+ if (((afi == AFI_IP || afi == AFI_IP6)
+ && (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN))
+ || (afi == AFI_L2VPN && safi == SAFI_EVPN)) {
+ /* Tunnel Encap attribute */
+ bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP);
#if ENABLE_BGP_VNC
- /* VNC attribute */
- bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_VNC);
+ /* VNC attribute */
+ bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_VNC);
#endif
- }
+ }
- /* Unknown transit attribute. */
- if (attr->transit)
- stream_put (s, attr->transit->val, attr->transit->length);
+ /* Unknown transit attribute. */
+ if (attr->transit)
+ stream_put(s, attr->transit->val, attr->transit->length);
- /* Return total size of attribute. */
- return stream_get_endp (s) - cp;
+ /* Return total size of attribute. */
+ return stream_get_endp(s) - cp;
}
-size_t
-bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi)
+size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi)
{
- unsigned long attrlen_pnt;
- iana_afi_t pkt_afi;
- safi_t pkt_safi;
+ unsigned long attrlen_pnt;
+ iana_afi_t pkt_afi;
+ safi_t pkt_safi;
- /* Set extended bit always to encode the attribute length as 2 bytes */
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
+ /* Set extended bit always to encode the attribute length as 2 bytes */
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_MP_UNREACH_NLRI);
- attrlen_pnt = stream_get_endp (s);
- stream_putw (s, 0); /* Length of this attribute. */
+ attrlen_pnt = stream_get_endp(s);
+ stream_putw(s, 0); /* Length of this attribute. */
- /* Convert AFI, SAFI to values for packet. */
- bgp_map_afi_safi_int2iana (afi, safi, &pkt_afi, &pkt_safi);
+ /* Convert AFI, SAFI to values for packet. */
+ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
- stream_putw (s, pkt_afi);
- stream_putc (s, pkt_safi);
+ stream_putw(s, pkt_afi);
+ stream_putc(s, pkt_safi);
- return attrlen_pnt;
+ return attrlen_pnt;
}
-void
-bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
- afi_t afi, safi_t safi, struct prefix_rd *prd,
- mpls_label_t *label, int addpath_encode,
- u_int32_t addpath_tx_id, struct attr *attr)
+void bgp_packet_mpunreach_prefix(struct stream *s, struct prefix *p, afi_t afi,
+ safi_t safi, struct prefix_rd *prd,
+ mpls_label_t *label, int addpath_encode,
+ u_int32_t addpath_tx_id, struct attr *attr)
{
- u_char wlabel[3] = {0x80, 0x00, 0x00};
+ u_char wlabel[3] = {0x80, 0x00, 0x00};
- if (safi == SAFI_LABELED_UNICAST)
- label = (mpls_label_t *) wlabel;
+ if (safi == SAFI_LABELED_UNICAST)
+ label = (mpls_label_t *)wlabel;
- return bgp_packet_mpattr_prefix (s, afi, safi, p, prd,
- label,
- addpath_encode, addpath_tx_id, attr);
+ return bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
+ addpath_encode, addpath_tx_id, attr);
}
-void
-bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt)
+void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt)
{
- bgp_packet_mpattr_end (s, attrlen_pnt);
+ bgp_packet_mpattr_end(s, attrlen_pnt);
}
/* Initialization of attribute. */
-void
-bgp_attr_init (void)
+void bgp_attr_init(void)
{
- aspath_init ();
- attrhash_init ();
- community_init ();
- ecommunity_init ();
- lcommunity_init ();
- cluster_init ();
- transit_init ();
- encap_init ();
+ aspath_init();
+ attrhash_init();
+ community_init();
+ ecommunity_init();
+ lcommunity_init();
+ cluster_init();
+ transit_init();
+ encap_init();
}
-void
-bgp_attr_finish (void)
+void bgp_attr_finish(void)
{
- aspath_finish ();
- attrhash_finish ();
- community_finish ();
- ecommunity_finish ();
- lcommunity_finish ();
- cluster_finish ();
- transit_finish ();
- encap_finish ();
+ aspath_finish();
+ attrhash_finish();
+ community_finish();
+ ecommunity_finish();
+ lcommunity_finish();
+ cluster_finish();
+ transit_finish();
+ encap_finish();
}
/* Make attribute packet. */
-void
-bgp_dump_routes_attr (struct stream *s, struct attr *attr,
- struct prefix *prefix)
-{
- unsigned long cp;
- unsigned long len;
- size_t aspath_lenp;
- struct aspath *aspath;
- int addpath_encode = 0;
- u_int32_t addpath_tx_id = 0;
-
- /* Remember current pointer. */
- cp = stream_get_endp (s);
-
- /* Place holder of length. */
- stream_putw (s, 0);
-
- /* Origin attribute. */
- stream_putc (s, BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_ORIGIN);
- stream_putc (s, 1);
- stream_putc (s, attr->origin);
-
- aspath = attr->aspath;
-
- stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_AS_PATH);
- aspath_lenp = stream_get_endp (s);
- stream_putw (s, 0);
-
- stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
-
- /* Nexthop attribute. */
- /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
- if(prefix != NULL && prefix->family != AF_INET6)
- {
- stream_putc (s, BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_NEXT_HOP);
- stream_putc (s, 4);
- stream_put_ipv4 (s, attr->nexthop.s_addr);
- }
-
- /* MED attribute. */
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
- stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
- stream_putc (s, 4);
- stream_putl (s, attr->med);
- }
-
- /* Local preference. */
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
- {
- stream_putc (s, BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_LOCAL_PREF);
- stream_putc (s, 4);
- stream_putl (s, attr->local_pref);
- }
-
- /* Atomic aggregate. */
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
- {
- stream_putc (s, BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
- stream_putc (s, 0);
- }
-
- /* Aggregator. */
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_AGGREGATOR);
- stream_putc (s, 8);
- stream_putl (s, attr->aggregator_as);
- stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
- }
-
- /* Community attribute. */
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
- {
- if (attr->community->size * 4 > 255)
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_COMMUNITIES);
- stream_putw (s, attr->community->size * 4);
+void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
+ struct prefix *prefix)
+{
+ unsigned long cp;
+ unsigned long len;
+ size_t aspath_lenp;
+ struct aspath *aspath;
+ int addpath_encode = 0;
+ u_int32_t addpath_tx_id = 0;
+
+ /* Remember current pointer. */
+ cp = stream_get_endp(s);
+
+ /* Place holder of length. */
+ stream_putw(s, 0);
+
+ /* Origin attribute. */
+ stream_putc(s, BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_ORIGIN);
+ stream_putc(s, 1);
+ stream_putc(s, attr->origin);
+
+ aspath = attr->aspath;
+
+ stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_AS_PATH);
+ aspath_lenp = stream_get_endp(s);
+ stream_putw(s, 0);
+
+ stream_putw_at(s, aspath_lenp, aspath_put(s, aspath, 1));
+
+ /* Nexthop attribute. */
+ /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
+ if (prefix != NULL && prefix->family != AF_INET6) {
+ stream_putc(s, BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_NEXT_HOP);
+ stream_putc(s, 4);
+ stream_put_ipv4(s, attr->nexthop.s_addr);
}
- else
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_COMMUNITIES);
- stream_putc (s, attr->community->size * 4);
- }
- stream_put (s, attr->community->val, attr->community->size * 4);
- }
-
- /* Large Community attribute. */
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES))
- {
- if (attr->lcommunity->size * 12 > 255)
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
- stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
- stream_putw (s, attr->lcommunity->size * 12);
- }
- else
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_LARGE_COMMUNITIES);
- stream_putc (s, attr->lcommunity->size * 12);
- }
-
- stream_put (s, attr->lcommunity->val, attr->lcommunity->size * 12);
- }
-
- /* Add a MP_NLRI attribute to dump the IPv6 next hop */
- if (prefix != NULL && prefix->family == AF_INET6 &&
- (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
- attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) )
- {
- int sizep;
-
- stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
- stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
- sizep = stream_get_endp (s);
-
- /* MP header */
- stream_putc (s, 0); /* Marker: Attribute length. */
- stream_putw(s, AFI_IP6); /* AFI */
- stream_putc(s, SAFI_UNICAST); /* SAFI */
-
- /* Next hop */
- stream_putc(s, attr->mp_nexthop_len);
- stream_put(s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN);
- if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
- stream_put(s, &attr->mp_nexthop_local, IPV6_MAX_BYTELEN);
-
- /* SNPA */
- stream_putc(s, 0);
-
- /* Prefix */
- stream_put_prefix_addpath (s, prefix, addpath_encode, addpath_tx_id);
-
- /* Set MP attribute length. */
- stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
- }
-
- /* Prefix SID */
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_PREFIX_SID))
- {
- if (attr->label_index != BGP_INVALID_LABEL_INDEX)
- {
- stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
- stream_putc (s, BGP_ATTR_PREFIX_SID);
- stream_putc (s, 10);
- stream_putc (s, BGP_PREFIX_SID_LABEL_INDEX);
- stream_putc (s, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
- stream_putc (s, 0); // reserved
- stream_putw (s, 0); // flags
- stream_putl (s, attr->label_index);
- }
- }
-
- /* Return total size of attribute. */
- len = stream_get_endp (s) - cp - 2;
- stream_putw_at (s, cp, len);
+
+ /* MED attribute. */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
+ stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
+ stream_putc(s, 4);
+ stream_putl(s, attr->med);
+ }
+
+ /* Local preference. */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
+ stream_putc(s, BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_LOCAL_PREF);
+ stream_putc(s, 4);
+ stream_putl(s, attr->local_pref);
+ }
+
+ /* Atomic aggregate. */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) {
+ stream_putc(s, BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE);
+ stream_putc(s, 0);
+ }
+
+ /* Aggregator. */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) {
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_AGGREGATOR);
+ stream_putc(s, 8);
+ stream_putl(s, attr->aggregator_as);
+ stream_put_ipv4(s, attr->aggregator_addr.s_addr);
+ }
+
+ /* Community attribute. */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
+ if (attr->community->size * 4 > 255) {
+ stream_putc(s,
+ BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_COMMUNITIES);
+ stream_putw(s, attr->community->size * 4);
+ } else {
+ stream_putc(s,
+ BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_COMMUNITIES);
+ stream_putc(s, attr->community->size * 4);
+ }
+ stream_put(s, attr->community->val, attr->community->size * 4);
+ }
+
+ /* Large Community attribute. */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
+ if (attr->lcommunity->size * 12 > 255) {
+ stream_putc(s,
+ BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
+ | BGP_ATTR_FLAG_EXTLEN);
+ stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
+ stream_putw(s, attr->lcommunity->size * 12);
+ } else {
+ stream_putc(s,
+ BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
+ stream_putc(s, attr->lcommunity->size * 12);
+ }
+
+ stream_put(s, attr->lcommunity->val,
+ attr->lcommunity->size * 12);
+ }
+
+ /* Add a MP_NLRI attribute to dump the IPv6 next hop */
+ if (prefix != NULL && prefix->family == AF_INET6
+ && (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL
+ || attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)) {
+ int sizep;
+
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
+ stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
+ sizep = stream_get_endp(s);
+
+ /* MP header */
+ stream_putc(s, 0); /* Marker: Attribute length. */
+ stream_putw(s, AFI_IP6); /* AFI */
+ stream_putc(s, SAFI_UNICAST); /* SAFI */
+
+ /* Next hop */
+ stream_putc(s, attr->mp_nexthop_len);
+ stream_put(s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN);
+ if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
+ stream_put(s, &attr->mp_nexthop_local,
+ IPV6_MAX_BYTELEN);
+
+ /* SNPA */
+ stream_putc(s, 0);
+
+ /* Prefix */
+ stream_put_prefix_addpath(s, prefix, addpath_encode,
+ addpath_tx_id);
+
+ /* Set MP attribute length. */
+ stream_putc_at(s, sizep, (stream_get_endp(s) - sizep) - 1);
+ }
+
+ /* Prefix SID */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
+ if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
+ stream_putc(s,
+ BGP_ATTR_FLAG_OPTIONAL
+ | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_PREFIX_SID);
+ stream_putc(s, 10);
+ stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
+ stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
+ stream_putc(s, 0); // reserved
+ stream_putw(s, 0); // flags
+ stream_putl(s, attr->label_index);
+ }
+ }
+
+ /* Return total size of attribute. */
+ len = stream_get_endp(s) - cp - 2;
+ stream_putw_at(s, cp, len);
}