summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/ChangeLog5
-rw-r--r--bgpd/bgp_attr.c64
-rw-r--r--bgpd/bgp_ecommunity.c65
-rw-r--r--bgpd/bgp_ecommunity.h5
-rw-r--r--bgpd/bgp_packet.c2
5 files changed, 119 insertions, 22 deletions
diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog
index cdcd83b9..3adb996b 100644
--- a/bgpd/ChangeLog
+++ b/bgpd/ChangeLog
@@ -1,3 +1,8 @@
+2004-05-20 Akihiro Mizutani <mizutani@net-chef.net>
+
+ * bgp_ecommunity.c: Transit ecommunity support.
+ * bgp_ecommunity.c: Fix for unknown community crush.
+
2005-05-20 Kunihiro Ishiguro <kunihiro@ipinfusion.com>
* *: Maximum prefix threshold support.
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 91a0e07c..7d48374d 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1653,19 +1653,67 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
&& (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
{
- if (attr->ecommunity->size * 8 > 255)
+ if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED)
{
- 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);
+ 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
{
- 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);
+ u_char *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, attr->ecommunity->val, attr->ecommunity->size * 8);
}
/* Unknown transit attribute. */
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 2f9cc945..4adbcf52 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -158,6 +158,15 @@ ecommunity_dup (struct ecommunity *ecom)
return new;
}
+/* Retrun string representation of communities attribute. */
+char *
+ecommunity_str (struct ecommunity *ecom)
+{
+ if (! ecom->str)
+ ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY);
+ return ecom->str;
+}
+
/* Merge two Extended Communities Attribute structure. */
struct ecommunity *
ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2)
@@ -559,24 +568,30 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
for (i = 0; i < ecom->size; i++)
{
+ /* Space between each value. */
+ if (! first)
+ str_buf[str_pnt++] = ' ';
+
pnt = ecom->val + (i * 8);
/* High-order octet of type. */
encode = *pnt++;
if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP)
{
- if (str_buf)
- XFREE (MTYPE_ECOMMUNITY_STR, str_buf);
- return "Unknown";
+ len = sprintf (str_buf + str_pnt, "?");
+ str_pnt += len;
+ first = 0;
+ continue;
}
/* Low-order octet of type. */
type = *pnt++;
if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN)
{
- if (str_buf)
- XFREE (MTYPE_ECOMMUNITY_STR, str_buf);
- return "Unknown";
+ len = sprintf (str_buf + str_pnt, "?");
+ str_pnt += len;
+ first = 0;
+ continue;
}
switch (format)
@@ -591,9 +606,7 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
prefix = "";
break;
default:
- if (str_buf)
- XFREE (MTYPE_ECOMMUNITY_STR, str_buf);
- return "Unknown";
+ prefix = "";
break;
}
@@ -604,10 +617,6 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size);
}
- /* Space between each value. */
- if (! first)
- str_buf[str_pnt++] = ' ';
-
/* Put string into buffer. */
if (encode == ECOMMUNITY_ENCODE_AS)
{
@@ -639,3 +648,33 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)
}
return str_buf;
}
+
+int
+ecommunity_match (struct ecommunity *ecom1, struct ecommunity *ecom2)
+{
+ int i = 0;
+ int j = 0;
+
+ if (ecom1 == NULL && ecom2 == NULL)
+ return 1;
+
+ if (ecom1 == NULL || ecom2 == NULL)
+ return 0;
+
+ if (ecom1->size < ecom2->size)
+ return 0;
+
+ /* Every community on com2 needs to be on com1 for this to match */
+ while (i < ecom1->size && j < ecom2->size)
+ {
+ if (memcmp (ecom1->val + i, ecom2->val + j, ECOMMUNITY_SIZE) == 0)
+ j++;
+ i++;
+ }
+
+ if (j == ecom2->size)
+ return 1;
+ else
+ return 0;
+}
+
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 678d1308..e266471f 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -34,6 +34,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
/* Extended Communities value is eight octet long. */
#define ECOMMUNITY_SIZE 8
+/* Extended Communities type flag. */
+#define ECOMMUNITY_FLAG_NON_TRANSITIVE 0x40
+
/* Extended Communities attribute. */
struct ecommunity
{
@@ -70,3 +73,5 @@ void ecommunity_unintern (struct ecommunity *);
unsigned int ecommunity_hash_make (struct ecommunity *);
struct ecommunity *ecommunity_str2com (char *, int, int);
char *ecommunity_ecom2str (struct ecommunity *, int);
+int ecommunity_match (struct ecommunity *, struct ecommunity *);
+char *ecommunity_str (struct ecommunity *);
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 9995c02c..341a192c 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -273,7 +273,7 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi)
#endif /* MPLS_VPN */
if (STREAM_REMAIN (s)
- <= (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen)))
+ < (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen)))
break;
if (stream_empty (s))