forked from Mirror/frr
Support for BGP Large Communities
BGP Large Communities are a novel way to signal information between networks. An example of a Large Community is: "2914:65400:38016". Large BGP Communities are composed of three 4-byte integers, separated by a colon. This is easy to remember and accommodates advanced routing policies in relation to 4-Byte ASNs. This feature was developed by: Keyur Patel <keyur@arrcus.com> (Arrcus, Inc.), Job Snijders <job@ntt.net> (NTT Communications), David Lamparter <equinox@opensourcerouting.org> and Donald Sharp <sharpd@cumulusnetworks.com> Signed-off-by: Job Snijders <job@ntt.net> Signed-off-by: David Lamparter <equinox@opensourcerouting.org> Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
parent
45680e7568
commit
57d187bc77
|
@ -75,7 +75,8 @@ libbgp_a_SOURCES = \
|
||||||
bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \
|
bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \
|
||||||
bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \
|
bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \
|
||||||
bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
|
bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
|
||||||
bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
|
bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_lcommunity.c \
|
||||||
|
bgp_mplsvpn.c bgp_nexthop.c \
|
||||||
bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
|
bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
|
||||||
bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \
|
bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c bgp_bfd.c \
|
||||||
bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC)
|
bgp_encap.c bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC)
|
||||||
|
@ -85,7 +86,8 @@ noinst_HEADERS = \
|
||||||
bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
|
bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
|
||||||
bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \
|
bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \
|
||||||
bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
|
bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
|
||||||
bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
|
bgp_ecommunity.h bgp_lcommunity.h \
|
||||||
|
bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
|
||||||
bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \
|
bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \
|
||||||
bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \
|
bgp_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \
|
||||||
$(BGP_VNC_RFAPI_HD)
|
$(BGP_VNC_RFAPI_HD)
|
||||||
|
|
101
bgpd/bgp_attr.c
101
bgpd/bgp_attr.c
|
@ -42,6 +42,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
#include "bgpd/bgp_debug.h"
|
#include "bgpd/bgp_debug.h"
|
||||||
#include "bgpd/bgp_packet.h"
|
#include "bgpd/bgp_packet.h"
|
||||||
#include "bgpd/bgp_ecommunity.h"
|
#include "bgpd/bgp_ecommunity.h"
|
||||||
|
#include "bgpd/bgp_lcommunity.h"
|
||||||
#include "bgpd/bgp_updgrp.h"
|
#include "bgpd/bgp_updgrp.h"
|
||||||
#include "bgpd/bgp_encap_types.h"
|
#include "bgpd/bgp_encap_types.h"
|
||||||
#if ENABLE_BGP_VNC
|
#if ENABLE_BGP_VNC
|
||||||
|
@ -76,6 +77,7 @@ static const struct message attr_str [] =
|
||||||
#if ENABLE_BGP_VNC
|
#if ENABLE_BGP_VNC
|
||||||
{ BGP_ATTR_VNC, "VNC" },
|
{ BGP_ATTR_VNC, "VNC" },
|
||||||
#endif
|
#endif
|
||||||
|
{ BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" }
|
||||||
};
|
};
|
||||||
static const int attr_str_max = array_size(attr_str);
|
static const int attr_str_max = array_size(attr_str);
|
||||||
|
|
||||||
|
@ -670,6 +672,8 @@ attrhash_key_make (void *p)
|
||||||
|
|
||||||
if (extra)
|
if (extra)
|
||||||
{
|
{
|
||||||
|
if (extra->lcommunity)
|
||||||
|
MIX(lcommunity_hash_make (extra->lcommunity));
|
||||||
if (extra->ecommunity)
|
if (extra->ecommunity)
|
||||||
MIX(ecommunity_hash_make (extra->ecommunity));
|
MIX(ecommunity_hash_make (extra->ecommunity));
|
||||||
if (extra->cluster)
|
if (extra->cluster)
|
||||||
|
@ -718,6 +722,7 @@ attrhash_cmp (const void *p1, const void *p2)
|
||||||
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
|
&& IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
|
||||||
&& IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
|
&& IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
|
||||||
&& ae1->ecommunity == ae2->ecommunity
|
&& ae1->ecommunity == ae2->ecommunity
|
||||||
|
&& ae1->lcommunity == ae2->lcommunity
|
||||||
&& ae1->cluster == ae2->cluster
|
&& ae1->cluster == ae2->cluster
|
||||||
&& ae1->transit == ae2->transit
|
&& ae1->transit == ae2->transit
|
||||||
&& (ae1->encap_tunneltype == ae2->encap_tunneltype)
|
&& (ae1->encap_tunneltype == ae2->encap_tunneltype)
|
||||||
|
@ -836,6 +841,13 @@ bgp_attr_intern (struct attr *attr)
|
||||||
attre->ecommunity->refcnt++;
|
attre->ecommunity->refcnt++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (attre->lcommunity)
|
||||||
|
{
|
||||||
|
if (! attre->lcommunity->refcnt)
|
||||||
|
attre->lcommunity = lcommunity_intern (attre->lcommunity);
|
||||||
|
else
|
||||||
|
attre->lcommunity->refcnt++;
|
||||||
|
}
|
||||||
if (attre->cluster)
|
if (attre->cluster)
|
||||||
{
|
{
|
||||||
if (! attre->cluster->refcnt)
|
if (! attre->cluster->refcnt)
|
||||||
|
@ -1026,6 +1038,10 @@ bgp_attr_unintern_sub (struct attr *attr)
|
||||||
if (attr->extra->ecommunity)
|
if (attr->extra->ecommunity)
|
||||||
ecommunity_unintern (&attr->extra->ecommunity);
|
ecommunity_unintern (&attr->extra->ecommunity);
|
||||||
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES));
|
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES));
|
||||||
|
|
||||||
|
if (attr->extra->lcommunity)
|
||||||
|
lcommunity_unintern (&attr->extra->lcommunity);
|
||||||
|
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES));
|
||||||
|
|
||||||
if (attr->extra->cluster)
|
if (attr->extra->cluster)
|
||||||
cluster_unintern (attr->extra->cluster);
|
cluster_unintern (attr->extra->cluster);
|
||||||
|
@ -1096,6 +1112,8 @@ bgp_attr_flush (struct attr *attr)
|
||||||
|
|
||||||
if (attre->ecommunity && ! attre->ecommunity->refcnt)
|
if (attre->ecommunity && ! attre->ecommunity->refcnt)
|
||||||
ecommunity_free (&attre->ecommunity);
|
ecommunity_free (&attre->ecommunity);
|
||||||
|
if (attre->lcommunity && ! attre->lcommunity->refcnt)
|
||||||
|
lcommunity_free (&attre->lcommunity);
|
||||||
if (attre->cluster && ! attre->cluster->refcnt)
|
if (attre->cluster && ! attre->cluster->refcnt)
|
||||||
{
|
{
|
||||||
cluster_free (attre->cluster);
|
cluster_free (attre->cluster);
|
||||||
|
@ -1254,6 +1272,7 @@ const u_int8_t attr_flags_values [] = {
|
||||||
[BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
|
[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_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
|
||||||
[BGP_ATTR_AS4_AGGREGATOR] = 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_TRANS | BGP_ATTR_FLAG_OPTIONAL
|
||||||
};
|
};
|
||||||
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
|
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
|
||||||
|
|
||||||
|
@ -2042,6 +2061,40 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
|
||||||
return BGP_ATTR_PARSE_PROCEED;
|
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)
|
||||||
|
{
|
||||||
|
if (attr->extra)
|
||||||
|
attr->extra->lcommunity = NULL;
|
||||||
|
/* Empty extcomm doesn't seem to be invalid per se */
|
||||||
|
return BGP_ATTR_PARSE_PROCEED;
|
||||||
|
}
|
||||||
|
|
||||||
|
(bgp_attr_extra_get (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->extra && !attr->extra->lcommunity)
|
||||||
|
return bgp_attr_malformed (args,
|
||||||
|
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
|
||||||
|
args->total);
|
||||||
|
|
||||||
|
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
|
||||||
|
|
||||||
|
return BGP_ATTR_PARSE_PROCEED;
|
||||||
|
}
|
||||||
|
|
||||||
/* Extended Community attribute. */
|
/* Extended Community attribute. */
|
||||||
static bgp_attr_parse_ret_t
|
static bgp_attr_parse_ret_t
|
||||||
bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
|
bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
|
||||||
|
@ -2063,7 +2116,7 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
|
||||||
/* XXX: fix ecommunity_parse to use stream API */
|
/* XXX: fix ecommunity_parse to use stream API */
|
||||||
stream_forward_getp (peer->ibuf, length);
|
stream_forward_getp (peer->ibuf, length);
|
||||||
|
|
||||||
if (!attr->extra->ecommunity)
|
if (attr->extra && !attr->extra->ecommunity)
|
||||||
return bgp_attr_malformed (args,
|
return bgp_attr_malformed (args,
|
||||||
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
|
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
|
||||||
args->total);
|
args->total);
|
||||||
|
@ -2477,6 +2530,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
|
||||||
case BGP_ATTR_COMMUNITIES:
|
case BGP_ATTR_COMMUNITIES:
|
||||||
ret = bgp_attr_community (&attr_args);
|
ret = bgp_attr_community (&attr_args);
|
||||||
break;
|
break;
|
||||||
|
case BGP_ATTR_LARGE_COMMUNITIES:
|
||||||
|
ret = bgp_attr_large_community (&attr_args);
|
||||||
|
break;
|
||||||
case BGP_ATTR_ORIGINATOR_ID:
|
case BGP_ATTR_ORIGINATOR_ID:
|
||||||
ret = bgp_attr_originator_id (&attr_args);
|
ret = bgp_attr_originator_id (&attr_args);
|
||||||
break;
|
break;
|
||||||
|
@ -3101,6 +3157,28 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
|
||||||
stream_put (s, attr->community->val, attr->community->size * 4);
|
stream_put (s, attr->community->val, attr->community->size * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Large Community attribute.
|
||||||
|
*/
|
||||||
|
if (attr->extra &&
|
||||||
|
CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY)
|
||||||
|
&& (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES)))
|
||||||
|
{
|
||||||
|
if (attr->extra->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->extra->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->extra->lcommunity->size * 12);
|
||||||
|
}
|
||||||
|
stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12);
|
||||||
|
}
|
||||||
|
|
||||||
/* Route Reflector. */
|
/* Route Reflector. */
|
||||||
if (peer->sort == BGP_PEER_IBGP
|
if (peer->sort == BGP_PEER_IBGP
|
||||||
&& from
|
&& from
|
||||||
|
@ -3333,6 +3411,7 @@ bgp_attr_init (void)
|
||||||
attrhash_init ();
|
attrhash_init ();
|
||||||
community_init ();
|
community_init ();
|
||||||
ecommunity_init ();
|
ecommunity_init ();
|
||||||
|
lcommunity_init ();
|
||||||
cluster_init ();
|
cluster_init ();
|
||||||
transit_init ();
|
transit_init ();
|
||||||
encap_init ();
|
encap_init ();
|
||||||
|
@ -3345,6 +3424,7 @@ bgp_attr_finish (void)
|
||||||
attrhash_finish ();
|
attrhash_finish ();
|
||||||
community_finish ();
|
community_finish ();
|
||||||
ecommunity_finish ();
|
ecommunity_finish ();
|
||||||
|
lcommunity_finish ();
|
||||||
cluster_finish ();
|
cluster_finish ();
|
||||||
transit_finish ();
|
transit_finish ();
|
||||||
encap_finish ();
|
encap_finish ();
|
||||||
|
@ -3448,6 +3528,25 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
|
||||||
stream_put (s, attr->community->val, attr->community->size * 4);
|
stream_put (s, attr->community->val, attr->community->size * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Large Community attribute. */
|
||||||
|
if (attr->extra && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES))
|
||||||
|
{
|
||||||
|
if (attr->extra->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->extra->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->extra->lcommunity->size * 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_put (s, attr->extra->lcommunity->val, attr->extra->lcommunity->size * 12);
|
||||||
|
}
|
||||||
|
|
||||||
/* Add a MP_NLRI attribute to dump the IPv6 next hop */
|
/* Add a MP_NLRI attribute to dump the IPv6 next hop */
|
||||||
if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
|
if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
|
||||||
(attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
|
(attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
|
||||||
|
|
|
@ -92,6 +92,9 @@ struct attr_extra
|
||||||
|
|
||||||
/* Extended Communities attribute. */
|
/* Extended Communities attribute. */
|
||||||
struct ecommunity *ecommunity;
|
struct ecommunity *ecommunity;
|
||||||
|
|
||||||
|
/* Large Communities attribute. */
|
||||||
|
struct lcommunity *lcommunity;
|
||||||
|
|
||||||
/* Route-Reflector Cluster attribute */
|
/* Route-Reflector Cluster attribute */
|
||||||
struct cluster_list *cluster;
|
struct cluster_list *cluster;
|
||||||
|
|
312
bgpd/bgp_clist.c
312
bgpd/bgp_clist.c
|
@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
#include "bgpd/bgpd.h"
|
#include "bgpd/bgpd.h"
|
||||||
#include "bgpd/bgp_community.h"
|
#include "bgpd/bgp_community.h"
|
||||||
#include "bgpd/bgp_ecommunity.h"
|
#include "bgpd/bgp_ecommunity.h"
|
||||||
|
#include "bgpd/bgp_lcommunity.h"
|
||||||
#include "bgpd/bgp_aspath.h"
|
#include "bgpd/bgp_aspath.h"
|
||||||
#include "bgpd/bgp_regex.h"
|
#include "bgpd/bgp_regex.h"
|
||||||
#include "bgpd/bgp_clist.h"
|
#include "bgpd/bgp_clist.h"
|
||||||
|
@ -45,6 +46,8 @@ community_list_master_lookup (struct community_list_handler *ch, int master)
|
||||||
return &ch->community_list;
|
return &ch->community_list;
|
||||||
case EXTCOMMUNITY_LIST_MASTER:
|
case EXTCOMMUNITY_LIST_MASTER:
|
||||||
return &ch->extcommunity_list;
|
return &ch->extcommunity_list;
|
||||||
|
case LARGE_COMMUNITY_LIST_MASTER:
|
||||||
|
return &ch->lcommunity_list;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -66,6 +69,10 @@ community_entry_free (struct community_entry *entry)
|
||||||
if (entry->u.com)
|
if (entry->u.com)
|
||||||
community_free (entry->u.com);
|
community_free (entry->u.com);
|
||||||
break;
|
break;
|
||||||
|
case LARGE_COMMUNITY_LIST_STANDARD:
|
||||||
|
if (entry->u.lcom)
|
||||||
|
lcommunity_free (&entry->u.lcom);
|
||||||
|
break;
|
||||||
case EXTCOMMUNITY_LIST_STANDARD:
|
case EXTCOMMUNITY_LIST_STANDARD:
|
||||||
/* In case of standard extcommunity-list, configuration string
|
/* In case of standard extcommunity-list, configuration string
|
||||||
is made by ecommunity_ecom2str(). */
|
is made by ecommunity_ecom2str(). */
|
||||||
|
@ -76,6 +83,7 @@ community_entry_free (struct community_entry *entry)
|
||||||
break;
|
break;
|
||||||
case COMMUNITY_LIST_EXPANDED:
|
case COMMUNITY_LIST_EXPANDED:
|
||||||
case EXTCOMMUNITY_LIST_EXPANDED:
|
case EXTCOMMUNITY_LIST_EXPANDED:
|
||||||
|
case LARGE_COMMUNITY_LIST_EXPANDED:
|
||||||
if (entry->config)
|
if (entry->config)
|
||||||
XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
|
XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
|
||||||
if (entry->reg)
|
if (entry->reg)
|
||||||
|
@ -320,8 +328,13 @@ community_list_entry_lookup (struct community_list *list, const void *arg,
|
||||||
if (entry->direct == direct && ecommunity_cmp (entry->u.ecom, arg))
|
if (entry->direct == direct && ecommunity_cmp (entry->u.ecom, arg))
|
||||||
return entry;
|
return entry;
|
||||||
break;
|
break;
|
||||||
|
case LARGE_COMMUNITY_LIST_STANDARD:
|
||||||
|
if (entry->direct == direct && lcommunity_cmp (entry->u.lcom, arg))
|
||||||
|
return entry;
|
||||||
|
break;
|
||||||
case COMMUNITY_LIST_EXPANDED:
|
case COMMUNITY_LIST_EXPANDED:
|
||||||
case EXTCOMMUNITY_LIST_EXPANDED:
|
case EXTCOMMUNITY_LIST_EXPANDED:
|
||||||
|
case LARGE_COMMUNITY_LIST_EXPANDED:
|
||||||
if (entry->direct == direct && strcmp (entry->config, arg) == 0)
|
if (entry->direct == direct && strcmp (entry->config, arg) == 0)
|
||||||
return entry;
|
return entry;
|
||||||
break;
|
break;
|
||||||
|
@ -447,6 +460,91 @@ community_regexp_match (struct community *com, regex_t * reg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
lcommunity_str_get (struct lcommunity *lcom, int i)
|
||||||
|
{
|
||||||
|
struct lcommunity_val lcomval;
|
||||||
|
u_int32_t globaladmin;
|
||||||
|
u_int32_t localdata1;
|
||||||
|
u_int32_t localdata2;
|
||||||
|
char *str;
|
||||||
|
u_char *ptr;
|
||||||
|
char *pnt;
|
||||||
|
|
||||||
|
ptr = lcom->val;
|
||||||
|
ptr += (i * LCOMMUNITY_SIZE);
|
||||||
|
|
||||||
|
memcpy (&lcomval, ptr, LCOMMUNITY_SIZE);
|
||||||
|
|
||||||
|
/* Allocate memory. 48 bytes taken off bgp_lcommunity.c */
|
||||||
|
str = pnt = XMALLOC (MTYPE_LCOMMUNITY_STR, 48);
|
||||||
|
|
||||||
|
ptr = (u_char *)lcomval.val;
|
||||||
|
globaladmin = (*ptr++ << 24);
|
||||||
|
globaladmin |= (*ptr++ << 16);
|
||||||
|
globaladmin |= (*ptr++ << 8);
|
||||||
|
globaladmin |= (*ptr++);
|
||||||
|
|
||||||
|
localdata1 = (*ptr++ << 24);
|
||||||
|
localdata1 |= (*ptr++ << 16);
|
||||||
|
localdata1 |= (*ptr++ << 8);
|
||||||
|
localdata1 |= (*ptr++);
|
||||||
|
|
||||||
|
localdata2 = (*ptr++ << 24);
|
||||||
|
localdata2 |= (*ptr++ << 16);
|
||||||
|
localdata2 |= (*ptr++ << 8);
|
||||||
|
localdata2 |= (*ptr++);
|
||||||
|
|
||||||
|
sprintf (pnt, "%u:%u:%u", globaladmin, localdata1, localdata2);
|
||||||
|
pnt += strlen (pnt);
|
||||||
|
*pnt = '\0';
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal function to perform regular expression match for
|
||||||
|
* * a single community. */
|
||||||
|
static int
|
||||||
|
lcommunity_regexp_include (regex_t * reg, struct lcommunity *lcom, int i)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
|
||||||
|
/* When there is no communities attribute it is treated as empty
|
||||||
|
* string. */
|
||||||
|
if (lcom == NULL || lcom->size == 0)
|
||||||
|
str = "";
|
||||||
|
else
|
||||||
|
str = lcommunity_str_get (lcom, i);
|
||||||
|
|
||||||
|
/* Regular expression match. */
|
||||||
|
if (regexec (reg, str, 0, NULL, 0) == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* No match. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lcommunity_regexp_match (struct lcommunity *com, regex_t * reg)
|
||||||
|
{
|
||||||
|
const char *str;
|
||||||
|
|
||||||
|
/* When there is no communities attribute it is treated as empty
|
||||||
|
string. */
|
||||||
|
if (com == NULL || com->size == 0)
|
||||||
|
str = "";
|
||||||
|
else
|
||||||
|
str = lcommunity_str (com);
|
||||||
|
|
||||||
|
/* Regular expression match. */
|
||||||
|
if (regexec (reg, str, 0, NULL, 0) == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* No match. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
|
ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
|
||||||
{
|
{
|
||||||
|
@ -546,6 +644,30 @@ community_list_match (struct community *com, struct community_list *list)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lcommunity_list_match (struct lcommunity *lcom, struct community_list *list)
|
||||||
|
{
|
||||||
|
struct community_entry *entry;
|
||||||
|
|
||||||
|
for (entry = list->head; entry; entry = entry->next)
|
||||||
|
{
|
||||||
|
if (entry->any)
|
||||||
|
return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
|
||||||
|
|
||||||
|
if (entry->style == LARGE_COMMUNITY_LIST_STANDARD)
|
||||||
|
{
|
||||||
|
if (lcommunity_match (lcom, entry->u.lcom))
|
||||||
|
return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
|
||||||
|
}
|
||||||
|
else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED)
|
||||||
|
{
|
||||||
|
if (lcommunity_regexp_match (lcom, entry->reg))
|
||||||
|
return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
|
ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
|
||||||
{
|
{
|
||||||
|
@ -694,12 +816,17 @@ community_list_dup_check (struct community_list *list,
|
||||||
if (community_cmp (entry->u.com, new->u.com))
|
if (community_cmp (entry->u.com, new->u.com))
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
|
case LARGE_COMMUNITY_LIST_STANDARD:
|
||||||
|
if (lcommunity_cmp (entry->u.lcom, new->u.lcom))
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
case EXTCOMMUNITY_LIST_STANDARD:
|
case EXTCOMMUNITY_LIST_STANDARD:
|
||||||
if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
|
if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
case COMMUNITY_LIST_EXPANDED:
|
case COMMUNITY_LIST_EXPANDED:
|
||||||
case EXTCOMMUNITY_LIST_EXPANDED:
|
case EXTCOMMUNITY_LIST_EXPANDED:
|
||||||
|
case LARGE_COMMUNITY_LIST_EXPANDED:
|
||||||
if (strcmp (entry->config, new->config) == 0)
|
if (strcmp (entry->config, new->config) == 0)
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
|
@ -817,6 +944,185 @@ community_list_unset (struct community_list_handler *ch,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Delete all permitted large communities in the list from com. */
|
||||||
|
struct lcommunity *
|
||||||
|
lcommunity_list_match_delete (struct lcommunity *lcom,
|
||||||
|
struct community_list *list)
|
||||||
|
{
|
||||||
|
struct community_entry *entry;
|
||||||
|
u_int32_t com_index_to_delete[lcom->size];
|
||||||
|
u_char *ptr;
|
||||||
|
int delete_index = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Loop over each lcommunity value and evaluate each against the
|
||||||
|
* community-list. If we need to delete a community value add its index to
|
||||||
|
* com_index_to_delete.
|
||||||
|
*/
|
||||||
|
ptr = lcom->val;
|
||||||
|
for (i = 0; i < lcom->size; i++)
|
||||||
|
{
|
||||||
|
ptr += (i * LCOMMUNITY_SIZE);
|
||||||
|
for (entry = list->head; entry; entry = entry->next)
|
||||||
|
{
|
||||||
|
if (entry->any)
|
||||||
|
{
|
||||||
|
if (entry->direct == COMMUNITY_PERMIT)
|
||||||
|
{
|
||||||
|
com_index_to_delete[delete_index] = i;
|
||||||
|
delete_index++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
|
||||||
|
&& lcommunity_include (entry->u.lcom, ptr) )
|
||||||
|
{
|
||||||
|
if (entry->direct == COMMUNITY_PERMIT)
|
||||||
|
{
|
||||||
|
com_index_to_delete[delete_index] = i;
|
||||||
|
delete_index++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD)
|
||||||
|
&& lcommunity_regexp_include (entry->reg, lcom, i))
|
||||||
|
{
|
||||||
|
if (entry->direct == COMMUNITY_PERMIT)
|
||||||
|
{
|
||||||
|
com_index_to_delete[delete_index] = i;
|
||||||
|
delete_index++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete all of the communities we flagged for deletion */
|
||||||
|
ptr = lcom->val;
|
||||||
|
for (i = delete_index-1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
ptr += (com_index_to_delete[i] * LCOMMUNITY_SIZE);
|
||||||
|
lcommunity_del_val (lcom, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lcom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set lcommunity-list. */
|
||||||
|
int
|
||||||
|
lcommunity_list_set (struct community_list_handler *ch,
|
||||||
|
const char *name, const char *str, int direct, int style)
|
||||||
|
{
|
||||||
|
struct community_entry *entry = NULL;
|
||||||
|
struct community_list *list;
|
||||||
|
struct lcommunity *lcom = NULL;
|
||||||
|
regex_t *regex = NULL;
|
||||||
|
|
||||||
|
/* Get community list. */
|
||||||
|
list = community_list_get (ch, name, LARGE_COMMUNITY_LIST_MASTER);
|
||||||
|
|
||||||
|
/* When community-list already has entry, new entry should have same
|
||||||
|
style. If you want to have mixed style community-list, you can
|
||||||
|
comment out this check. */
|
||||||
|
if (!community_list_empty_p (list))
|
||||||
|
{
|
||||||
|
struct community_entry *first;
|
||||||
|
|
||||||
|
first = list->head;
|
||||||
|
|
||||||
|
if (style != first->style)
|
||||||
|
{
|
||||||
|
return (first->style == COMMUNITY_LIST_STANDARD
|
||||||
|
? COMMUNITY_LIST_ERR_STANDARD_CONFLICT
|
||||||
|
: COMMUNITY_LIST_ERR_EXPANDED_CONFLICT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str)
|
||||||
|
{
|
||||||
|
if (style == LARGE_COMMUNITY_LIST_STANDARD)
|
||||||
|
lcom = lcommunity_str2com (str);
|
||||||
|
else
|
||||||
|
regex = bgp_regcomp (str);
|
||||||
|
|
||||||
|
if (! lcom && ! regex)
|
||||||
|
return COMMUNITY_LIST_ERR_MALFORMED_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = community_entry_new ();
|
||||||
|
entry->direct = direct;
|
||||||
|
entry->style = style;
|
||||||
|
entry->any = (str ? 0 : 1);
|
||||||
|
entry->u.lcom = lcom;
|
||||||
|
entry->reg = regex;
|
||||||
|
if (lcom)
|
||||||
|
entry->config = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_COMMUNITY_LIST);
|
||||||
|
else if (regex)
|
||||||
|
entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str);
|
||||||
|
else
|
||||||
|
entry->config = NULL;
|
||||||
|
|
||||||
|
/* Do not put duplicated community entry. */
|
||||||
|
if (community_list_dup_check (list, entry))
|
||||||
|
community_entry_free (entry);
|
||||||
|
else
|
||||||
|
community_list_entry_add (list, entry);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unset community-list. When str is NULL, delete all of
|
||||||
|
community-list entry belongs to the specified name. */
|
||||||
|
int
|
||||||
|
lcommunity_list_unset (struct community_list_handler *ch,
|
||||||
|
const char *name, const char *str,
|
||||||
|
int direct, int style)
|
||||||
|
{
|
||||||
|
struct community_entry *entry = NULL;
|
||||||
|
struct community_list *list;
|
||||||
|
struct lcommunity *lcom = NULL;
|
||||||
|
regex_t *regex = NULL;
|
||||||
|
|
||||||
|
/* Lookup community list. */
|
||||||
|
list = community_list_lookup (ch, name, LARGE_COMMUNITY_LIST_MASTER);
|
||||||
|
if (list == NULL)
|
||||||
|
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
|
||||||
|
|
||||||
|
/* Delete all of entry belongs to this community-list. */
|
||||||
|
if (!str)
|
||||||
|
{
|
||||||
|
community_list_delete (list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (style == LARGE_COMMUNITY_LIST_STANDARD)
|
||||||
|
lcom = lcommunity_str2com (str);
|
||||||
|
else
|
||||||
|
regex = bgp_regcomp (str);
|
||||||
|
|
||||||
|
if (! lcom && ! regex)
|
||||||
|
return COMMUNITY_LIST_ERR_MALFORMED_VAL;
|
||||||
|
|
||||||
|
if (lcom)
|
||||||
|
entry = community_list_entry_lookup (list, lcom, direct);
|
||||||
|
else
|
||||||
|
entry = community_list_entry_lookup (list, str, direct);
|
||||||
|
|
||||||
|
if (lcom)
|
||||||
|
lcommunity_free (&lcom);
|
||||||
|
if (regex)
|
||||||
|
bgp_regex_free (regex);
|
||||||
|
|
||||||
|
if (!entry)
|
||||||
|
return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
|
||||||
|
|
||||||
|
community_list_entry_delete (list, entry, style);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set extcommunity-list. */
|
/* Set extcommunity-list. */
|
||||||
int
|
int
|
||||||
extcommunity_list_set (struct community_list_handler *ch,
|
extcommunity_list_set (struct community_list_handler *ch,
|
||||||
|
@ -959,6 +1265,12 @@ community_list_terminate (struct community_list_handler *ch)
|
||||||
while ((list = cm->str.head) != NULL)
|
while ((list = cm->str.head) != NULL)
|
||||||
community_list_delete (list);
|
community_list_delete (list);
|
||||||
|
|
||||||
|
cm = &ch->lcommunity_list;
|
||||||
|
while ((list = cm->num.head) != NULL)
|
||||||
|
community_list_delete (list);
|
||||||
|
while ((list = cm->str.head) != NULL)
|
||||||
|
community_list_delete (list);
|
||||||
|
|
||||||
cm = &ch->extcommunity_list;
|
cm = &ch->extcommunity_list;
|
||||||
while ((list = cm->num.head) != NULL)
|
while ((list = cm->num.head) != NULL)
|
||||||
community_list_delete (list);
|
community_list_delete (list);
|
||||||
|
|
|
@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
/* Master Community-list. */
|
/* Master Community-list. */
|
||||||
#define COMMUNITY_LIST_MASTER 0
|
#define COMMUNITY_LIST_MASTER 0
|
||||||
#define EXTCOMMUNITY_LIST_MASTER 1
|
#define EXTCOMMUNITY_LIST_MASTER 1
|
||||||
|
#define LARGE_COMMUNITY_LIST_MASTER 2
|
||||||
|
|
||||||
/* Community-list deny and permit. */
|
/* Community-list deny and permit. */
|
||||||
#define COMMUNITY_DENY 0
|
#define COMMUNITY_DENY 0
|
||||||
|
@ -38,6 +39,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
#define COMMUNITY_LIST_EXPANDED 1 /* Expanded community-list. */
|
#define COMMUNITY_LIST_EXPANDED 1 /* Expanded community-list. */
|
||||||
#define EXTCOMMUNITY_LIST_STANDARD 2 /* Standard extcommunity-list. */
|
#define EXTCOMMUNITY_LIST_STANDARD 2 /* Standard extcommunity-list. */
|
||||||
#define EXTCOMMUNITY_LIST_EXPANDED 3 /* Expanded extcommunity-list. */
|
#define EXTCOMMUNITY_LIST_EXPANDED 3 /* Expanded extcommunity-list. */
|
||||||
|
#define LARGE_COMMUNITY_LIST_STANDARD 4 /* Standard Large community-list. */
|
||||||
|
#define LARGE_COMMUNITY_LIST_EXPANDED 5 /* Expanded Large community-list. */
|
||||||
|
|
||||||
/* Community-list. */
|
/* Community-list. */
|
||||||
struct community_list
|
struct community_list
|
||||||
|
@ -80,6 +83,7 @@ struct community_entry
|
||||||
{
|
{
|
||||||
struct community *com;
|
struct community *com;
|
||||||
struct ecommunity *ecom;
|
struct ecommunity *ecom;
|
||||||
|
struct lcommunity *lcom;
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
/* Configuration string. */
|
/* Configuration string. */
|
||||||
|
@ -112,6 +116,9 @@ struct community_list_handler
|
||||||
|
|
||||||
/* Exteded community-list. */
|
/* Exteded community-list. */
|
||||||
struct community_list_master extcommunity_list;
|
struct community_list_master extcommunity_list;
|
||||||
|
|
||||||
|
/* Large community-list. */
|
||||||
|
struct community_list_master lcommunity_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Error code of community-list. */
|
/* Error code of community-list. */
|
||||||
|
@ -139,6 +146,12 @@ extern int extcommunity_list_set (struct community_list_handler *ch,
|
||||||
extern int extcommunity_list_unset (struct community_list_handler *ch,
|
extern int extcommunity_list_unset (struct community_list_handler *ch,
|
||||||
const char *name, const char *str,
|
const char *name, const char *str,
|
||||||
int direct, int style, int delete_all);
|
int direct, int style, int delete_all);
|
||||||
|
extern int lcommunity_list_set (struct community_list_handler *ch,
|
||||||
|
const char *name, const char *str,
|
||||||
|
int direct, int style);
|
||||||
|
extern int lcommunity_list_unset (struct community_list_handler *ch,
|
||||||
|
const char *name, const char *str,
|
||||||
|
int direct, int style);
|
||||||
|
|
||||||
extern struct community_list_master *
|
extern struct community_list_master *
|
||||||
community_list_master_lookup (struct community_list_handler *, int);
|
community_list_master_lookup (struct community_list_handler *, int);
|
||||||
|
@ -148,9 +161,12 @@ community_list_lookup (struct community_list_handler *, const char *, int);
|
||||||
|
|
||||||
extern int community_list_match (struct community *, struct community_list *);
|
extern int community_list_match (struct community *, struct community_list *);
|
||||||
extern int ecommunity_list_match (struct ecommunity *, struct community_list *);
|
extern int ecommunity_list_match (struct ecommunity *, struct community_list *);
|
||||||
|
extern int lcommunity_list_match (struct lcommunity *, struct community_list *);
|
||||||
extern int community_list_exact_match (struct community *,
|
extern int community_list_exact_match (struct community *,
|
||||||
struct community_list *);
|
struct community_list *);
|
||||||
extern struct community *
|
extern struct community *
|
||||||
community_list_match_delete (struct community *, struct community_list *);
|
community_list_match_delete (struct community *, struct community_list *);
|
||||||
|
extern struct lcommunity *
|
||||||
|
lcommunity_list_match_delete (struct lcommunity *lcom,
|
||||||
|
struct community_list *list);
|
||||||
#endif /* _QUAGGA_BGP_CLIST_H */
|
#endif /* _QUAGGA_BGP_CLIST_H */
|
||||||
|
|
|
@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
|
||||||
#include "bgpd/bgpd.h"
|
#include "bgpd/bgpd.h"
|
||||||
#include "bgpd/bgp_ecommunity.h"
|
#include "bgpd/bgp_ecommunity.h"
|
||||||
|
#include "bgpd/bgp_lcommunity.h"
|
||||||
#include "bgpd/bgp_aspath.h"
|
#include "bgpd/bgp_aspath.h"
|
||||||
|
|
||||||
/* Hash of community attribute. */
|
/* Hash of community attribute. */
|
||||||
|
|
|
@ -41,6 +41,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
#include "bgpd/bgp_route.h"
|
#include "bgpd/bgp_route.h"
|
||||||
#include "bgpd/bgp_attr.h"
|
#include "bgpd/bgp_attr.h"
|
||||||
#include "bgpd/bgp_ecommunity.h"
|
#include "bgpd/bgp_ecommunity.h"
|
||||||
|
#include "bgpd/bgp_lcommunity.h"
|
||||||
#include "bgpd/bgp_mplsvpn.h"
|
#include "bgpd/bgp_mplsvpn.h"
|
||||||
#include "bgpd/bgp_vty.h"
|
#include "bgpd/bgp_vty.h"
|
||||||
#include "bgpd/bgp_encap.h"
|
#include "bgpd/bgp_encap.h"
|
||||||
|
|
563
bgpd/bgp_lcommunity.c
Normal file
563
bgpd/bgp_lcommunity.c
Normal file
|
@ -0,0 +1,563 @@
|
||||||
|
/* BGP Large Communities Attribute
|
||||||
|
|
||||||
|
Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
|
||||||
|
|
||||||
|
This file is part of GNU Zebra.
|
||||||
|
|
||||||
|
GNU Zebra is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by the
|
||||||
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
|
later version.
|
||||||
|
|
||||||
|
GNU Zebra is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with GNU Zebra; see the file COPYING. If not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
02111-1307, USA. */
|
||||||
|
|
||||||
|
#include <zebra.h>
|
||||||
|
|
||||||
|
#include "hash.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "prefix.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "filter.h"
|
||||||
|
|
||||||
|
#include "bgpd/bgpd.h"
|
||||||
|
#include "bgpd/bgp_lcommunity.h"
|
||||||
|
#include "bgpd/bgp_aspath.h"
|
||||||
|
|
||||||
|
/* Hash of community attribute. */
|
||||||
|
static struct hash *lcomhash;
|
||||||
|
|
||||||
|
/* Allocate a new lcommunities. */
|
||||||
|
static struct lcommunity *
|
||||||
|
lcommunity_new (void)
|
||||||
|
{
|
||||||
|
return (struct lcommunity *) XCALLOC (MTYPE_LCOMMUNITY,
|
||||||
|
sizeof (struct lcommunity));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate lcommunities. */
|
||||||
|
void
|
||||||
|
lcommunity_free (struct lcommunity **lcom)
|
||||||
|
{
|
||||||
|
if ((*lcom)->val)
|
||||||
|
XFREE (MTYPE_LCOMMUNITY_VAL, (*lcom)->val);
|
||||||
|
if ((*lcom)->str)
|
||||||
|
XFREE (MTYPE_LCOMMUNITY_STR, (*lcom)->str);
|
||||||
|
XFREE (MTYPE_LCOMMUNITY, *lcom);
|
||||||
|
lcom = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a new Large Communities value to Large Communities
|
||||||
|
Attribute structure. When the value is already exists in the
|
||||||
|
structure, we don't add the value. Newly added value is sorted by
|
||||||
|
numerical order. When the value is added to the structure return 1
|
||||||
|
else return 0. */
|
||||||
|
static int
|
||||||
|
lcommunity_add_val (struct lcommunity *lcom, struct lcommunity_val *lval)
|
||||||
|
{
|
||||||
|
u_int8_t *p;
|
||||||
|
int ret;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
/* When this is fist value, just add it. */
|
||||||
|
if (lcom->val == NULL)
|
||||||
|
{
|
||||||
|
lcom->size++;
|
||||||
|
lcom->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom_length (lcom));
|
||||||
|
memcpy (lcom->val, lval->val, LCOMMUNITY_SIZE);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the value already exists in the structure return 0. */
|
||||||
|
c = 0;
|
||||||
|
for (p = lcom->val; c < lcom->size; p += LCOMMUNITY_SIZE, c++)
|
||||||
|
{
|
||||||
|
ret = memcmp (p, lval->val, LCOMMUNITY_SIZE);
|
||||||
|
if (ret == 0)
|
||||||
|
return 0;
|
||||||
|
if (ret > 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the value to the structure with numerical sorting. */
|
||||||
|
lcom->size++;
|
||||||
|
lcom->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom->val, lcom_length (lcom));
|
||||||
|
|
||||||
|
memmove (lcom->val + (c + 1) * LCOMMUNITY_SIZE,
|
||||||
|
lcom->val + c * LCOMMUNITY_SIZE,
|
||||||
|
(lcom->size - 1 - c) * LCOMMUNITY_SIZE);
|
||||||
|
memcpy (lcom->val + c * LCOMMUNITY_SIZE, lval->val, LCOMMUNITY_SIZE);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function takes pointer to Large Communites strucutre then
|
||||||
|
create a new Large Communities structure by uniq and sort each
|
||||||
|
Large Communities value. */
|
||||||
|
struct lcommunity *
|
||||||
|
lcommunity_uniq_sort (struct lcommunity *lcom)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct lcommunity *new;
|
||||||
|
struct lcommunity_val *lval;
|
||||||
|
|
||||||
|
if (! lcom)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
new = lcommunity_new ();
|
||||||
|
|
||||||
|
for (i = 0; i < lcom->size; i++)
|
||||||
|
{
|
||||||
|
lval = (struct lcommunity_val *) (lcom->val + (i * LCOMMUNITY_SIZE));
|
||||||
|
lcommunity_add_val (new, lval);
|
||||||
|
}
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse Large Communites Attribute in BGP packet. */
|
||||||
|
struct lcommunity *
|
||||||
|
lcommunity_parse (u_int8_t *pnt, u_short length)
|
||||||
|
{
|
||||||
|
struct lcommunity tmp;
|
||||||
|
struct lcommunity *new;
|
||||||
|
|
||||||
|
/* Length check. */
|
||||||
|
if (length % LCOMMUNITY_SIZE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Prepare tmporary structure for making a new Large Communities
|
||||||
|
Attribute. */
|
||||||
|
tmp.size = length / LCOMMUNITY_SIZE;
|
||||||
|
tmp.val = pnt;
|
||||||
|
|
||||||
|
/* Create a new Large Communities Attribute by uniq and sort each
|
||||||
|
Large Communities value */
|
||||||
|
new = lcommunity_uniq_sort (&tmp);
|
||||||
|
|
||||||
|
return lcommunity_intern (new);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Duplicate the Large Communities Attribute structure. */
|
||||||
|
struct lcommunity *
|
||||||
|
lcommunity_dup (struct lcommunity *lcom)
|
||||||
|
{
|
||||||
|
struct lcommunity *new;
|
||||||
|
|
||||||
|
new = XCALLOC (MTYPE_LCOMMUNITY, sizeof (struct lcommunity));
|
||||||
|
new->size = lcom->size;
|
||||||
|
if (new->size)
|
||||||
|
{
|
||||||
|
new->val = XMALLOC (MTYPE_LCOMMUNITY_VAL, lcom->size * LCOMMUNITY_SIZE);
|
||||||
|
memcpy (new->val, lcom->val, lcom->size * LCOMMUNITY_SIZE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
new->val = NULL;
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrun string representation of communities attribute. */
|
||||||
|
char *
|
||||||
|
lcommunity_str (struct lcommunity *lcom)
|
||||||
|
{
|
||||||
|
if (! lcom->str)
|
||||||
|
lcom->str = lcommunity_lcom2str (lcom, LCOMMUNITY_FORMAT_DISPLAY);
|
||||||
|
return lcom->str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Merge two Large Communities Attribute structure. */
|
||||||
|
struct lcommunity *
|
||||||
|
lcommunity_merge (struct lcommunity *lcom1, struct lcommunity *lcom2)
|
||||||
|
{
|
||||||
|
if (lcom1->val)
|
||||||
|
lcom1->val = XREALLOC (MTYPE_LCOMMUNITY_VAL, lcom1->val,
|
||||||
|
(lcom1->size + lcom2->size) * LCOMMUNITY_SIZE);
|
||||||
|
else
|
||||||
|
lcom1->val = XMALLOC (MTYPE_LCOMMUNITY_VAL,
|
||||||
|
(lcom1->size + lcom2->size) * LCOMMUNITY_SIZE);
|
||||||
|
|
||||||
|
memcpy (lcom1->val + (lcom1->size * LCOMMUNITY_SIZE),
|
||||||
|
lcom2->val, lcom2->size * LCOMMUNITY_SIZE);
|
||||||
|
lcom1->size += lcom2->size;
|
||||||
|
|
||||||
|
return lcom1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Intern Large Communities Attribute. */
|
||||||
|
struct lcommunity *
|
||||||
|
lcommunity_intern (struct lcommunity *lcom)
|
||||||
|
{
|
||||||
|
struct lcommunity *find;
|
||||||
|
|
||||||
|
assert (lcom->refcnt == 0);
|
||||||
|
|
||||||
|
find = (struct lcommunity *) hash_get (lcomhash, lcom, hash_alloc_intern);
|
||||||
|
|
||||||
|
if (find != lcom)
|
||||||
|
lcommunity_free (&lcom);
|
||||||
|
|
||||||
|
find->refcnt++;
|
||||||
|
|
||||||
|
if (! find->str)
|
||||||
|
find->str = lcommunity_lcom2str (find, LCOMMUNITY_FORMAT_DISPLAY);
|
||||||
|
|
||||||
|
return find;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unintern Large Communities Attribute. */
|
||||||
|
void
|
||||||
|
lcommunity_unintern (struct lcommunity **lcom)
|
||||||
|
{
|
||||||
|
struct lcommunity *ret;
|
||||||
|
|
||||||
|
if ((*lcom)->refcnt)
|
||||||
|
(*lcom)->refcnt--;
|
||||||
|
|
||||||
|
/* Pull off from hash. */
|
||||||
|
if ((*lcom)->refcnt == 0)
|
||||||
|
{
|
||||||
|
/* Large community must be in the hash. */
|
||||||
|
ret = (struct lcommunity *) hash_release (lcomhash, *lcom);
|
||||||
|
assert (ret != NULL);
|
||||||
|
|
||||||
|
lcommunity_free (lcom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Utility function to make hash key. */
|
||||||
|
unsigned int
|
||||||
|
lcommunity_hash_make (void *arg)
|
||||||
|
{
|
||||||
|
const struct lcommunity *lcom = arg;
|
||||||
|
int size = lcom->size * LCOMMUNITY_SIZE;
|
||||||
|
u_int8_t *pnt = lcom->val;
|
||||||
|
unsigned int key = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
for (c = 0; c < size; c += LCOMMUNITY_SIZE)
|
||||||
|
{
|
||||||
|
key += pnt[c];
|
||||||
|
key += pnt[c + 1];
|
||||||
|
key += pnt[c + 2];
|
||||||
|
key += pnt[c + 3];
|
||||||
|
key += pnt[c + 4];
|
||||||
|
key += pnt[c + 5];
|
||||||
|
key += pnt[c + 6];
|
||||||
|
key += pnt[c + 7];
|
||||||
|
key += pnt[c + 8];
|
||||||
|
key += pnt[c + 9];
|
||||||
|
key += pnt[c + 10];
|
||||||
|
key += pnt[c + 11];
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compare two Large Communities Attribute structure. */
|
||||||
|
int
|
||||||
|
lcommunity_cmp (const void *arg1, const void *arg2)
|
||||||
|
{
|
||||||
|
const struct lcommunity *lcom1 = arg1;
|
||||||
|
const struct lcommunity *lcom2 = arg2;
|
||||||
|
|
||||||
|
return (lcom1->size == lcom2->size
|
||||||
|
&& memcmp (lcom1->val, lcom2->val, lcom1->size * LCOMMUNITY_SIZE) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return communities hash. */
|
||||||
|
struct hash *
|
||||||
|
lcommunity_hash (void)
|
||||||
|
{
|
||||||
|
return lcomhash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize Large Comminities related hash. */
|
||||||
|
void
|
||||||
|
lcommunity_init (void)
|
||||||
|
{
|
||||||
|
lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lcommunity_finish (void)
|
||||||
|
{
|
||||||
|
hash_free (lcomhash);
|
||||||
|
lcomhash = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Large Communities token enum. */
|
||||||
|
enum lcommunity_token
|
||||||
|
{
|
||||||
|
lcommunity_token_unknown = 0,
|
||||||
|
lcommunity_token_val,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Get next Large Communities token from the string. */
|
||||||
|
static const char *
|
||||||
|
lcommunity_gettoken (const char *str, struct lcommunity_val *lval,
|
||||||
|
enum lcommunity_token *token)
|
||||||
|
{
|
||||||
|
const char *p = str;
|
||||||
|
|
||||||
|
/* Skip white space. */
|
||||||
|
while (isspace ((int) *p))
|
||||||
|
{
|
||||||
|
p++;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the end of the line. */
|
||||||
|
if (*p == '\0')
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Community value. */
|
||||||
|
if (isdigit ((int) *p))
|
||||||
|
{
|
||||||
|
int separator = 0;
|
||||||
|
int digit = 0;
|
||||||
|
u_int32_t globaladmin = 0;
|
||||||
|
u_int32_t localdata1 = 0;
|
||||||
|
u_int32_t localdata2 = 0;
|
||||||
|
|
||||||
|
while (isdigit ((int) *p) || *p == ':')
|
||||||
|
{
|
||||||
|
if (*p == ':')
|
||||||
|
{
|
||||||
|
if (separator == 2)
|
||||||
|
{
|
||||||
|
*token = lcommunity_token_unknown;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
separator++;
|
||||||
|
digit = 0;
|
||||||
|
if (separator == 1) {
|
||||||
|
globaladmin = localdata2;
|
||||||
|
} else {
|
||||||
|
localdata1 = localdata2;
|
||||||
|
}
|
||||||
|
localdata2 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
digit = 1;
|
||||||
|
localdata2 *= 10;
|
||||||
|
localdata2 += (*p - '0');
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
if (! digit)
|
||||||
|
{
|
||||||
|
*token = lcommunity_token_unknown;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy the large comm.
|
||||||
|
*/
|
||||||
|
lval->val[0] = (globaladmin >> 24) & 0xff;
|
||||||
|
lval->val[1] = (globaladmin >> 16) & 0xff;
|
||||||
|
lval->val[2] = (globaladmin >> 8) & 0xff;
|
||||||
|
lval->val[3] = globaladmin & 0xff;
|
||||||
|
lval->val[4] = (localdata1 >> 24) & 0xff;
|
||||||
|
lval->val[5] = (localdata1 >> 16) & 0xff;
|
||||||
|
lval->val[6] = (localdata1 >> 8) & 0xff;
|
||||||
|
lval->val[7] = localdata1 & 0xff;
|
||||||
|
lval->val[8] = (localdata2 >> 24) & 0xff;
|
||||||
|
lval->val[9] = (localdata2 >> 16) & 0xff;
|
||||||
|
lval->val[10] = (localdata2 >> 8) & 0xff;
|
||||||
|
lval->val[11] = localdata2 & 0xff;
|
||||||
|
|
||||||
|
*token = lcommunity_token_val;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
*token = lcommunity_token_unknown;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert string to large community attribute.
|
||||||
|
When type is already known, please specify both str and type.
|
||||||
|
|
||||||
|
When string includes keyword for each large community value.
|
||||||
|
Please specify keyword_included as non-zero value.
|
||||||
|
*/
|
||||||
|
struct lcommunity *
|
||||||
|
lcommunity_str2com (const char *str)
|
||||||
|
{
|
||||||
|
struct lcommunity *lcom = NULL;
|
||||||
|
enum lcommunity_token token = lcommunity_token_unknown;
|
||||||
|
struct lcommunity_val lval;
|
||||||
|
|
||||||
|
while ((str = lcommunity_gettoken (str, &lval, &token)))
|
||||||
|
{
|
||||||
|
switch (token)
|
||||||
|
{
|
||||||
|
case lcommunity_token_val:
|
||||||
|
if (lcom == NULL)
|
||||||
|
lcom = lcommunity_new ();
|
||||||
|
lcommunity_add_val (lcom, &lval);
|
||||||
|
break;
|
||||||
|
case lcommunity_token_unknown:
|
||||||
|
default:
|
||||||
|
if (lcom)
|
||||||
|
lcommunity_free (&lcom);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lcom;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lcommunity_include (struct lcommunity *lcom, u_char *ptr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u_char *lcom_ptr;
|
||||||
|
|
||||||
|
lcom_ptr = lcom->val;
|
||||||
|
for (i = 0; i < lcom->size; i++) {
|
||||||
|
lcom_ptr += (i * LCOMMUNITY_SIZE);
|
||||||
|
if (memcmp (ptr, lcom_ptr, LCOMMUNITY_SIZE) == 0)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert large community attribute to string.
|
||||||
|
The large coms will be in 65535:65531:0 format.
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
lcommunity_lcom2str (struct lcommunity *lcom, int format)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u_int8_t *pnt;
|
||||||
|
#define LCOMMUNITY_STR_DEFAULT_LEN 40
|
||||||
|
int str_size;
|
||||||
|
int str_pnt;
|
||||||
|
char *str_buf;
|
||||||
|
int len = 0;
|
||||||
|
int first = 1;
|
||||||
|
u_int32_t globaladmin, localdata1, localdata2;
|
||||||
|
|
||||||
|
if (lcom->size == 0)
|
||||||
|
{
|
||||||
|
str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, 1);
|
||||||
|
str_buf[0] = '\0';
|
||||||
|
return str_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare buffer. */
|
||||||
|
str_buf = XMALLOC (MTYPE_LCOMMUNITY_STR, LCOMMUNITY_STR_DEFAULT_LEN + 1);
|
||||||
|
str_size = LCOMMUNITY_STR_DEFAULT_LEN + 1;
|
||||||
|
str_pnt = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < lcom->size; i++)
|
||||||
|
{
|
||||||
|
/* Make it sure size is enough. */
|
||||||
|
while (str_pnt + LCOMMUNITY_STR_DEFAULT_LEN >= str_size)
|
||||||
|
{
|
||||||
|
str_size *= 2;
|
||||||
|
str_buf = XREALLOC (MTYPE_LCOMMUNITY_STR, str_buf, str_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Space between each value. */
|
||||||
|
if (! first)
|
||||||
|
str_buf[str_pnt++] = ' ';
|
||||||
|
|
||||||
|
pnt = lcom->val + (i * 12);
|
||||||
|
|
||||||
|
globaladmin = (*pnt++ << 24);
|
||||||
|
globaladmin |= (*pnt++ << 16);
|
||||||
|
globaladmin |= (*pnt++ << 8);
|
||||||
|
globaladmin |= (*pnt++);
|
||||||
|
|
||||||
|
localdata1 = (*pnt++ << 24);
|
||||||
|
localdata1 |= (*pnt++ << 16);
|
||||||
|
localdata1 |= (*pnt++ << 8);
|
||||||
|
localdata1 |= (*pnt++);
|
||||||
|
|
||||||
|
localdata2 = (*pnt++ << 24);
|
||||||
|
localdata2 |= (*pnt++ << 16);
|
||||||
|
localdata2 |= (*pnt++ << 8);
|
||||||
|
localdata2 |= (*pnt++);
|
||||||
|
|
||||||
|
len = sprintf( str_buf + str_pnt, "%u:%u:%u", globaladmin,
|
||||||
|
localdata1, localdata2);
|
||||||
|
str_pnt += len;
|
||||||
|
first = 0;
|
||||||
|
}
|
||||||
|
return str_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
lcommunity_match (const struct lcommunity *lcom1,
|
||||||
|
const struct lcommunity *lcom2)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
if (lcom1 == NULL && lcom2 == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (lcom1 == NULL || lcom2 == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (lcom1->size < lcom2->size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Every community on com2 needs to be on com1 for this to match */
|
||||||
|
while (i < lcom1->size && j < lcom2->size)
|
||||||
|
{
|
||||||
|
if (memcmp (lcom1->val + (i*12), lcom2->val + (j*12), LCOMMUNITY_SIZE) == 0)
|
||||||
|
j++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == lcom2->size)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete one lcommunity. */
|
||||||
|
void
|
||||||
|
lcommunity_del_val (struct lcommunity *lcom, u_char *ptr)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int c = 0;
|
||||||
|
|
||||||
|
if (! lcom->val)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (i < lcom->size)
|
||||||
|
{
|
||||||
|
if (memcmp (lcom->val + i*LCOMMUNITY_SIZE, ptr, LCOMMUNITY_SIZE) == 0)
|
||||||
|
{
|
||||||
|
c = lcom->size -i -1;
|
||||||
|
|
||||||
|
if (c > 0)
|
||||||
|
memmove (lcom->val + i*LCOMMUNITY_SIZE, lcom->val + (i + 1)*LCOMMUNITY_SIZE, c * LCOMMUNITY_SIZE);
|
||||||
|
|
||||||
|
lcom->size--;
|
||||||
|
|
||||||
|
if (lcom->size > 0)
|
||||||
|
lcom->val = XREALLOC (MTYPE_COMMUNITY_VAL, lcom->val,
|
||||||
|
lcom_length (lcom));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XFREE (MTYPE_COMMUNITY_VAL, lcom->val);
|
||||||
|
lcom->val = NULL;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
75
bgpd/bgp_lcommunity.h
Normal file
75
bgpd/bgp_lcommunity.h
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/* BGP Large Communities Attribute.
|
||||||
|
|
||||||
|
Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
|
||||||
|
|
||||||
|
This file is part of GNU Zebra.
|
||||||
|
|
||||||
|
GNU Zebra is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU General Public License as published by the
|
||||||
|
Free Software Foundation; either version 2, or (at your option) any
|
||||||
|
later version.
|
||||||
|
|
||||||
|
GNU Zebra is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with GNU Zebra; see the file COPYING. If not, write to the Free
|
||||||
|
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
02111-1307, USA. */
|
||||||
|
|
||||||
|
#ifndef _QUAGGA_BGP_LCOMMUNITY_H
|
||||||
|
#define _QUAGGA_BGP_LCOMMUNITY_H
|
||||||
|
|
||||||
|
/* Extended communities attribute string format. */
|
||||||
|
#define LCOMMUNITY_FORMAT_ROUTE_MAP 0
|
||||||
|
#define LCOMMUNITY_FORMAT_COMMUNITY_LIST 1
|
||||||
|
#define LCOMMUNITY_FORMAT_DISPLAY 2
|
||||||
|
|
||||||
|
/* Large Communities value is twelve octets long. */
|
||||||
|
#define LCOMMUNITY_SIZE 12
|
||||||
|
|
||||||
|
/* Large Communities attribute. */
|
||||||
|
struct lcommunity
|
||||||
|
{
|
||||||
|
/* Reference counter. */
|
||||||
|
unsigned long refcnt;
|
||||||
|
|
||||||
|
/* Size of Extended Communities attribute. */
|
||||||
|
int size;
|
||||||
|
|
||||||
|
/* Extended Communities value. */
|
||||||
|
u_int8_t *val;
|
||||||
|
|
||||||
|
/* Human readable format string. */
|
||||||
|
char *str;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Extended community value is eight octet. */
|
||||||
|
struct lcommunity_val
|
||||||
|
{
|
||||||
|
char val[LCOMMUNITY_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define lcom_length(X) ((X)->size * LCOMMUNITY_SIZE)
|
||||||
|
|
||||||
|
extern void lcommunity_init (void);
|
||||||
|
extern void lcommunity_finish (void);
|
||||||
|
extern void lcommunity_free (struct lcommunity **);
|
||||||
|
extern struct lcommunity *lcommunity_parse (u_int8_t *, u_short);
|
||||||
|
extern struct lcommunity *lcommunity_dup (struct lcommunity *);
|
||||||
|
extern struct lcommunity *lcommunity_merge (struct lcommunity *, struct lcommunity *);
|
||||||
|
extern struct lcommunity *lcommunity_uniq_sort (struct lcommunity *);
|
||||||
|
extern struct lcommunity *lcommunity_intern (struct lcommunity *);
|
||||||
|
extern int lcommunity_cmp (const void *, const void *);
|
||||||
|
extern void lcommunity_unintern (struct lcommunity **);
|
||||||
|
extern unsigned int lcommunity_hash_make (void *);
|
||||||
|
extern struct hash *lcommunity_hash (void);
|
||||||
|
extern struct lcommunity *lcommunity_str2com (const char *);
|
||||||
|
extern char *lcommunity_lcom2str (struct lcommunity *, int);
|
||||||
|
extern int lcommunity_match (const struct lcommunity *, const struct lcommunity *);
|
||||||
|
extern char *lcommunity_str (struct lcommunity *);
|
||||||
|
extern int lcommunity_include (struct lcommunity *lcom, u_char *ptr);
|
||||||
|
extern void lcommunity_del_val (struct lcommunity *lcom, u_char *ptr);
|
||||||
|
#endif /* _QUAGGA_BGP_LCOMMUNITY_H */
|
|
@ -111,3 +111,7 @@ DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV")
|
||||||
|
|
||||||
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options")
|
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options")
|
||||||
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value")
|
DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value")
|
||||||
|
|
||||||
|
DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community")
|
||||||
|
DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string")
|
||||||
|
DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
|
||||||
|
|
|
@ -108,4 +108,7 @@ DECLARE_MTYPE(ENCAP_TLV)
|
||||||
DECLARE_MTYPE(BGP_TEA_OPTIONS)
|
DECLARE_MTYPE(BGP_TEA_OPTIONS)
|
||||||
DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE)
|
DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE)
|
||||||
|
|
||||||
|
DECLARE_MTYPE(LCOMMUNITY)
|
||||||
|
DECLARE_MTYPE(LCOMMUNITY_STR)
|
||||||
|
DECLARE_MTYPE(LCOMMUNITY_VAL)
|
||||||
#endif /* _QUAGGA_BGP_MEMORY_H */
|
#endif /* _QUAGGA_BGP_MEMORY_H */
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "bgpd/bgp_aspath.h"
|
#include "bgpd/bgp_aspath.h"
|
||||||
#include "bgpd/bgp_community.h"
|
#include "bgpd/bgp_community.h"
|
||||||
#include "bgpd/bgp_ecommunity.h"
|
#include "bgpd/bgp_ecommunity.h"
|
||||||
|
#include "bgpd/bgp_lcommunity.h"
|
||||||
#include "bgpd/bgp_mpath.h"
|
#include "bgpd/bgp_mpath.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -662,6 +663,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
|
||||||
u_char origin;
|
u_char origin;
|
||||||
struct community *community, *commerge;
|
struct community *community, *commerge;
|
||||||
struct ecommunity *ecomm, *ecommerge;
|
struct ecommunity *ecomm, *ecommerge;
|
||||||
|
struct lcommunity *lcomm, *lcommerge;
|
||||||
struct attr_extra *ae;
|
struct attr_extra *ae;
|
||||||
struct attr attr = { 0 };
|
struct attr attr = { 0 };
|
||||||
|
|
||||||
|
@ -698,6 +700,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
|
||||||
community = attr.community ? community_dup (attr.community) : NULL;
|
community = attr.community ? community_dup (attr.community) : NULL;
|
||||||
ae = attr.extra;
|
ae = attr.extra;
|
||||||
ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL;
|
ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL;
|
||||||
|
lcomm = (ae && ae->lcommunity) ? lcommunity_dup (ae->lcommunity) : NULL;
|
||||||
|
|
||||||
for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
|
for (mpinfo = bgp_info_mpath_first (new_best); mpinfo;
|
||||||
mpinfo = bgp_info_mpath_next (mpinfo))
|
mpinfo = bgp_info_mpath_next (mpinfo))
|
||||||
|
@ -733,6 +736,17 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
|
||||||
else
|
else
|
||||||
ecomm = ecommunity_dup (ae->ecommunity);
|
ecomm = ecommunity_dup (ae->ecommunity);
|
||||||
}
|
}
|
||||||
|
if (ae && ae->lcommunity)
|
||||||
|
{
|
||||||
|
if (lcomm)
|
||||||
|
{
|
||||||
|
lcommerge = lcommunity_merge (lcomm, ae->lcommunity);
|
||||||
|
lcomm = lcommunity_uniq_sort (lcommerge);
|
||||||
|
lcommunity_free (&lcommerge);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
lcomm = lcommunity_dup (ae->lcommunity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attr.aspath = aspath;
|
attr.aspath = aspath;
|
||||||
|
|
|
@ -46,6 +46,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
#include "bgpd/bgp_aspath.h"
|
#include "bgpd/bgp_aspath.h"
|
||||||
#include "bgpd/bgp_community.h"
|
#include "bgpd/bgp_community.h"
|
||||||
#include "bgpd/bgp_ecommunity.h"
|
#include "bgpd/bgp_ecommunity.h"
|
||||||
|
#include "bgpd/bgp_lcommunity.h"
|
||||||
#include "bgpd/bgp_network.h"
|
#include "bgpd/bgp_network.h"
|
||||||
#include "bgpd/bgp_mplsvpn.h"
|
#include "bgpd/bgp_mplsvpn.h"
|
||||||
#include "bgpd/bgp_encap.h"
|
#include "bgpd/bgp_encap.h"
|
||||||
|
|
122
bgpd/bgp_route.c
122
bgpd/bgp_route.c
|
@ -1,5 +1,6 @@
|
||||||
/* BGP routing information
|
/* BGP routing information
|
||||||
Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
|
Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro
|
||||||
|
Copyright (C) 2016 Job Snijders <job@instituut.net>
|
||||||
|
|
||||||
This file is part of GNU Zebra.
|
This file is part of GNU Zebra.
|
||||||
|
|
||||||
|
@ -46,6 +47,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
#include "bgpd/bgp_regex.h"
|
#include "bgpd/bgp_regex.h"
|
||||||
#include "bgpd/bgp_community.h"
|
#include "bgpd/bgp_community.h"
|
||||||
#include "bgpd/bgp_ecommunity.h"
|
#include "bgpd/bgp_ecommunity.h"
|
||||||
|
#include "bgpd/bgp_lcommunity.h"
|
||||||
#include "bgpd/bgp_clist.h"
|
#include "bgpd/bgp_clist.h"
|
||||||
#include "bgpd/bgp_packet.h"
|
#include "bgpd/bgp_packet.h"
|
||||||
#include "bgpd/bgp_filter.h"
|
#include "bgpd/bgp_filter.h"
|
||||||
|
@ -7059,7 +7061,12 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Line 6 display Originator, Cluster-id */
|
/* Line 6 display Large community */
|
||||||
|
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))
|
||||||
|
vty_out (vty, " Large Community: %s%s",
|
||||||
|
attr->extra->lcommunity->str, VTY_NEWLINE);
|
||||||
|
|
||||||
|
/* Line 7 display Originator, Cluster-id */
|
||||||
if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) ||
|
if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) ||
|
||||||
(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)))
|
(attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)))
|
||||||
{
|
{
|
||||||
|
@ -7115,7 +7122,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
|
||||||
if (binfo->extra && binfo->extra->damp_info)
|
if (binfo->extra && binfo->extra->damp_info)
|
||||||
bgp_damp_info_vty (vty, binfo, json_path);
|
bgp_damp_info_vty (vty, binfo, json_path);
|
||||||
|
|
||||||
/* Line 7 display Addpath IDs */
|
/* Line 8 display Addpath IDs */
|
||||||
if (binfo->addpath_rx_id || binfo->addpath_tx_id)
|
if (binfo->addpath_rx_id || binfo->addpath_tx_id)
|
||||||
{
|
{
|
||||||
if (json_paths)
|
if (json_paths)
|
||||||
|
@ -7170,7 +7177,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Line 8 display Uptime */
|
/* Line 9 display Uptime */
|
||||||
tbuf = time(NULL) - (bgp_clock() - binfo->uptime);
|
tbuf = time(NULL) - (bgp_clock() - binfo->uptime);
|
||||||
if (json_paths)
|
if (json_paths)
|
||||||
{
|
{
|
||||||
|
@ -7227,6 +7234,9 @@ enum bgp_show_type
|
||||||
bgp_show_type_community_exact,
|
bgp_show_type_community_exact,
|
||||||
bgp_show_type_community_list,
|
bgp_show_type_community_list,
|
||||||
bgp_show_type_community_list_exact,
|
bgp_show_type_community_list_exact,
|
||||||
|
bgp_show_type_lcommunity_all,
|
||||||
|
bgp_show_type_lcommunity,
|
||||||
|
bgp_show_type_lcommunity_list,
|
||||||
bgp_show_type_flap_statistics,
|
bgp_show_type_flap_statistics,
|
||||||
bgp_show_type_flap_neighbor,
|
bgp_show_type_flap_neighbor,
|
||||||
bgp_show_type_dampend_paths,
|
bgp_show_type_dampend_paths,
|
||||||
|
@ -7416,6 +7426,32 @@ bgp_show_table (struct vty *vty, struct bgp *bgp, struct bgp_table *table,
|
||||||
if (! community_list_exact_match (ri->attr->community, list))
|
if (! community_list_exact_match (ri->attr->community, list))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (type == bgp_show_type_community_all)
|
||||||
|
{
|
||||||
|
if (! ri->attr->community)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (type == bgp_show_type_lcommunity)
|
||||||
|
{
|
||||||
|
struct lcommunity *lcom = output_arg;
|
||||||
|
|
||||||
|
if (! ri->attr->extra || ! ri->attr->extra->lcommunity ||
|
||||||
|
! lcommunity_match (ri->attr->extra->lcommunity, lcom))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (type == bgp_show_type_lcommunity_list)
|
||||||
|
{
|
||||||
|
struct community_list *list = output_arg;
|
||||||
|
|
||||||
|
if (! ri->attr->extra ||
|
||||||
|
! lcommunity_list_match (ri->attr->extra->lcommunity, list))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (type == bgp_show_type_lcommunity_all)
|
||||||
|
{
|
||||||
|
if (! ri->attr->extra || ! ri->attr->extra->lcommunity)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (type == bgp_show_type_dampend_paths
|
if (type == bgp_show_type_dampend_paths
|
||||||
|| type == bgp_show_type_damp_neighbor)
|
|| type == bgp_show_type_damp_neighbor)
|
||||||
{
|
{
|
||||||
|
@ -7832,6 +7868,63 @@ bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str,
|
||||||
use_json);
|
use_json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bgp_show_lcommunity (struct vty *vty, struct bgp *bgp, int argc,
|
||||||
|
struct cmd_token **argv, afi_t afi, safi_t safi, u_char uj)
|
||||||
|
{
|
||||||
|
struct lcommunity *lcom;
|
||||||
|
struct buffer *b;
|
||||||
|
int i;
|
||||||
|
char *str;
|
||||||
|
int first = 0;
|
||||||
|
|
||||||
|
b = buffer_new (1024);
|
||||||
|
for (i = 0; i < argc; i++)
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
|
buffer_putc (b, ' ');
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (strmatch (argv[i]->text, "<AA:BB:CC>"))
|
||||||
|
{
|
||||||
|
first = 1;
|
||||||
|
buffer_putstr (b, argv[i]->arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer_putc (b, '\0');
|
||||||
|
|
||||||
|
str = buffer_getstr (b);
|
||||||
|
buffer_free (b);
|
||||||
|
|
||||||
|
lcom = lcommunity_str2com (str);
|
||||||
|
XFREE (MTYPE_TMP, str);
|
||||||
|
if (! lcom)
|
||||||
|
{
|
||||||
|
vty_out (vty, "%% Large-community malformed: %s", VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity, lcom, uj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bgp_show_lcommunity_list (struct vty *vty, struct bgp *bgp, const char *lcom,
|
||||||
|
afi_t afi, safi_t safi, u_char uj)
|
||||||
|
{
|
||||||
|
struct community_list *list;
|
||||||
|
|
||||||
|
list = community_list_lookup (bgp_clist, lcom, LARGE_COMMUNITY_LIST_MASTER);
|
||||||
|
if (list == NULL)
|
||||||
|
{
|
||||||
|
vty_out (vty, "%% %s is not a valid large-community-list name%s", lcom,
|
||||||
|
VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_list, list, uj);
|
||||||
|
}
|
||||||
|
|
||||||
/* BGP route print out function. */
|
/* BGP route print out function. */
|
||||||
DEFUN (show_ip_bgp_ipv4,
|
DEFUN (show_ip_bgp_ipv4,
|
||||||
show_ip_bgp_ipv4_cmd,
|
show_ip_bgp_ipv4_cmd,
|
||||||
|
@ -7844,6 +7937,8 @@ DEFUN (show_ip_bgp_ipv4,
|
||||||
|filter-list WORD\
|
|filter-list WORD\
|
||||||
|community [<AA:NN|local-AS|no-advertise|no-export> [exact-match]]\
|
|community [<AA:NN|local-AS|no-advertise|no-export> [exact-match]]\
|
||||||
|community-list <(1-500)|WORD> [exact-match]\
|
|community-list <(1-500)|WORD> [exact-match]\
|
||||||
|
|large-community [<AA:BB:CC>...]\
|
||||||
|
|large-community-list <(1-500)|WORD>\
|
||||||
|A.B.C.D/M longer-prefixes\
|
|A.B.C.D/M longer-prefixes\
|
||||||
|X:X::X:X/M longer-prefixes>\
|
|X:X::X:X/M longer-prefixes>\
|
||||||
] [json]",
|
] [json]",
|
||||||
|
@ -7878,6 +7973,14 @@ DEFUN (show_ip_bgp_ipv4,
|
||||||
"community-list number\n"
|
"community-list number\n"
|
||||||
"community-list name\n"
|
"community-list name\n"
|
||||||
"Exact match of the communities\n"
|
"Exact match of the communities\n"
|
||||||
|
"Display routes matching the large-communities\n"
|
||||||
|
"large-community number\n"
|
||||||
|
"large-community number\n"
|
||||||
|
"large-community number\n"
|
||||||
|
"large-community number\n"
|
||||||
|
"Display routes matching the large-community-list\n"
|
||||||
|
"large-community-list number\n"
|
||||||
|
"large-community-list name\n"
|
||||||
"IPv4 prefix\n"
|
"IPv4 prefix\n"
|
||||||
"Display route and more specific routes\n"
|
"Display route and more specific routes\n"
|
||||||
"IPv6 prefix\n"
|
"IPv6 prefix\n"
|
||||||
|
@ -7967,6 +8070,17 @@ DEFUN (show_ip_bgp_ipv4,
|
||||||
exact_match = 1;
|
exact_match = 1;
|
||||||
return bgp_show_community_list (vty, vrf, clist_number_or_name, exact_match, afi, safi);
|
return bgp_show_community_list (vty, vrf, clist_number_or_name, exact_match, afi, safi);
|
||||||
}
|
}
|
||||||
|
else if (strmatch(argv[idx]->text, "large-community"))
|
||||||
|
{
|
||||||
|
if (strmatch(argv[idx+1]->text, "<AA:BB:CC>"))
|
||||||
|
return bgp_show_lcommunity (vty, bgp, argc, argv, afi, safi, uj);
|
||||||
|
else
|
||||||
|
return bgp_show (vty, bgp, afi, safi, bgp_show_type_lcommunity_all, NULL, uj);
|
||||||
|
}
|
||||||
|
else if (strmatch(argv[idx]->text, "large-community-list"))
|
||||||
|
{
|
||||||
|
return bgp_show_lcommunity_list (vty, bgp, argv[idx+1]->arg, afi, safi, uj);
|
||||||
|
}
|
||||||
/* prefix-longer */
|
/* prefix-longer */
|
||||||
else if (argv[idx]->type == IPV4_TKN || argv[idx]->type == IPV6_TKN)
|
else if (argv[idx]->type == IPV4_TKN || argv[idx]->type == IPV6_TKN)
|
||||||
return bgp_show_prefix_longer (vty, vrf, argv[idx + 1]->arg, afi, safi, bgp_show_type_prefix_longer);
|
return bgp_show_prefix_longer (vty, vrf, argv[idx + 1]->arg, afi, safi, bgp_show_type_prefix_longer);
|
||||||
|
@ -10527,6 +10641,7 @@ bgp_route_init (void)
|
||||||
install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
|
install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
|
||||||
install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
|
install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
|
||||||
install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd);
|
install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd);
|
||||||
|
|
||||||
install_element (VIEW_NODE, &show_ip_bgp_instance_neighbor_advertised_route_cmd);
|
install_element (VIEW_NODE, &show_ip_bgp_instance_neighbor_advertised_route_cmd);
|
||||||
install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd);
|
install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd);
|
||||||
install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
|
install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
|
||||||
|
@ -10537,6 +10652,7 @@ bgp_route_init (void)
|
||||||
/* BGP dampening clear commands */
|
/* BGP dampening clear commands */
|
||||||
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd);
|
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd);
|
||||||
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd);
|
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd);
|
||||||
|
|
||||||
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd);
|
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd);
|
||||||
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd);
|
install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd);
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
#include "bgpd/bgp_filter.h"
|
#include "bgpd/bgp_filter.h"
|
||||||
#include "bgpd/bgp_mplsvpn.h"
|
#include "bgpd/bgp_mplsvpn.h"
|
||||||
#include "bgpd/bgp_ecommunity.h"
|
#include "bgpd/bgp_ecommunity.h"
|
||||||
|
#include "bgpd/bgp_lcommunity.h"
|
||||||
#include "bgpd/bgp_vty.h"
|
#include "bgpd/bgp_vty.h"
|
||||||
#include "bgpd/bgp_debug.h"
|
#include "bgpd/bgp_debug.h"
|
||||||
|
|
||||||
|
@ -84,6 +85,8 @@ o Cisco route-map
|
||||||
as-path tag : Not yet
|
as-path tag : Not yet
|
||||||
automatic-tag : (This will not be implemented by bgpd)
|
automatic-tag : (This will not be implemented by bgpd)
|
||||||
community : Done
|
community : Done
|
||||||
|
large-community : Done
|
||||||
|
large-comm-list : Done
|
||||||
comm-list : Not yet
|
comm-list : Not yet
|
||||||
dampning : Not yet
|
dampning : Not yet
|
||||||
default : (This will not be implemented by bgpd)
|
default : (This will not be implemented by bgpd)
|
||||||
|
@ -847,6 +850,78 @@ struct route_map_rule_cmd route_match_community_cmd =
|
||||||
route_match_community_free
|
route_match_community_free
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Match function for lcommunity match. */
|
||||||
|
static route_map_result_t
|
||||||
|
route_match_lcommunity (void *rule, struct prefix *prefix,
|
||||||
|
route_map_object_t type, void *object)
|
||||||
|
{
|
||||||
|
struct community_list *list;
|
||||||
|
struct bgp_info *bgp_info;
|
||||||
|
struct rmap_community *rcom;
|
||||||
|
|
||||||
|
if (type == RMAP_BGP)
|
||||||
|
{
|
||||||
|
bgp_info = object;
|
||||||
|
rcom = rule;
|
||||||
|
|
||||||
|
list = community_list_lookup (bgp_clist, rcom->name,
|
||||||
|
LARGE_COMMUNITY_LIST_MASTER);
|
||||||
|
if (! list)
|
||||||
|
return RMAP_NOMATCH;
|
||||||
|
|
||||||
|
if (bgp_info->attr->extra &&
|
||||||
|
lcommunity_list_match (bgp_info->attr->extra->lcommunity, list))
|
||||||
|
return RMAP_MATCH;
|
||||||
|
|
||||||
|
}
|
||||||
|
return RMAP_NOMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compile function for community match. */
|
||||||
|
static void *
|
||||||
|
route_match_lcommunity_compile (const char *arg)
|
||||||
|
{
|
||||||
|
struct rmap_community *rcom;
|
||||||
|
int len;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community));
|
||||||
|
|
||||||
|
p = strchr (arg, ' ');
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
len = p - arg;
|
||||||
|
rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
|
||||||
|
memcpy (rcom->name, arg, len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
|
||||||
|
rcom->exact = 0;
|
||||||
|
}
|
||||||
|
return rcom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compile function for community match. */
|
||||||
|
static void
|
||||||
|
route_match_lcommunity_free (void *rule)
|
||||||
|
{
|
||||||
|
struct rmap_community *rcom = rule;
|
||||||
|
|
||||||
|
XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name);
|
||||||
|
XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Route map commands for community matching. */
|
||||||
|
struct route_map_rule_cmd route_match_lcommunity_cmd =
|
||||||
|
{
|
||||||
|
"large-community",
|
||||||
|
route_match_lcommunity,
|
||||||
|
route_match_lcommunity_compile,
|
||||||
|
route_match_lcommunity_free
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Match function for extcommunity match. */
|
/* Match function for extcommunity match. */
|
||||||
static route_map_result_t
|
static route_map_result_t
|
||||||
route_match_ecommunity (void *rule, struct prefix *prefix,
|
route_match_ecommunity (void *rule, struct prefix *prefix,
|
||||||
|
@ -1544,6 +1619,225 @@ struct route_map_rule_cmd route_set_community_cmd =
|
||||||
route_set_community_free,
|
route_set_community_free,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* `set community COMMUNITY' */
|
||||||
|
struct rmap_lcom_set
|
||||||
|
{
|
||||||
|
struct lcommunity *lcom;
|
||||||
|
int additive;
|
||||||
|
int none;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* For lcommunity set mechanism. */
|
||||||
|
static route_map_result_t
|
||||||
|
route_set_lcommunity (void *rule, struct prefix *prefix,
|
||||||
|
route_map_object_t type, void *object)
|
||||||
|
{
|
||||||
|
struct rmap_lcom_set *rcs;
|
||||||
|
struct bgp_info *binfo;
|
||||||
|
struct attr *attr;
|
||||||
|
struct lcommunity *new = NULL;
|
||||||
|
struct lcommunity *old;
|
||||||
|
struct lcommunity *merge;
|
||||||
|
|
||||||
|
if (type == RMAP_BGP)
|
||||||
|
{
|
||||||
|
rcs = rule;
|
||||||
|
binfo = object;
|
||||||
|
attr = binfo->attr;
|
||||||
|
old = (attr->extra) ? attr->extra->lcommunity : NULL;
|
||||||
|
|
||||||
|
/* "none" case. */
|
||||||
|
if (rcs->none)
|
||||||
|
{
|
||||||
|
attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES));
|
||||||
|
if (attr->extra) {
|
||||||
|
attr->extra->lcommunity = NULL;
|
||||||
|
}
|
||||||
|
/* See the longer comment down below. */
|
||||||
|
if (old && old->refcnt == 0)
|
||||||
|
lcommunity_free(&old);
|
||||||
|
return RMAP_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rcs->additive && old)
|
||||||
|
{
|
||||||
|
merge = lcommunity_merge (lcommunity_dup (old), rcs->lcom);
|
||||||
|
|
||||||
|
/* HACK: if the old large-community is not intern'd,
|
||||||
|
* we should free it here, or all reference to it may be lost.
|
||||||
|
* Really need to cleanup attribute caching sometime.
|
||||||
|
*/
|
||||||
|
if (old->refcnt == 0)
|
||||||
|
lcommunity_free (&old);
|
||||||
|
new = lcommunity_uniq_sort (merge);
|
||||||
|
lcommunity_free (&merge);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
new = lcommunity_dup (rcs->lcom);
|
||||||
|
|
||||||
|
/* will be interned by caller if required */
|
||||||
|
if (attr->extra) {
|
||||||
|
attr->extra->lcommunity = new;
|
||||||
|
}
|
||||||
|
attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RMAP_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compile function for set community. */
|
||||||
|
static void *
|
||||||
|
route_set_lcommunity_compile (const char *arg)
|
||||||
|
{
|
||||||
|
struct rmap_lcom_set *rcs;
|
||||||
|
struct lcommunity *lcom = NULL;
|
||||||
|
char *sp;
|
||||||
|
int additive = 0;
|
||||||
|
int none = 0;
|
||||||
|
|
||||||
|
if (strcmp (arg, "none") == 0)
|
||||||
|
none = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sp = strstr (arg, "additive");
|
||||||
|
|
||||||
|
if (sp && sp > arg)
|
||||||
|
{
|
||||||
|
/* "additive" keyworkd is included. */
|
||||||
|
additive = 1;
|
||||||
|
*(sp - 1) = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
lcom = lcommunity_str2com (arg);
|
||||||
|
|
||||||
|
if (additive)
|
||||||
|
*(sp - 1) = ' ';
|
||||||
|
|
||||||
|
if (! lcom)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rcs = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set));
|
||||||
|
rcs->lcom = lcom;
|
||||||
|
rcs->additive = additive;
|
||||||
|
rcs->none = none;
|
||||||
|
|
||||||
|
return rcs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free function for set lcommunity. */
|
||||||
|
static void
|
||||||
|
route_set_lcommunity_free (void *rule)
|
||||||
|
{
|
||||||
|
struct rmap_lcom_set *rcs = rule;
|
||||||
|
|
||||||
|
if (rcs->lcom) {
|
||||||
|
lcommunity_free (&rcs->lcom);
|
||||||
|
}
|
||||||
|
XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set community rule structure. */
|
||||||
|
struct route_map_rule_cmd route_set_lcommunity_cmd =
|
||||||
|
{
|
||||||
|
"large-community",
|
||||||
|
route_set_lcommunity,
|
||||||
|
route_set_lcommunity_compile,
|
||||||
|
route_set_lcommunity_free,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */
|
||||||
|
|
||||||
|
/* For large community set mechanism. */
|
||||||
|
static route_map_result_t
|
||||||
|
route_set_lcommunity_delete (void *rule, struct prefix *prefix,
|
||||||
|
route_map_object_t type, void *object)
|
||||||
|
{
|
||||||
|
struct community_list *list;
|
||||||
|
struct lcommunity *merge;
|
||||||
|
struct lcommunity *new;
|
||||||
|
struct lcommunity *old;
|
||||||
|
struct bgp_info *binfo;
|
||||||
|
|
||||||
|
if (type == RMAP_BGP)
|
||||||
|
{
|
||||||
|
if (! rule)
|
||||||
|
return RMAP_OKAY;
|
||||||
|
|
||||||
|
binfo = object;
|
||||||
|
list = community_list_lookup (bgp_clist, rule,
|
||||||
|
LARGE_COMMUNITY_LIST_MASTER);
|
||||||
|
old = ((binfo->attr->extra) ? binfo->attr->extra->lcommunity : NULL);
|
||||||
|
|
||||||
|
if (list && old)
|
||||||
|
{
|
||||||
|
merge = lcommunity_list_match_delete (lcommunity_dup (old), list);
|
||||||
|
new = lcommunity_uniq_sort (merge);
|
||||||
|
lcommunity_free (&merge);
|
||||||
|
|
||||||
|
/* HACK: if the old community is not intern'd,
|
||||||
|
* we should free it here, or all reference to it may be lost.
|
||||||
|
* Really need to cleanup attribute caching sometime.
|
||||||
|
*/
|
||||||
|
if (old->refcnt == 0)
|
||||||
|
lcommunity_free (&old);
|
||||||
|
|
||||||
|
if (new->size == 0)
|
||||||
|
{
|
||||||
|
binfo->attr->extra->lcommunity = NULL;
|
||||||
|
binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
|
||||||
|
lcommunity_free (&new);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
binfo->attr->extra->lcommunity = new;
|
||||||
|
binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LARGE_COMMUNITIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RMAP_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compile function for set lcommunity. */
|
||||||
|
static void *
|
||||||
|
route_set_lcommunity_delete_compile (const char *arg)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
char *str;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
p = strchr (arg, ' ');
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
len = p - arg;
|
||||||
|
str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
|
||||||
|
memcpy (str, arg, len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
str = NULL;
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free function for set lcommunity. */
|
||||||
|
static void
|
||||||
|
route_set_lcommunity_delete_free (void *rule)
|
||||||
|
{
|
||||||
|
XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set lcommunity rule structure. */
|
||||||
|
struct route_map_rule_cmd route_set_lcommunity_delete_cmd =
|
||||||
|
{
|
||||||
|
"large-comm-list",
|
||||||
|
route_set_lcommunity_delete,
|
||||||
|
route_set_lcommunity_delete_compile,
|
||||||
|
route_set_lcommunity_delete_free,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* `set comm-list (<1-99>|<100-500>|WORD) delete' */
|
/* `set comm-list (<1-99>|<100-500>|WORD) delete' */
|
||||||
|
|
||||||
/* For community set mechanism. */
|
/* For community set mechanism. */
|
||||||
|
@ -3114,7 +3408,32 @@ DEFUN (no_match_community,
|
||||||
RMAP_EVENT_CLIST_DELETED);
|
RMAP_EVENT_CLIST_DELETED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN (match_lcommunity,
|
||||||
|
match_lcommunity_cmd,
|
||||||
|
"match large-community [(1-99)|(100-500)|WORD]",
|
||||||
|
MATCH_STR
|
||||||
|
"Match BGP large community list\n"
|
||||||
|
"Large Community-list number (standard)\n"
|
||||||
|
"Large Community-list number (expanded)\n"
|
||||||
|
"Large Community-list name\n")
|
||||||
|
{
|
||||||
|
return bgp_route_match_add (vty, "large-community", argv[2]->arg,
|
||||||
|
RMAP_EVENT_LLIST_ADDED);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (no_match_lcommunity,
|
||||||
|
no_match_lcommunity_cmd,
|
||||||
|
"no match large-community [(1-99)|(100-500)|WORD]",
|
||||||
|
NO_STR
|
||||||
|
MATCH_STR
|
||||||
|
"Match BGP large community list\n"
|
||||||
|
"Large Community-list number (standard)\n"
|
||||||
|
"Large Community-list number (expanded)\n"
|
||||||
|
"Large Community-list name\n")
|
||||||
|
{
|
||||||
|
return bgp_route_match_delete (vty, "large-community", NULL,
|
||||||
|
RMAP_EVENT_LLIST_DELETED);
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN (match_ecommunity,
|
DEFUN (match_ecommunity,
|
||||||
match_ecommunity_cmd,
|
match_ecommunity_cmd,
|
||||||
|
@ -3547,6 +3866,86 @@ DEFUN (no_set_community_delete,
|
||||||
"comm-list", NULL);
|
"comm-list", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN (set_lcommunity,
|
||||||
|
set_lcommunity_cmd,
|
||||||
|
"set large-community AA:BB:CC...",
|
||||||
|
SET_STR
|
||||||
|
"BGP large community attribute\n"
|
||||||
|
"Large Community number in aa:bb:cc format or additive\n")
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
str = argv_concat (argv, argc, 2);
|
||||||
|
ret = generic_set_add (vty, VTY_GET_CONTEXT(route_map_index), "large-community", str);
|
||||||
|
XFREE (MTYPE_TMP, str);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (set_lcommunity_none,
|
||||||
|
set_lcommunity_none_cmd,
|
||||||
|
"set large-community none",
|
||||||
|
SET_STR
|
||||||
|
"BGP large community attribute\n"
|
||||||
|
"No large community attribute\n")
|
||||||
|
{
|
||||||
|
return generic_set_add (vty, VTY_GET_CONTEXT(route_map_index),
|
||||||
|
"large-community", "none");
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (no_set_lcommunity,
|
||||||
|
no_set_lcommunity_cmd,
|
||||||
|
"no set large-community <none|[AA:BB:CC...]>",
|
||||||
|
NO_STR
|
||||||
|
SET_STR
|
||||||
|
"BGP large community attribute\n"
|
||||||
|
"No community attribute\n"
|
||||||
|
"Large community\n"
|
||||||
|
"Large community in AA:BB:CC... format or additive\n")
|
||||||
|
{
|
||||||
|
return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index),
|
||||||
|
"large-community", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DEFUN (set_lcommunity_delete,
|
||||||
|
set_lcommunity_delete_cmd,
|
||||||
|
"set large-comm-list <(1-99)|(100-500)|WORD> delete",
|
||||||
|
SET_STR
|
||||||
|
"set BGP large community list (for deletion)\n"
|
||||||
|
"Large Community-list number (standard)\n"
|
||||||
|
"Large Communitly-list number (expanded)\n"
|
||||||
|
"Large Community-list name\n"
|
||||||
|
"Delete matching large communities\n")
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
str = XCALLOC (MTYPE_TMP, strlen (argv[2]->arg) + strlen (" delete") + 1);
|
||||||
|
strcpy (str, argv[2]->arg);
|
||||||
|
strcpy (str + strlen (argv[2]->arg), " delete");
|
||||||
|
|
||||||
|
generic_set_add (vty, VTY_GET_CONTEXT(route_map_index),
|
||||||
|
"large-comm-list", str);
|
||||||
|
|
||||||
|
XFREE (MTYPE_TMP, str);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (no_set_lcommunity_delete,
|
||||||
|
no_set_lcommunity_delete_cmd,
|
||||||
|
"no set large-comm-list [<(1-99|(100-500)|word)> delete]",
|
||||||
|
NO_STR
|
||||||
|
SET_STR
|
||||||
|
"set BGP large community list (for deletion)\n"
|
||||||
|
"Large Community-list number (standard)\n"
|
||||||
|
"Large Communitly-list number (expanded)\n"
|
||||||
|
"Large Community-list name\n"
|
||||||
|
"Delete matching large communities\n")
|
||||||
|
{
|
||||||
|
return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index),
|
||||||
|
"large-comm-list", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
DEFUN (set_ecommunity_rt,
|
DEFUN (set_ecommunity_rt,
|
||||||
set_ecommunity_rt_cmd,
|
set_ecommunity_rt_cmd,
|
||||||
|
@ -4002,6 +4401,7 @@ bgp_route_map_init (void)
|
||||||
route_map_install_match (&route_match_ip_route_source_prefix_list_cmd);
|
route_map_install_match (&route_match_ip_route_source_prefix_list_cmd);
|
||||||
route_map_install_match (&route_match_aspath_cmd);
|
route_map_install_match (&route_match_aspath_cmd);
|
||||||
route_map_install_match (&route_match_community_cmd);
|
route_map_install_match (&route_match_community_cmd);
|
||||||
|
route_map_install_match (&route_match_lcommunity_cmd);
|
||||||
route_map_install_match (&route_match_ecommunity_cmd);
|
route_map_install_match (&route_match_ecommunity_cmd);
|
||||||
route_map_install_match (&route_match_local_pref_cmd);
|
route_map_install_match (&route_match_local_pref_cmd);
|
||||||
route_map_install_match (&route_match_metric_cmd);
|
route_map_install_match (&route_match_metric_cmd);
|
||||||
|
@ -4021,6 +4421,8 @@ bgp_route_map_init (void)
|
||||||
route_map_install_set (&route_set_aggregator_as_cmd);
|
route_map_install_set (&route_set_aggregator_as_cmd);
|
||||||
route_map_install_set (&route_set_community_cmd);
|
route_map_install_set (&route_set_community_cmd);
|
||||||
route_map_install_set (&route_set_community_delete_cmd);
|
route_map_install_set (&route_set_community_delete_cmd);
|
||||||
|
route_map_install_set (&route_set_lcommunity_cmd);
|
||||||
|
route_map_install_set (&route_set_lcommunity_delete_cmd);
|
||||||
route_map_install_set (&route_set_vpnv4_nexthop_cmd);
|
route_map_install_set (&route_set_vpnv4_nexthop_cmd);
|
||||||
route_map_install_set (&route_set_originator_id_cmd);
|
route_map_install_set (&route_set_originator_id_cmd);
|
||||||
route_map_install_set (&route_set_ecommunity_rt_cmd);
|
route_map_install_set (&route_set_ecommunity_rt_cmd);
|
||||||
|
@ -4042,6 +4444,8 @@ bgp_route_map_init (void)
|
||||||
install_element (RMAP_NODE, &match_community_cmd);
|
install_element (RMAP_NODE, &match_community_cmd);
|
||||||
install_element (RMAP_NODE, &match_community_exact_cmd);
|
install_element (RMAP_NODE, &match_community_exact_cmd);
|
||||||
install_element (RMAP_NODE, &no_match_community_cmd);
|
install_element (RMAP_NODE, &no_match_community_cmd);
|
||||||
|
install_element (RMAP_NODE, &match_lcommunity_cmd);
|
||||||
|
install_element (RMAP_NODE, &no_match_lcommunity_cmd);
|
||||||
install_element (RMAP_NODE, &match_ecommunity_cmd);
|
install_element (RMAP_NODE, &match_ecommunity_cmd);
|
||||||
install_element (RMAP_NODE, &no_match_ecommunity_cmd);
|
install_element (RMAP_NODE, &no_match_ecommunity_cmd);
|
||||||
install_element (RMAP_NODE, &match_origin_cmd);
|
install_element (RMAP_NODE, &match_origin_cmd);
|
||||||
|
@ -4071,6 +4475,11 @@ bgp_route_map_init (void)
|
||||||
install_element (RMAP_NODE, &no_set_community_cmd);
|
install_element (RMAP_NODE, &no_set_community_cmd);
|
||||||
install_element (RMAP_NODE, &set_community_delete_cmd);
|
install_element (RMAP_NODE, &set_community_delete_cmd);
|
||||||
install_element (RMAP_NODE, &no_set_community_delete_cmd);
|
install_element (RMAP_NODE, &no_set_community_delete_cmd);
|
||||||
|
install_element (RMAP_NODE, &set_lcommunity_cmd);
|
||||||
|
install_element (RMAP_NODE, &set_lcommunity_none_cmd);
|
||||||
|
install_element (RMAP_NODE, &no_set_lcommunity_cmd);
|
||||||
|
install_element (RMAP_NODE, &set_lcommunity_delete_cmd);
|
||||||
|
install_element (RMAP_NODE, &no_set_lcommunity_delete_cmd);
|
||||||
install_element (RMAP_NODE, &set_ecommunity_rt_cmd);
|
install_element (RMAP_NODE, &set_ecommunity_rt_cmd);
|
||||||
install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd);
|
install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd);
|
||||||
install_element (RMAP_NODE, &set_ecommunity_soo_cmd);
|
install_element (RMAP_NODE, &set_ecommunity_soo_cmd);
|
||||||
|
|
445
bgpd/bgp_vty.c
445
bgpd/bgp_vty.c
|
@ -41,6 +41,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
#include "bgpd/bgp_aspath.h"
|
#include "bgpd/bgp_aspath.h"
|
||||||
#include "bgpd/bgp_community.h"
|
#include "bgpd/bgp_community.h"
|
||||||
#include "bgpd/bgp_ecommunity.h"
|
#include "bgpd/bgp_ecommunity.h"
|
||||||
|
#include "bgpd/bgp_lcommunity.h"
|
||||||
#include "bgpd/bgp_damp.h"
|
#include "bgpd/bgp_damp.h"
|
||||||
#include "bgpd/bgp_debug.h"
|
#include "bgpd/bgp_debug.h"
|
||||||
#include "bgpd/bgp_fsm.h"
|
#include "bgpd/bgp_fsm.h"
|
||||||
|
@ -3748,13 +3749,15 @@ DEFUN (no_neighbor_send_community,
|
||||||
/* neighbor send-community extended. */
|
/* neighbor send-community extended. */
|
||||||
DEFUN (neighbor_send_community_type,
|
DEFUN (neighbor_send_community_type,
|
||||||
neighbor_send_community_type_cmd,
|
neighbor_send_community_type_cmd,
|
||||||
"neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|extended|standard>",
|
"neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
|
||||||
NEIGHBOR_STR
|
NEIGHBOR_STR
|
||||||
NEIGHBOR_ADDR_STR2
|
NEIGHBOR_ADDR_STR2
|
||||||
"Send Community attribute to this neighbor\n"
|
"Send Community attribute to this neighbor\n"
|
||||||
"Send Standard and Extended Community attributes\n"
|
"Send Standard and Extended Community attributes\n"
|
||||||
|
"Send Standard, Large and Extended Community attributes\n"
|
||||||
"Send Extended Community attributes\n"
|
"Send Extended Community attributes\n"
|
||||||
"Send Standard Community attributes\n")
|
"Send Standard Community attributes\n"
|
||||||
|
"Send Large Community attributes\n")
|
||||||
{
|
{
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
u_int32_t flag = 0;
|
u_int32_t flag = 0;
|
||||||
|
@ -3765,25 +3768,35 @@ DEFUN (neighbor_send_community_type,
|
||||||
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
|
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
|
||||||
else if (argv_find (argv, argc, "extended", &idx))
|
else if (argv_find (argv, argc, "extended", &idx))
|
||||||
SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
|
SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
|
||||||
|
else if (argv_find (argv, argc, "large", &idx))
|
||||||
|
SET_FLAG (flag, PEER_FLAG_SEND_LARGE_COMMUNITY);
|
||||||
|
else if (argv_find (argv, argc, "both", &idx))
|
||||||
|
{
|
||||||
|
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
|
||||||
|
SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
|
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
|
||||||
SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
|
SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
|
||||||
}
|
SET_FLAG (flag, PEER_FLAG_SEND_LARGE_COMMUNITY);
|
||||||
|
}
|
||||||
|
|
||||||
return peer_af_flag_set_vty (vty, peer, bgp_node_afi (vty), bgp_node_safi (vty), flag);
|
return peer_af_flag_set_vty (vty, peer, bgp_node_afi (vty), bgp_node_safi (vty), flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN (no_neighbor_send_community_type,
|
DEFUN (no_neighbor_send_community_type,
|
||||||
no_neighbor_send_community_type_cmd,
|
no_neighbor_send_community_type_cmd,
|
||||||
"no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|extended|standard>",
|
"no neighbor <A.B.C.D|X:X::X:X|WORD> send-community <both|all|extended|standard|large>",
|
||||||
NO_STR
|
NO_STR
|
||||||
NEIGHBOR_STR
|
NEIGHBOR_STR
|
||||||
NEIGHBOR_ADDR_STR2
|
NEIGHBOR_ADDR_STR2
|
||||||
"Send Community attribute to this neighbor\n"
|
"Send Community attribute to this neighbor\n"
|
||||||
"Send Standard and Extended Community attributes\n"
|
"Send Standard and Extended Community attributes\n"
|
||||||
|
"Send Standard, Large and Extended Community attributes\n"
|
||||||
"Send Extended Community attributes\n"
|
"Send Extended Community attributes\n"
|
||||||
"Send Standard Community attributes\n")
|
"Send Standard Community attributes\n"
|
||||||
|
"Send Large Community attributes\n")
|
||||||
{
|
{
|
||||||
int idx_peer = 2;
|
int idx_peer = 2;
|
||||||
int idx_type = 4;
|
int idx_type = 4;
|
||||||
|
@ -3795,11 +3808,21 @@ DEFUN (no_neighbor_send_community_type,
|
||||||
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
|
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
|
||||||
bgp_node_safi (vty),
|
bgp_node_safi (vty),
|
||||||
PEER_FLAG_SEND_EXT_COMMUNITY);
|
PEER_FLAG_SEND_EXT_COMMUNITY);
|
||||||
|
if (strncmp (argv[idx_type]->arg, "l", 1) == 0)
|
||||||
|
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
|
||||||
|
bgp_node_safi (vty),
|
||||||
|
PEER_FLAG_SEND_LARGE_COMMUNITY);
|
||||||
|
if (strncmp (argv[idx_type]->arg, "b", 1) == 0)
|
||||||
|
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
|
||||||
|
bgp_node_safi (vty),
|
||||||
|
PEER_FLAG_SEND_COMMUNITY |
|
||||||
|
PEER_FLAG_SEND_EXT_COMMUNITY);
|
||||||
|
|
||||||
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
|
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
|
||||||
bgp_node_safi (vty),
|
bgp_node_safi (vty),
|
||||||
(PEER_FLAG_SEND_COMMUNITY |
|
(PEER_FLAG_SEND_COMMUNITY |
|
||||||
PEER_FLAG_SEND_EXT_COMMUNITY));
|
PEER_FLAG_SEND_EXT_COMMUNITY|
|
||||||
|
PEER_FLAG_SEND_LARGE_COMMUNITY));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* neighbor soft-reconfig. */
|
/* neighbor soft-reconfig. */
|
||||||
|
@ -6132,6 +6155,12 @@ DEFUN (show_bgp_memory,
|
||||||
mtype_memstr (memstrbuf, sizeof (memstrbuf),
|
mtype_memstr (memstrbuf, sizeof (memstrbuf),
|
||||||
count * sizeof (struct ecommunity)),
|
count * sizeof (struct ecommunity)),
|
||||||
VTY_NEWLINE);
|
VTY_NEWLINE);
|
||||||
|
if ((count = mtype_stats_alloc (MTYPE_LCOMMUNITY)))
|
||||||
|
vty_out (vty, "%ld BGP large-community entries, using %s of memory%s",
|
||||||
|
count,
|
||||||
|
mtype_memstr (memstrbuf, sizeof (memstrbuf),
|
||||||
|
count * sizeof (struct lcommunity)),
|
||||||
|
VTY_NEWLINE);
|
||||||
|
|
||||||
if ((count = mtype_stats_alloc (MTYPE_CLUSTER)))
|
if ((count = mtype_stats_alloc (MTYPE_CLUSTER)))
|
||||||
vty_out (vty, "%ld Cluster lists, using %s of memory%s", count,
|
vty_out (vty, "%ld Cluster lists, using %s of memory%s", count,
|
||||||
|
@ -7109,12 +7138,16 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi,
|
||||||
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
|
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
|
||||||
vty_out (vty, " MED is propagated unchanged to this neighbor%s", VTY_NEWLINE);
|
vty_out (vty, " MED is propagated unchanged to this neighbor%s", VTY_NEWLINE);
|
||||||
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
|
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
|
||||||
|| CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
|
|| CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
|
||||||
|
|| CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
|
||||||
{
|
{
|
||||||
vty_out (vty, " Community attribute sent to this neighbor");
|
vty_out (vty, " Community attribute sent to this neighbor");
|
||||||
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
|
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
|
||||||
&& CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
|
&& CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
|
||||||
vty_out (vty, "(both)%s", VTY_NEWLINE);
|
&& CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
|
||||||
|
vty_out (vty, "(all)%s", VTY_NEWLINE);
|
||||||
|
else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY))
|
||||||
|
vty_out (vty, "(large)%s", VTY_NEWLINE);
|
||||||
else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
|
else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY))
|
||||||
vty_out (vty, "(extended)%s", VTY_NEWLINE);
|
vty_out (vty, "(extended)%s", VTY_NEWLINE);
|
||||||
else
|
else
|
||||||
|
@ -8637,6 +8670,36 @@ DEFUN (show_ip_bgp_community_info,
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lcommunity_show_all_iterator (struct hash_backet *backet, struct vty *vty)
|
||||||
|
{
|
||||||
|
struct lcommunity *lcom;
|
||||||
|
|
||||||
|
lcom = (struct lcommunity *) backet->data;
|
||||||
|
vty_out (vty, "[%p] (%ld) %s%s", (void *)backet, lcom->refcnt,
|
||||||
|
lcommunity_str (lcom), VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show BGP's community internal data. */
|
||||||
|
DEFUN (show_ip_bgp_lcommunity_info,
|
||||||
|
show_ip_bgp_lcommunity_info_cmd,
|
||||||
|
"show ip bgp large-community-info",
|
||||||
|
SHOW_STR
|
||||||
|
IP_STR
|
||||||
|
BGP_STR
|
||||||
|
"List all bgp large-community information\n")
|
||||||
|
{
|
||||||
|
vty_out (vty, "Address Refcnt Large-community%s", VTY_NEWLINE);
|
||||||
|
|
||||||
|
hash_iterate (lcommunity_hash (),
|
||||||
|
(void (*) (struct hash_backet *, void *))
|
||||||
|
lcommunity_show_all_iterator,
|
||||||
|
vty);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DEFUN (show_ip_bgp_attr_info,
|
DEFUN (show_ip_bgp_attr_info,
|
||||||
show_ip_bgp_attr_info_cmd,
|
show_ip_bgp_attr_info_cmd,
|
||||||
"show [ip] bgp attribute-info",
|
"show [ip] bgp attribute-info",
|
||||||
|
@ -10738,6 +10801,8 @@ bgp_vty_init (void)
|
||||||
/* "show [ip] bgp community" commands. */
|
/* "show [ip] bgp community" commands. */
|
||||||
install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd);
|
install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd);
|
||||||
|
|
||||||
|
/* "show ip bgp large-community" commands. */
|
||||||
|
install_element (VIEW_NODE, &show_ip_bgp_lcommunity_info_cmd);
|
||||||
/* "show [ip] bgp attribute-info" commands. */
|
/* "show [ip] bgp attribute-info" commands. */
|
||||||
install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd);
|
install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd);
|
||||||
|
|
||||||
|
@ -11070,6 +11135,324 @@ DEFUN (show_ip_community_list_arg,
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Large Community code.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
lcommunity_list_set_vty (struct vty *vty, int argc, struct cmd_token **argv,
|
||||||
|
int style, int reject_all_digit_name)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int direct;
|
||||||
|
char *str;
|
||||||
|
int idx = 0;
|
||||||
|
char *cl_name;
|
||||||
|
|
||||||
|
direct = argv_find (argv, argc, "permit", &idx) ? COMMUNITY_PERMIT : COMMUNITY_DENY;
|
||||||
|
|
||||||
|
/* All digit name check. */
|
||||||
|
idx = 0;
|
||||||
|
argv_find (argv, argc, "WORD", &idx);
|
||||||
|
argv_find (argv, argc, "(1-99)", &idx);
|
||||||
|
argv_find (argv, argc, "(100-500)", &idx);
|
||||||
|
cl_name = argv[idx]->arg;
|
||||||
|
if (reject_all_digit_name && all_digit (cl_name))
|
||||||
|
{
|
||||||
|
vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
argv_find (argv, argc, "AA:BB:CC", &idx);
|
||||||
|
argv_find (argv, argc, "LINE", &idx);
|
||||||
|
/* Concat community string argument. */
|
||||||
|
if (idx)
|
||||||
|
str = argv_concat (argv, argc, idx);
|
||||||
|
else
|
||||||
|
str = NULL;
|
||||||
|
|
||||||
|
ret = lcommunity_list_set (bgp_clist, cl_name, str, direct, style);
|
||||||
|
|
||||||
|
/* Free temporary community list string allocated by
|
||||||
|
argv_concat(). */
|
||||||
|
if (str)
|
||||||
|
XFREE (MTYPE_TMP, str);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
community_list_perror (vty, ret);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lcommunity_list_unset_vty (struct vty *vty, int argc, struct cmd_token **argv,
|
||||||
|
int style)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int direct = 0;
|
||||||
|
char *str = NULL;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
argv_find (argv, argc, "permit", &idx);
|
||||||
|
argv_find (argv, argc, "deny", &idx);
|
||||||
|
|
||||||
|
if (idx)
|
||||||
|
{
|
||||||
|
/* Check the list direct. */
|
||||||
|
if (strncmp (argv[idx]->arg, "p", 1) == 0)
|
||||||
|
direct = COMMUNITY_PERMIT;
|
||||||
|
else
|
||||||
|
direct = COMMUNITY_DENY;
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
argv_find (argv, argc, "LINE", &idx);
|
||||||
|
argv_find (argv, argc, "AA:AA:NN", &idx);
|
||||||
|
/* Concat community string argument. */
|
||||||
|
str = argv_concat (argv, argc, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
argv_find (argv, argc, "(1-99)", &idx);
|
||||||
|
argv_find (argv, argc, "(100-500)", &idx);
|
||||||
|
argv_find (argv, argc, "WORD", &idx);
|
||||||
|
|
||||||
|
/* Unset community list. */
|
||||||
|
ret = lcommunity_list_unset (bgp_clist, argv[idx]->arg, str, direct, style);
|
||||||
|
|
||||||
|
/* Free temporary community list string allocated by
|
||||||
|
argv_concat(). */
|
||||||
|
if (str)
|
||||||
|
XFREE (MTYPE_TMP, str);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
community_list_perror (vty, ret);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "large-community-list" keyword help string. */
|
||||||
|
#define LCOMMUNITY_LIST_STR "Add a large community list entry\n"
|
||||||
|
#define LCOMMUNITY_VAL_STR "large community in 'aa:bb:cc' format\n"
|
||||||
|
|
||||||
|
DEFUN (ip_lcommunity_list_standard,
|
||||||
|
ip_lcommunity_list_standard_cmd,
|
||||||
|
"ip large-community-list (1-99) <deny|permit> [AA:BB:CC...]",
|
||||||
|
IP_STR
|
||||||
|
LCOMMUNITY_LIST_STR
|
||||||
|
"Large Community list number (standard)\n"
|
||||||
|
"Specify large community to reject\n"
|
||||||
|
"Specify large community to accept\n"
|
||||||
|
LCOMMUNITY_VAL_STR)
|
||||||
|
{
|
||||||
|
return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (ip_lcommunity_list_expanded,
|
||||||
|
ip_lcommunity_list_expanded_cmd,
|
||||||
|
"ip large-community-list (100-500) <deny|permit> LINE...",
|
||||||
|
IP_STR
|
||||||
|
LCOMMUNITY_LIST_STR
|
||||||
|
"Large Community list number (expanded)\n"
|
||||||
|
"Specify large community to reject\n"
|
||||||
|
"Specify large community to accept\n"
|
||||||
|
"An ordered list as a regular-expression\n")
|
||||||
|
{
|
||||||
|
return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (ip_lcommunity_list_name_standard,
|
||||||
|
ip_lcommunity_list_name_standard_cmd,
|
||||||
|
"ip large-community-list standard WORD <deny|permit> [AA:BB.CC...]",
|
||||||
|
IP_STR
|
||||||
|
LCOMMUNITY_LIST_STR
|
||||||
|
"Specify standard large-community-list\n"
|
||||||
|
"Large Community list name\n"
|
||||||
|
"Specify large community to reject\n"
|
||||||
|
"Specify large community to accept\n"
|
||||||
|
LCOMMUNITY_VAL_STR)
|
||||||
|
{
|
||||||
|
return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (ip_lcommunity_list_name_expanded,
|
||||||
|
ip_lcommunity_list_name_expanded_cmd,
|
||||||
|
"ip large-community-list expanded WORD <deny|permit> LINE...",
|
||||||
|
IP_STR
|
||||||
|
LCOMMUNITY_LIST_STR
|
||||||
|
"Specify expanded large-community-list\n"
|
||||||
|
"Large Community list name\n"
|
||||||
|
"Specify large community to reject\n"
|
||||||
|
"Specify large community to accept\n"
|
||||||
|
"An ordered list as a regular-expression\n")
|
||||||
|
{
|
||||||
|
return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (no_ip_lcommunity_list_standard_all,
|
||||||
|
no_ip_lcommunity_list_standard_all_cmd,
|
||||||
|
"no ip large-community-list <(1-99)|(100-500)|WORD>",
|
||||||
|
NO_STR
|
||||||
|
IP_STR
|
||||||
|
LCOMMUNITY_LIST_STR
|
||||||
|
"Large Community list number (standard)\n"
|
||||||
|
"Large Community list number (expanded)\n"
|
||||||
|
"Large Community list name\n")
|
||||||
|
{
|
||||||
|
return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (no_ip_lcommunity_list_name_expanded_all,
|
||||||
|
no_ip_lcommunity_list_name_expanded_all_cmd,
|
||||||
|
"no ip large-community-list expanded WORD",
|
||||||
|
NO_STR
|
||||||
|
IP_STR
|
||||||
|
LCOMMUNITY_LIST_STR
|
||||||
|
"Specify expanded large-community-list\n"
|
||||||
|
"Large Community list name\n")
|
||||||
|
{
|
||||||
|
return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (no_ip_lcommunity_list_standard,
|
||||||
|
no_ip_lcommunity_list_standard_cmd,
|
||||||
|
"no ip large-community-list (1-99) <deny|permit> AA:AA:NN...",
|
||||||
|
NO_STR
|
||||||
|
IP_STR
|
||||||
|
LCOMMUNITY_LIST_STR
|
||||||
|
"Large Community list number (standard)\n"
|
||||||
|
"Specify large community to reject\n"
|
||||||
|
"Specify large community to accept\n"
|
||||||
|
LCOMMUNITY_VAL_STR)
|
||||||
|
{
|
||||||
|
return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (no_ip_lcommunity_list_expanded,
|
||||||
|
no_ip_lcommunity_list_expanded_cmd,
|
||||||
|
"no ip large-community-list (100-500) <deny|permit> LINE...",
|
||||||
|
NO_STR
|
||||||
|
IP_STR
|
||||||
|
LCOMMUNITY_LIST_STR
|
||||||
|
"Large Community list number (expanded)\n"
|
||||||
|
"Specify large community to reject\n"
|
||||||
|
"Specify large community to accept\n"
|
||||||
|
"An ordered list as a regular-expression\n")
|
||||||
|
{
|
||||||
|
return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (no_ip_lcommunity_list_name_standard,
|
||||||
|
no_ip_lcommunity_list_name_standard_cmd,
|
||||||
|
"no ip large-community-list standard WORD <deny|permit> AA:AA:NN...",
|
||||||
|
NO_STR
|
||||||
|
IP_STR
|
||||||
|
LCOMMUNITY_LIST_STR
|
||||||
|
"Specify standard large-community-list\n"
|
||||||
|
"Large Community list name\n"
|
||||||
|
"Specify large community to reject\n"
|
||||||
|
"Specify large community to accept\n"
|
||||||
|
LCOMMUNITY_VAL_STR)
|
||||||
|
{
|
||||||
|
return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (no_ip_lcommunity_list_name_expanded,
|
||||||
|
no_ip_lcommunity_list_name_expanded_cmd,
|
||||||
|
"no ip large-community-list expanded WORD <deny|permit> LINE...",
|
||||||
|
NO_STR
|
||||||
|
IP_STR
|
||||||
|
LCOMMUNITY_LIST_STR
|
||||||
|
"Specify expanded large-community-list\n"
|
||||||
|
"Large community list name\n"
|
||||||
|
"Specify large community to reject\n"
|
||||||
|
"Specify large community to accept\n"
|
||||||
|
"An ordered list as a regular-expression\n")
|
||||||
|
{
|
||||||
|
return lcommunity_list_unset_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_EXPANDED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lcommunity_list_show (struct vty *vty, struct community_list *list)
|
||||||
|
{
|
||||||
|
struct community_entry *entry;
|
||||||
|
|
||||||
|
for (entry = list->head; entry; entry = entry->next)
|
||||||
|
{
|
||||||
|
if (entry == list->head)
|
||||||
|
{
|
||||||
|
if (all_digit (list->name))
|
||||||
|
vty_out (vty, "Large community %s list %s%s",
|
||||||
|
entry->style == EXTCOMMUNITY_LIST_STANDARD ?
|
||||||
|
"standard" : "(expanded) access",
|
||||||
|
list->name, VTY_NEWLINE);
|
||||||
|
else
|
||||||
|
vty_out (vty, "Named large community %s list %s%s",
|
||||||
|
entry->style == EXTCOMMUNITY_LIST_STANDARD ?
|
||||||
|
"standard" : "expanded",
|
||||||
|
list->name, VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
if (entry->any)
|
||||||
|
vty_out (vty, " %s%s",
|
||||||
|
community_direct_str (entry->direct), VTY_NEWLINE);
|
||||||
|
else
|
||||||
|
vty_out (vty, " %s %s%s",
|
||||||
|
community_direct_str (entry->direct),
|
||||||
|
entry->style == EXTCOMMUNITY_LIST_STANDARD ?
|
||||||
|
entry->u.ecom->str : entry->config,
|
||||||
|
VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (show_ip_lcommunity_list,
|
||||||
|
show_ip_lcommunity_list_cmd,
|
||||||
|
"show ip large-community-list",
|
||||||
|
SHOW_STR
|
||||||
|
IP_STR
|
||||||
|
"List large-community list\n")
|
||||||
|
{
|
||||||
|
struct community_list *list;
|
||||||
|
struct community_list_master *cm;
|
||||||
|
|
||||||
|
cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER);
|
||||||
|
if (! cm)
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
|
||||||
|
for (list = cm->num.head; list; list = list->next)
|
||||||
|
lcommunity_list_show (vty, list);
|
||||||
|
|
||||||
|
for (list = cm->str.head; list; list = list->next)
|
||||||
|
lcommunity_list_show (vty, list);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN (show_ip_lcommunity_list_arg,
|
||||||
|
show_ip_lcommunity_list_arg_cmd,
|
||||||
|
"show ip large-community-list <(1-500)|WORD>",
|
||||||
|
SHOW_STR
|
||||||
|
IP_STR
|
||||||
|
"List large-community list\n"
|
||||||
|
"large-community-list number\n"
|
||||||
|
"large-community-list name\n")
|
||||||
|
{
|
||||||
|
struct community_list *list;
|
||||||
|
|
||||||
|
list = community_list_lookup (bgp_clist, argv[3]->arg, LARGE_COMMUNITY_LIST_MASTER);
|
||||||
|
if (! list)
|
||||||
|
{
|
||||||
|
vty_out (vty, "%% Can't find extcommunity-list%s", VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
lcommunity_list_show (vty, list);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* "extcommunity-list" keyword help string. */
|
/* "extcommunity-list" keyword help string. */
|
||||||
#define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n"
|
#define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n"
|
||||||
#define EXTCOMMUNITY_VAL_STR "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n"
|
#define EXTCOMMUNITY_VAL_STR "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n"
|
||||||
|
@ -11379,6 +11762,30 @@ community_list_config_write (struct vty *vty)
|
||||||
community_list_config_str (entry), VTY_NEWLINE);
|
community_list_config_str (entry), VTY_NEWLINE);
|
||||||
write++;
|
write++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* lcommunity-list. */
|
||||||
|
cm = community_list_master_lookup (bgp_clist, LARGE_COMMUNITY_LIST_MASTER);
|
||||||
|
|
||||||
|
for (list = cm->num.head; list; list = list->next)
|
||||||
|
for (entry = list->head; entry; entry = entry->next)
|
||||||
|
{
|
||||||
|
vty_out (vty, "ip large-community-list %s %s %s%s",
|
||||||
|
list->name, community_direct_str (entry->direct),
|
||||||
|
community_list_config_str (entry), VTY_NEWLINE);
|
||||||
|
write++;
|
||||||
|
}
|
||||||
|
for (list = cm->str.head; list; list = list->next)
|
||||||
|
for (entry = list->head; entry; entry = entry->next)
|
||||||
|
{
|
||||||
|
vty_out (vty, "ip large-community-list %s %s %s %s%s",
|
||||||
|
entry->style == LARGE_COMMUNITY_LIST_STANDARD
|
||||||
|
? "standard" : "expanded",
|
||||||
|
list->name, community_direct_str (entry->direct),
|
||||||
|
community_list_config_str (entry), VTY_NEWLINE);
|
||||||
|
write++;
|
||||||
|
}
|
||||||
|
|
||||||
return write;
|
return write;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11409,4 +11816,18 @@ community_list_vty (void)
|
||||||
install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd);
|
install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd);
|
||||||
install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd);
|
install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd);
|
||||||
install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd);
|
install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd);
|
||||||
|
|
||||||
|
/* Large Community List */
|
||||||
|
install_element (CONFIG_NODE, &ip_lcommunity_list_standard_cmd);
|
||||||
|
install_element (CONFIG_NODE, &ip_lcommunity_list_expanded_cmd);
|
||||||
|
install_element (CONFIG_NODE, &ip_lcommunity_list_name_standard_cmd);
|
||||||
|
install_element (CONFIG_NODE, &ip_lcommunity_list_name_expanded_cmd);
|
||||||
|
install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_all_cmd);
|
||||||
|
install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_all_cmd);
|
||||||
|
install_element (CONFIG_NODE, &no_ip_lcommunity_list_standard_cmd);
|
||||||
|
install_element (CONFIG_NODE, &no_ip_lcommunity_list_expanded_cmd);
|
||||||
|
install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_standard_cmd);
|
||||||
|
install_element (CONFIG_NODE, &no_ip_lcommunity_list_name_expanded_cmd);
|
||||||
|
install_element (VIEW_NODE, &show_ip_lcommunity_list_cmd);
|
||||||
|
install_element (VIEW_NODE, &show_ip_lcommunity_list_arg_cmd);
|
||||||
}
|
}
|
||||||
|
|
27
bgpd/bgpd.c
27
bgpd/bgpd.c
|
@ -902,6 +902,7 @@ peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi)
|
||||||
{
|
{
|
||||||
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
|
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
|
||||||
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
|
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
|
||||||
|
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear neighbor default_originate_rmap */
|
/* Clear neighbor default_originate_rmap */
|
||||||
|
@ -1206,6 +1207,7 @@ peer_new (struct bgp *bgp)
|
||||||
{
|
{
|
||||||
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
|
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
|
||||||
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
|
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
|
||||||
|
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
|
||||||
}
|
}
|
||||||
peer->orf_plist[afi][safi] = NULL;
|
peer->orf_plist[afi][safi] = NULL;
|
||||||
}
|
}
|
||||||
|
@ -3702,6 +3704,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] =
|
||||||
{
|
{
|
||||||
{ PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out },
|
{ PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out },
|
||||||
{ PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out },
|
{ PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out },
|
||||||
|
{ PEER_FLAG_SEND_LARGE_COMMUNITY, 1, peer_change_reset_out },
|
||||||
{ PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out },
|
{ PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out },
|
||||||
{ PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset },
|
{ PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset },
|
||||||
{ PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset },
|
{ PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset },
|
||||||
|
@ -6982,10 +6985,17 @@ bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp,
|
||||||
if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
|
if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
|
||||||
{
|
{
|
||||||
if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
|
if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
|
||||||
&& peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
|
&& peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)
|
||||||
|
&& peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
|
||||||
{
|
{
|
||||||
afi_header_vty_out (vty, afi, safi, write,
|
afi_header_vty_out (vty, afi, safi, write,
|
||||||
" neighbor %s send-community both%s",
|
" neighbor %s send-community all%s",
|
||||||
|
addr, VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
|
||||||
|
{
|
||||||
|
afi_header_vty_out (vty, afi, safi, write,
|
||||||
|
" neighbor %s send-community large%s",
|
||||||
addr, VTY_NEWLINE);
|
addr, VTY_NEWLINE);
|
||||||
}
|
}
|
||||||
else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
|
else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
|
||||||
|
@ -7006,10 +7016,19 @@ bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp,
|
||||||
if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) &&
|
if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) &&
|
||||||
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) &&
|
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) &&
|
||||||
!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) &&
|
!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) &&
|
||||||
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)))
|
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) &&
|
||||||
|
!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY) &&
|
||||||
|
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)))
|
||||||
{
|
{
|
||||||
afi_header_vty_out (vty, afi, safi, write,
|
afi_header_vty_out (vty, afi, safi, write,
|
||||||
" no neighbor %s send-community both%s",
|
" no neighbor %s send-community all%s",
|
||||||
|
addr, VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
else if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY) &&
|
||||||
|
(!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)))
|
||||||
|
{
|
||||||
|
afi_header_vty_out (vty, afi, safi, write,
|
||||||
|
" no neighbor %s send-community large%s",
|
||||||
addr, VTY_NEWLINE);
|
addr, VTY_NEWLINE);
|
||||||
}
|
}
|
||||||
else if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) &&
|
else if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) &&
|
||||||
|
|
|
@ -705,6 +705,7 @@ struct peer
|
||||||
#define PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS (1 << 23) /* addpath-tx-bestpath-per-AS */
|
#define PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS (1 << 23) /* addpath-tx-bestpath-per-AS */
|
||||||
#define PEER_FLAG_WEIGHT (1 << 24) /* weight */
|
#define PEER_FLAG_WEIGHT (1 << 24) /* weight */
|
||||||
#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1 << 25) /* allowas-in origin */
|
#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1 << 25) /* allowas-in origin */
|
||||||
|
#define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 26) /* Send large Communities */
|
||||||
|
|
||||||
/* MD5 password */
|
/* MD5 password */
|
||||||
char *password;
|
char *password;
|
||||||
|
@ -963,6 +964,7 @@ struct bgp_nlri
|
||||||
#define BGP_ATTR_AS4_AGGREGATOR 18
|
#define BGP_ATTR_AS4_AGGREGATOR 18
|
||||||
#define BGP_ATTR_AS_PATHLIMIT 21
|
#define BGP_ATTR_AS_PATHLIMIT 21
|
||||||
#define BGP_ATTR_ENCAP 23
|
#define BGP_ATTR_ENCAP 23
|
||||||
|
#define BGP_ATTR_LARGE_COMMUNITIES 32
|
||||||
#if ENABLE_BGP_VNC
|
#if ENABLE_BGP_VNC
|
||||||
#define BGP_ATTR_VNC 255
|
#define BGP_ATTR_VNC 255
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -710,6 +710,7 @@ enum route_map_dep_type
|
||||||
ROUTE_MAP_DEP_RMAP = 1,
|
ROUTE_MAP_DEP_RMAP = 1,
|
||||||
ROUTE_MAP_DEP_CLIST,
|
ROUTE_MAP_DEP_CLIST,
|
||||||
ROUTE_MAP_DEP_ECLIST,
|
ROUTE_MAP_DEP_ECLIST,
|
||||||
|
ROUTE_MAP_DEP_LCLIST,
|
||||||
ROUTE_MAP_DEP_PLIST,
|
ROUTE_MAP_DEP_PLIST,
|
||||||
ROUTE_MAP_DEP_ASPATH,
|
ROUTE_MAP_DEP_ASPATH,
|
||||||
ROUTE_MAP_DEP_FILTER,
|
ROUTE_MAP_DEP_FILTER,
|
||||||
|
@ -1819,6 +1820,7 @@ route_map_dep_update (struct hash *dephash, const char *dep_name,
|
||||||
case RMAP_EVENT_CLIST_ADDED:
|
case RMAP_EVENT_CLIST_ADDED:
|
||||||
case RMAP_EVENT_ECLIST_ADDED:
|
case RMAP_EVENT_ECLIST_ADDED:
|
||||||
case RMAP_EVENT_ASLIST_ADDED:
|
case RMAP_EVENT_ASLIST_ADDED:
|
||||||
|
case RMAP_EVENT_LLIST_ADDED:
|
||||||
case RMAP_EVENT_CALL_ADDED:
|
case RMAP_EVENT_CALL_ADDED:
|
||||||
case RMAP_EVENT_FILTER_ADDED:
|
case RMAP_EVENT_FILTER_ADDED:
|
||||||
if (rmap_debug)
|
if (rmap_debug)
|
||||||
|
@ -1840,6 +1842,7 @@ route_map_dep_update (struct hash *dephash, const char *dep_name,
|
||||||
case RMAP_EVENT_CLIST_DELETED:
|
case RMAP_EVENT_CLIST_DELETED:
|
||||||
case RMAP_EVENT_ECLIST_DELETED:
|
case RMAP_EVENT_ECLIST_DELETED:
|
||||||
case RMAP_EVENT_ASLIST_DELETED:
|
case RMAP_EVENT_ASLIST_DELETED:
|
||||||
|
case RMAP_EVENT_LLIST_DELETED:
|
||||||
case RMAP_EVENT_CALL_DELETED:
|
case RMAP_EVENT_CALL_DELETED:
|
||||||
case RMAP_EVENT_FILTER_DELETED:
|
case RMAP_EVENT_FILTER_DELETED:
|
||||||
if (rmap_debug)
|
if (rmap_debug)
|
||||||
|
@ -1902,6 +1905,10 @@ route_map_get_dep_hash (route_map_event_t event)
|
||||||
case RMAP_EVENT_ASLIST_DELETED:
|
case RMAP_EVENT_ASLIST_DELETED:
|
||||||
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
|
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
|
||||||
break;
|
break;
|
||||||
|
case RMAP_EVENT_LLIST_ADDED:
|
||||||
|
case RMAP_EVENT_LLIST_DELETED:
|
||||||
|
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_LCLIST];
|
||||||
|
break;
|
||||||
case RMAP_EVENT_CALL_ADDED:
|
case RMAP_EVENT_CALL_ADDED:
|
||||||
case RMAP_EVENT_CALL_DELETED:
|
case RMAP_EVENT_CALL_DELETED:
|
||||||
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
|
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
|
||||||
|
|
|
@ -84,6 +84,8 @@ typedef enum
|
||||||
RMAP_EVENT_CLIST_DELETED,
|
RMAP_EVENT_CLIST_DELETED,
|
||||||
RMAP_EVENT_ECLIST_ADDED,
|
RMAP_EVENT_ECLIST_ADDED,
|
||||||
RMAP_EVENT_ECLIST_DELETED,
|
RMAP_EVENT_ECLIST_DELETED,
|
||||||
|
RMAP_EVENT_LLIST_ADDED,
|
||||||
|
RMAP_EVENT_LLIST_DELETED,
|
||||||
RMAP_EVENT_ASLIST_ADDED,
|
RMAP_EVENT_ASLIST_ADDED,
|
||||||
RMAP_EVENT_ASLIST_DELETED,
|
RMAP_EVENT_ASLIST_DELETED,
|
||||||
RMAP_EVENT_FILTER_ADDED,
|
RMAP_EVENT_FILTER_ADDED,
|
||||||
|
|
Loading…
Reference in a new issue