diff options
-rw-r--r-- | bgpd/ChangeLog | 5 | ||||
-rw-r--r-- | bgpd/bgp_attr.c | 64 | ||||
-rw-r--r-- | bgpd/bgp_ecommunity.c | 65 | ||||
-rw-r--r-- | bgpd/bgp_ecommunity.h | 5 | ||||
-rw-r--r-- | bgpd/bgp_packet.c | 2 |
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)) |