mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-11 18:48:14 +00:00
Merge remote-tracking branch 'origin/master' into pr/111
This commit is contained in:
commit
c016b6c796
@ -75,7 +75,8 @@ libbgp_a_SOURCES = \
|
||||
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_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_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)
|
||||
@ -85,7 +86,8 @@ noinst_HEADERS = \
|
||||
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 \
|
||||
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_updgrp.h bgp_bfd.h bgp_encap.h bgp_encap_tlv.h bgp_encap_types.h \
|
||||
$(BGP_VNC_RFAPI_HD)
|
||||
|
113
bgpd/bgp_attr.c
113
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_packet.h"
|
||||
#include "bgpd/bgp_ecommunity.h"
|
||||
#include "bgpd/bgp_lcommunity.h"
|
||||
#include "bgpd/bgp_updgrp.h"
|
||||
#include "bgpd/bgp_encap_types.h"
|
||||
#if ENABLE_BGP_VNC
|
||||
@ -76,6 +77,7 @@ static const struct message attr_str [] =
|
||||
#if ENABLE_BGP_VNC
|
||||
{ BGP_ATTR_VNC, "VNC" },
|
||||
#endif
|
||||
{ BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY" }
|
||||
};
|
||||
static const int attr_str_max = array_size(attr_str);
|
||||
|
||||
@ -670,6 +672,8 @@ attrhash_key_make (void *p)
|
||||
|
||||
if (extra)
|
||||
{
|
||||
if (extra->lcommunity)
|
||||
MIX(lcommunity_hash_make (extra->lcommunity));
|
||||
if (extra->ecommunity)
|
||||
MIX(ecommunity_hash_make (extra->ecommunity));
|
||||
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)
|
||||
&& IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
|
||||
&& ae1->ecommunity == ae2->ecommunity
|
||||
&& ae1->lcommunity == ae2->lcommunity
|
||||
&& ae1->cluster == ae2->cluster
|
||||
&& ae1->transit == ae2->transit
|
||||
&& (ae1->encap_tunneltype == ae2->encap_tunneltype)
|
||||
@ -836,6 +841,13 @@ bgp_attr_intern (struct attr *attr)
|
||||
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->refcnt)
|
||||
@ -1026,7 +1038,11 @@ bgp_attr_unintern_sub (struct attr *attr)
|
||||
if (attr->extra->ecommunity)
|
||||
ecommunity_unintern (&attr->extra->ecommunity);
|
||||
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)
|
||||
cluster_unintern (attr->extra->cluster);
|
||||
UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST));
|
||||
@ -1096,6 +1112,8 @@ bgp_attr_flush (struct attr *attr)
|
||||
|
||||
if (attre->ecommunity && ! attre->ecommunity->refcnt)
|
||||
ecommunity_free (&attre->ecommunity);
|
||||
if (attre->lcommunity && ! attre->lcommunity->refcnt)
|
||||
lcommunity_free (&attre->lcommunity);
|
||||
if (attre->cluster && ! attre->cluster->refcnt)
|
||||
{
|
||||
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_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
|
||||
[BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
|
||||
[BGP_ATTR_LARGE_COMMUNITIES]= BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
|
||||
};
|
||||
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
|
||||
|
||||
@ -1849,7 +1868,8 @@ int
|
||||
bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
|
||||
struct bgp_nlri *mp_update)
|
||||
{
|
||||
afi_t pkt_afi, afi;
|
||||
iana_afi_t pkt_afi;
|
||||
afi_t afi;
|
||||
safi_t pkt_safi, safi;
|
||||
bgp_size_t nlri_len;
|
||||
size_t start;
|
||||
@ -2000,7 +2020,8 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
|
||||
struct bgp_nlri *mp_withdraw)
|
||||
{
|
||||
struct stream *s;
|
||||
afi_t pkt_afi, afi;
|
||||
iana_afi_t pkt_afi;
|
||||
afi_t afi;
|
||||
safi_t pkt_safi, safi;
|
||||
u_int16_t withdraw_len;
|
||||
struct peer *const peer = args->peer;
|
||||
@ -2042,6 +2063,40 @@ bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
|
||||
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. */
|
||||
static bgp_attr_parse_ret_t
|
||||
bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
|
||||
@ -2063,7 +2118,7 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
|
||||
/* XXX: fix ecommunity_parse to use stream API */
|
||||
stream_forward_getp (peer->ibuf, length);
|
||||
|
||||
if (!attr->extra->ecommunity)
|
||||
if (attr->extra && !attr->extra->ecommunity)
|
||||
return bgp_attr_malformed (args,
|
||||
BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
|
||||
args->total);
|
||||
@ -2477,6 +2532,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
|
||||
case BGP_ATTR_COMMUNITIES:
|
||||
ret = bgp_attr_community (&attr_args);
|
||||
break;
|
||||
case BGP_ATTR_LARGE_COMMUNITIES:
|
||||
ret = bgp_attr_large_community (&attr_args);
|
||||
break;
|
||||
case BGP_ATTR_ORIGINATOR_ID:
|
||||
ret = bgp_attr_originator_id (&attr_args);
|
||||
break;
|
||||
@ -2648,7 +2706,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, afi_t nh_afi,
|
||||
struct attr *attr)
|
||||
{
|
||||
size_t sizep;
|
||||
afi_t pkt_afi;
|
||||
iana_afi_t pkt_afi;
|
||||
safi_t pkt_safi;
|
||||
|
||||
/* Set extended bit always to encode the attribute length as 2 bytes */
|
||||
@ -3104,6 +3162,28 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
|
||||
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. */
|
||||
if (peer->sort == BGP_PEER_IBGP
|
||||
&& from
|
||||
@ -3282,7 +3362,7 @@ size_t
|
||||
bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi)
|
||||
{
|
||||
unsigned long attrlen_pnt;
|
||||
afi_t pkt_afi;
|
||||
iana_afi_t pkt_afi;
|
||||
safi_t pkt_safi;
|
||||
|
||||
/* Set extended bit always to encode the attribute length as 2 bytes */
|
||||
@ -3336,6 +3416,7 @@ bgp_attr_init (void)
|
||||
attrhash_init ();
|
||||
community_init ();
|
||||
ecommunity_init ();
|
||||
lcommunity_init ();
|
||||
cluster_init ();
|
||||
transit_init ();
|
||||
encap_init ();
|
||||
@ -3348,6 +3429,7 @@ bgp_attr_finish (void)
|
||||
attrhash_finish ();
|
||||
community_finish ();
|
||||
ecommunity_finish ();
|
||||
lcommunity_finish ();
|
||||
cluster_finish ();
|
||||
transit_finish ();
|
||||
encap_finish ();
|
||||
@ -3451,6 +3533,25 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr,
|
||||
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 */
|
||||
if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
|
||||
(attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL ||
|
||||
|
@ -92,7 +92,10 @@ struct attr_extra
|
||||
|
||||
/* Extended Communities attribute. */
|
||||
struct ecommunity *ecommunity;
|
||||
|
||||
|
||||
/* Large Communities attribute. */
|
||||
struct lcommunity *lcommunity;
|
||||
|
||||
/* Route-Reflector Cluster attribute */
|
||||
struct cluster_list *cluster;
|
||||
|
||||
|
320
bgpd/bgp_clist.c
320
bgpd/bgp_clist.c
@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_community.h"
|
||||
#include "bgpd/bgp_ecommunity.h"
|
||||
#include "bgpd/bgp_lcommunity.h"
|
||||
#include "bgpd/bgp_aspath.h"
|
||||
#include "bgpd/bgp_regex.h"
|
||||
#include "bgpd/bgp_clist.h"
|
||||
@ -42,9 +43,11 @@ community_list_master_lookup (struct community_list_handler *ch, int master)
|
||||
switch (master)
|
||||
{
|
||||
case COMMUNITY_LIST_MASTER:
|
||||
return &ch->community_list;
|
||||
return &ch->community_list;
|
||||
case EXTCOMMUNITY_LIST_MASTER:
|
||||
return &ch->extcommunity_list;
|
||||
return &ch->extcommunity_list;
|
||||
case LARGE_COMMUNITY_LIST_MASTER:
|
||||
return &ch->lcommunity_list;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -66,6 +69,10 @@ community_entry_free (struct community_entry *entry)
|
||||
if (entry->u.com)
|
||||
community_free (entry->u.com);
|
||||
break;
|
||||
case LARGE_COMMUNITY_LIST_STANDARD:
|
||||
if (entry->u.lcom)
|
||||
lcommunity_free (&entry->u.lcom);
|
||||
break;
|
||||
case EXTCOMMUNITY_LIST_STANDARD:
|
||||
/* In case of standard extcommunity-list, configuration string
|
||||
is made by ecommunity_ecom2str(). */
|
||||
@ -76,6 +83,7 @@ community_entry_free (struct community_entry *entry)
|
||||
break;
|
||||
case COMMUNITY_LIST_EXPANDED:
|
||||
case EXTCOMMUNITY_LIST_EXPANDED:
|
||||
case LARGE_COMMUNITY_LIST_EXPANDED:
|
||||
if (entry->config)
|
||||
XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
|
||||
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))
|
||||
return entry;
|
||||
break;
|
||||
case LARGE_COMMUNITY_LIST_STANDARD:
|
||||
if (entry->direct == direct && lcommunity_cmp (entry->u.lcom, arg))
|
||||
return entry;
|
||||
break;
|
||||
case COMMUNITY_LIST_EXPANDED:
|
||||
case EXTCOMMUNITY_LIST_EXPANDED:
|
||||
case LARGE_COMMUNITY_LIST_EXPANDED:
|
||||
if (entry->direct == direct && strcmp (entry->config, arg) == 0)
|
||||
return entry;
|
||||
break;
|
||||
@ -399,15 +412,14 @@ community_str_get (struct community *com, int i)
|
||||
}
|
||||
|
||||
/* Internal function to perform regular expression match for
|
||||
* * a single community. */
|
||||
* a single community. */
|
||||
static int
|
||||
community_regexp_include (regex_t * reg, struct community *com, int i)
|
||||
{
|
||||
char *str;
|
||||
int rv;
|
||||
|
||||
/* When there is no communities attribute it is treated as empty
|
||||
* string. */
|
||||
/* When there is no communities attribute it is treated as empty string. */
|
||||
if (com == NULL || com->size == 0)
|
||||
str = XSTRDUP(MTYPE_COMMUNITY_STR, "");
|
||||
else
|
||||
@ -447,6 +459,90 @@ community_regexp_match (struct community *com, regex_t * reg)
|
||||
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
|
||||
ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg)
|
||||
{
|
||||
@ -546,6 +642,30 @@ community_list_match (struct community *com, struct community_list *list)
|
||||
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
|
||||
ecommunity_list_match (struct ecommunity *ecom, struct community_list *list)
|
||||
{
|
||||
@ -694,12 +814,17 @@ community_list_dup_check (struct community_list *list,
|
||||
if (community_cmp (entry->u.com, new->u.com))
|
||||
return 1;
|
||||
break;
|
||||
case LARGE_COMMUNITY_LIST_STANDARD:
|
||||
if (lcommunity_cmp (entry->u.lcom, new->u.lcom))
|
||||
return 1;
|
||||
break;
|
||||
case EXTCOMMUNITY_LIST_STANDARD:
|
||||
if (ecommunity_cmp (entry->u.ecom, new->u.ecom))
|
||||
return 1;
|
||||
break;
|
||||
case COMMUNITY_LIST_EXPANDED:
|
||||
case EXTCOMMUNITY_LIST_EXPANDED:
|
||||
case LARGE_COMMUNITY_LIST_EXPANDED:
|
||||
if (strcmp (entry->config, new->config) == 0)
|
||||
return 1;
|
||||
break;
|
||||
@ -817,6 +942,185 @@ community_list_unset (struct community_list_handler *ch,
|
||||
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. */
|
||||
int
|
||||
extcommunity_list_set (struct community_list_handler *ch,
|
||||
@ -959,6 +1263,12 @@ community_list_terminate (struct community_list_handler *ch)
|
||||
while ((list = cm->str.head) != NULL)
|
||||
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;
|
||||
while ((list = cm->num.head) != NULL)
|
||||
community_list_delete (list);
|
||||
|
@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
/* Master Community-list. */
|
||||
#define COMMUNITY_LIST_MASTER 0
|
||||
#define EXTCOMMUNITY_LIST_MASTER 1
|
||||
#define LARGE_COMMUNITY_LIST_MASTER 2
|
||||
|
||||
/* Community-list deny and permit. */
|
||||
#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 EXTCOMMUNITY_LIST_STANDARD 2 /* Standard 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. */
|
||||
struct community_list
|
||||
@ -80,6 +83,7 @@ struct community_entry
|
||||
{
|
||||
struct community *com;
|
||||
struct ecommunity *ecom;
|
||||
struct lcommunity *lcom;
|
||||
} u;
|
||||
|
||||
/* Configuration string. */
|
||||
@ -112,6 +116,9 @@ struct community_list_handler
|
||||
|
||||
/* Exteded community-list. */
|
||||
struct community_list_master extcommunity_list;
|
||||
|
||||
/* Large community-list. */
|
||||
struct community_list_master lcommunity_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,
|
||||
const char *name, const char *str,
|
||||
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 *
|
||||
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 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 *,
|
||||
struct community_list *);
|
||||
extern struct community *
|
||||
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 */
|
||||
|
@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_ecommunity.h"
|
||||
#include "bgpd/bgp_lcommunity.h"
|
||||
#include "bgpd/bgp_aspath.h"
|
||||
|
||||
/* 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_attr.h"
|
||||
#include "bgpd/bgp_ecommunity.h"
|
||||
#include "bgpd/bgp_lcommunity.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
#include "bgpd/bgp_vty.h"
|
||||
#include "bgpd/bgp_encap.h"
|
||||
|
@ -24,14 +24,8 @@
|
||||
|
||||
extern void bgp_encap_init (void);
|
||||
extern int bgp_nlri_parse_encap (struct peer *, struct attr *, struct bgp_nlri *);
|
||||
int
|
||||
bgp_show_encap (
|
||||
struct vty *vty,
|
||||
afi_t afi,
|
||||
struct prefix_rd *prd,
|
||||
enum bgp_show_type type,
|
||||
void *output_arg,
|
||||
int tags);
|
||||
extern int bgp_show_encap (struct vty *vty, afi_t afi, struct prefix_rd *prd,
|
||||
enum bgp_show_type type, void *output_arg, int tags);
|
||||
|
||||
#include "bgp_encap_types.h"
|
||||
#endif /* _QUAGGA_BGP_ENCAP_H */
|
||||
|
569
bgpd/bgp_lcommunity.c
Normal file
569
bgpd/bgp_lcommunity.c
Normal file
@ -0,0 +1,569 @@
|
||||
/* BGP Large Communities Attribute
|
||||
*
|
||||
* Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
|
||||
*
|
||||
* This file is part of FreeRangeRouting (FRR).
|
||||
*
|
||||
* FRR 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.
|
||||
*
|
||||
* FRR 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 FRR; 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;
|
||||
}
|
||||
|
||||
static void
|
||||
lcommunity_hash_free (struct lcommunity *lcom)
|
||||
{
|
||||
lcommunity_free (&lcom);
|
||||
}
|
||||
|
||||
/* 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_clean (lcomhash, (void (*)(void *))lcommunity_hash_free);
|
||||
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++;
|
||||
}
|
||||
}
|
74
bgpd/bgp_lcommunity.h
Normal file
74
bgpd/bgp_lcommunity.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* BGP Large Communities Attribute.
|
||||
*
|
||||
* Copyright (C) 2016 Keyur Patel <keyur@arrcus.com>
|
||||
*
|
||||
* This file is part of FreeRangeRouting (FRR).
|
||||
*
|
||||
* FRR 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.
|
||||
*
|
||||
* FRR 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 FRR; 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_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_VALUE)
|
||||
|
||||
DECLARE_MTYPE(LCOMMUNITY)
|
||||
DECLARE_MTYPE(LCOMMUNITY_STR)
|
||||
DECLARE_MTYPE(LCOMMUNITY_VAL)
|
||||
#endif /* _QUAGGA_BGP_MEMORY_H */
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "bgpd/bgp_aspath.h"
|
||||
#include "bgpd/bgp_community.h"
|
||||
#include "bgpd/bgp_ecommunity.h"
|
||||
#include "bgpd/bgp_lcommunity.h"
|
||||
#include "bgpd/bgp_mpath.h"
|
||||
|
||||
/*
|
||||
@ -662,6 +663,7 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
|
||||
u_char origin;
|
||||
struct community *community, *commerge;
|
||||
struct ecommunity *ecomm, *ecommerge;
|
||||
struct lcommunity *lcomm, *lcommerge;
|
||||
struct attr_extra *ae;
|
||||
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;
|
||||
ae = attr.extra;
|
||||
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;
|
||||
mpinfo = bgp_info_mpath_next (mpinfo))
|
||||
@ -733,6 +736,17 @@ bgp_info_mpath_aggregate_update (struct bgp_info *new_best,
|
||||
else
|
||||
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;
|
||||
|
@ -566,6 +566,7 @@ DEFUN (no_vpnv6_network,
|
||||
return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg);
|
||||
}
|
||||
|
||||
#if defined(KEEP_OLD_VPN_COMMANDS)
|
||||
static int
|
||||
show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, u_char use_json, afi_t afi)
|
||||
{
|
||||
@ -732,6 +733,7 @@ show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd, u
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd,
|
||||
|
@ -30,6 +30,10 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
|
||||
#define RD_ADDRSTRLEN 28
|
||||
|
||||
#ifdef MPLS_LABEL_MAX
|
||||
# undef MPLS_LABEL_MAX
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
MPLS_LABEL_IPV4_EXPLICIT_NULL = 0, /* [RFC3032] */
|
||||
MPLS_LABEL_ROUTER_ALERT = 1, /* [RFC3032] */
|
||||
@ -45,7 +49,9 @@ typedef enum {
|
||||
MPLS_LABEL_UNASSIGNED11 = 11,
|
||||
MPLS_LABEL_GAL = 13, /* [RFC5586] */
|
||||
MPLS_LABEL_OAM_ALERT = 14, /* [RFC3429] */
|
||||
MPLS_LABEL_EXTENSION = 15 /* [RFC7274] */
|
||||
MPLS_LABEL_EXTENSION = 15, /* [RFC7274] */
|
||||
MPLS_LABEL_MAX = 1048575,
|
||||
MPLS_LABEL_ILLEGAL = 0xFFFFFFFF /* for internal use only */
|
||||
} mpls_special_label_t;
|
||||
|
||||
#define MPLS_LABEL_IS_SPECIAL(label) \
|
||||
@ -100,8 +106,7 @@ extern char *prefix_rd2str (struct prefix_rd *, char *, size_t);
|
||||
|
||||
extern int
|
||||
argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc, int *index, afi_t *afi);
|
||||
int
|
||||
bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd,
|
||||
enum bgp_show_type type, void *output_arg, int tags, u_char use_json);
|
||||
extern int bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd,
|
||||
enum bgp_show_type type, void *output_arg, int tags, u_char use_json);
|
||||
|
||||
#endif /* _QUAGGA_BGP_MPLSVPN_H */
|
||||
|
@ -492,7 +492,7 @@ bgp_show_all_instances_nexthops_vty (struct vty *vty)
|
||||
|
||||
DEFUN (show_ip_bgp_nexthop,
|
||||
show_ip_bgp_nexthop_cmd,
|
||||
"show [ip] bgp [<view|vrf> VRFNAME] nexthop [detail]",
|
||||
"show [ip] bgp [<view|vrf> WORD] nexthop [detail]",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
@ -501,7 +501,7 @@ DEFUN (show_ip_bgp_nexthop,
|
||||
"Show detailed information\n")
|
||||
{
|
||||
int idx = 0;
|
||||
char *vrf = argv_find (argv, argc, "VRFNAME", &idx) ? argv[idx]->arg : NULL;
|
||||
char *vrf = argv_find (argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;
|
||||
int detail = argv_find (argv, argc, "detail", &idx) ? 1 : 0;
|
||||
return show_ip_bgp_nexthop_table (vty, vrf, detail);
|
||||
}
|
||||
|
@ -188,7 +188,9 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
|
||||
{
|
||||
struct capability_mp_data mpc;
|
||||
struct stream *s = BGP_INPUT (peer);
|
||||
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
|
||||
/* Verify length is 4 */
|
||||
if (hdr->length != 4)
|
||||
{
|
||||
@ -204,14 +206,14 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
|
||||
peer->host, mpc.afi, mpc.safi);
|
||||
|
||||
/* Convert AFI, SAFI to internal values, check. */
|
||||
if (bgp_map_afi_safi_iana2int (mpc.afi, mpc.safi, &mpc.afi, &mpc.safi))
|
||||
if (bgp_map_afi_safi_iana2int (mpc.afi, mpc.safi, &afi, &safi))
|
||||
return -1;
|
||||
|
||||
/* Now safi remapped, and afi/safi are valid array indices */
|
||||
peer->afc_recv[mpc.afi][mpc.safi] = 1;
|
||||
peer->afc_recv[afi][safi] = 1;
|
||||
|
||||
if (peer->afc[mpc.afi][mpc.safi])
|
||||
peer->afc_nego[mpc.afi][mpc.safi] = 1;
|
||||
if (peer->afc[afi][safi])
|
||||
peer->afc_nego[afi][safi] = 1;
|
||||
else
|
||||
return -1;
|
||||
|
||||
@ -219,7 +221,7 @@ bgp_capability_mp (struct peer *peer, struct capability_header *hdr)
|
||||
}
|
||||
|
||||
static void
|
||||
bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi,
|
||||
bgp_capability_orf_not_support (struct peer *peer, iana_afi_t afi, safi_t safi,
|
||||
u_char type, u_char mode)
|
||||
{
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
@ -247,7 +249,8 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
|
||||
{
|
||||
struct stream *s = BGP_INPUT (peer);
|
||||
struct capability_orf_entry entry;
|
||||
afi_t pkt_afi, afi;
|
||||
iana_afi_t pkt_afi;
|
||||
afi_t afi;
|
||||
safi_t pkt_safi, safi;
|
||||
u_char type;
|
||||
u_char mode;
|
||||
@ -274,7 +277,7 @@ bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
entry.mpc.afi = afi;
|
||||
entry.mpc.afi = pkt_afi;
|
||||
entry.mpc.safi = safi;
|
||||
|
||||
/* validate number field */
|
||||
@ -418,7 +421,7 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)
|
||||
{
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
afi_t pkt_afi = stream_getw (s);
|
||||
iana_afi_t pkt_afi = stream_getw (s);
|
||||
safi_t pkt_safi = stream_getc (s);
|
||||
u_char flag = stream_getc (s);
|
||||
|
||||
@ -496,7 +499,7 @@ bgp_capability_addpath (struct peer *peer, struct capability_header *hdr)
|
||||
{
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
afi_t pkt_afi = stream_getw (s);
|
||||
iana_afi_t pkt_afi = stream_getw (s);
|
||||
safi_t pkt_safi = stream_getc (s);
|
||||
u_char send_receive = stream_getc (s);
|
||||
|
||||
@ -550,9 +553,11 @@ bgp_capability_enhe (struct peer *peer, struct capability_header *hdr)
|
||||
|
||||
while (stream_get_getp (s) + 6 <= end)
|
||||
{
|
||||
afi_t afi, pkt_afi = stream_getw (s);
|
||||
iana_afi_t pkt_afi = stream_getw (s);
|
||||
afi_t afi;
|
||||
safi_t safi, pkt_safi = stream_getw (s);
|
||||
afi_t nh_afi, pkt_nh_afi = stream_getw (s);
|
||||
iana_afi_t pkt_nh_afi = stream_getw (s);
|
||||
afi_t nh_afi;
|
||||
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug ("%s Received with afi/safi/next-hop afi: %u/%u/%u",
|
||||
@ -1162,7 +1167,7 @@ bgp_open_capability_orf (struct stream *s, struct peer *peer,
|
||||
unsigned long orfp;
|
||||
unsigned long numberp;
|
||||
int number_of_orfs = 0;
|
||||
afi_t pkt_afi;
|
||||
iana_afi_t pkt_afi;
|
||||
safi_t pkt_safi;
|
||||
|
||||
/* Convert AFI, SAFI to values for packet. */
|
||||
@ -1225,7 +1230,8 @@ bgp_open_capability (struct stream *s, struct peer *peer)
|
||||
{
|
||||
u_char len;
|
||||
unsigned long cp, capp, rcapp;
|
||||
afi_t afi, pkt_afi;
|
||||
iana_afi_t pkt_afi;
|
||||
afi_t afi;
|
||||
safi_t safi, pkt_safi;
|
||||
as_t local_as;
|
||||
u_int32_t restart_time;
|
||||
|
@ -31,7 +31,7 @@ struct capability_header
|
||||
/* Generic MP capability data */
|
||||
struct capability_mp_data
|
||||
{
|
||||
afi_t afi;
|
||||
iana_afi_t afi;
|
||||
u_char reserved;
|
||||
safi_t safi;
|
||||
};
|
||||
|
@ -46,6 +46,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "bgpd/bgp_aspath.h"
|
||||
#include "bgpd/bgp_community.h"
|
||||
#include "bgpd/bgp_ecommunity.h"
|
||||
#include "bgpd/bgp_lcommunity.h"
|
||||
#include "bgpd/bgp_network.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
#include "bgpd/bgp_encap.h"
|
||||
@ -147,7 +148,7 @@ static struct stream *
|
||||
bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi)
|
||||
{
|
||||
struct stream *s;
|
||||
afi_t pkt_afi;
|
||||
iana_afi_t pkt_afi;
|
||||
safi_t pkt_safi;
|
||||
|
||||
if (DISABLE_BGP_ANNOUNCE)
|
||||
@ -695,7 +696,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
|
||||
struct stream *s;
|
||||
struct bgp_filter *filter;
|
||||
int orf_refresh = 0;
|
||||
afi_t pkt_afi;
|
||||
iana_afi_t pkt_afi;
|
||||
safi_t pkt_safi;
|
||||
|
||||
if (DISABLE_BGP_ANNOUNCE)
|
||||
@ -782,7 +783,7 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,
|
||||
int capability_code, int action)
|
||||
{
|
||||
struct stream *s;
|
||||
afi_t pkt_afi;
|
||||
iana_afi_t pkt_afi;
|
||||
safi_t pkt_safi;
|
||||
|
||||
/* Convert AFI, SAFI to values for packet. */
|
||||
@ -1711,7 +1712,8 @@ bgp_keepalive_receive (struct peer *peer, bgp_size_t size)
|
||||
static void
|
||||
bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
|
||||
{
|
||||
afi_t pkt_afi, afi;
|
||||
iana_afi_t pkt_afi;
|
||||
afi_t afi;
|
||||
safi_t pkt_safi, safi;
|
||||
struct stream *s;
|
||||
struct peer_af *paf;
|
||||
@ -1932,7 +1934,8 @@ bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
|
||||
struct capability_mp_data mpc;
|
||||
struct capability_header *hdr;
|
||||
u_char action;
|
||||
afi_t pkt_afi, afi;
|
||||
iana_afi_t pkt_afi;
|
||||
afi_t afi;
|
||||
safi_t pkt_safi, safi;
|
||||
|
||||
end = pnt + length;
|
||||
@ -2153,15 +2156,6 @@ bgp_marker_all_one (struct stream *s, int length)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Recent thread time.
|
||||
On same clock base as bgp_clock (MONOTONIC)
|
||||
but can be time of last context switch to bgp_read thread. */
|
||||
static time_t
|
||||
bgp_recent_clock (void)
|
||||
{
|
||||
return recent_relative_time().tv_sec;
|
||||
}
|
||||
|
||||
/* Starting point of packet process function. */
|
||||
int
|
||||
bgp_read (struct thread *thread)
|
||||
@ -2288,14 +2282,14 @@ bgp_read (struct thread *thread)
|
||||
bgp_open_receive (peer, size); /* XXX return value ignored! */
|
||||
break;
|
||||
case BGP_MSG_UPDATE:
|
||||
peer->readtime = bgp_recent_clock ();
|
||||
peer->readtime = monotime (NULL);
|
||||
bgp_update_receive (peer, size);
|
||||
break;
|
||||
case BGP_MSG_NOTIFY:
|
||||
bgp_notify_receive (peer, size);
|
||||
break;
|
||||
case BGP_MSG_KEEPALIVE:
|
||||
peer->readtime = bgp_recent_clock ();
|
||||
peer->readtime = monotime (NULL);
|
||||
bgp_keepalive_receive (peer, size);
|
||||
break;
|
||||
case BGP_MSG_ROUTE_REFRESH_NEW:
|
||||
|
952
bgpd/bgp_route.c
952
bgpd/bgp_route.c
File diff suppressed because it is too large
Load Diff
@ -41,6 +41,9 @@ enum bgp_show_type
|
||||
bgp_show_type_community_exact,
|
||||
bgp_show_type_community_list,
|
||||
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_neighbor,
|
||||
bgp_show_type_dampend_paths,
|
||||
|
@ -52,6 +52,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "bgpd/bgp_filter.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
#include "bgpd/bgp_ecommunity.h"
|
||||
#include "bgpd/bgp_lcommunity.h"
|
||||
#include "bgpd/bgp_vty.h"
|
||||
#include "bgpd/bgp_debug.h"
|
||||
|
||||
@ -84,6 +85,8 @@ o Cisco route-map
|
||||
as-path tag : Not yet
|
||||
automatic-tag : (This will not be implemented by bgpd)
|
||||
community : Done
|
||||
large-community : Done
|
||||
large-comm-list : Done
|
||||
comm-list : Not yet
|
||||
dampning : Not yet
|
||||
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
|
||||
};
|
||||
|
||||
/* 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. */
|
||||
static route_map_result_t
|
||||
route_match_ecommunity (void *rule, struct prefix *prefix,
|
||||
@ -1544,6 +1619,224 @@ struct route_map_rule_cmd route_set_community_cmd =
|
||||
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 intern()'d or attr_flush()'d by bgp_update_main() */
|
||||
(bgp_attr_extra_get (attr))->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' */
|
||||
|
||||
/* For community set mechanism. */
|
||||
@ -3164,7 +3457,32 @@ DEFUN (no_match_community,
|
||||
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,
|
||||
match_ecommunity_cmd,
|
||||
@ -3597,6 +3915,95 @@ DEFUN (no_set_community_delete,
|
||||
"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",
|
||||
NO_STR
|
||||
SET_STR
|
||||
"BGP large community attribute\n"
|
||||
"No community attribute\n")
|
||||
{
|
||||
return generic_set_delete (vty, VTY_GET_CONTEXT(route_map_index),
|
||||
"large-community", NULL);
|
||||
}
|
||||
|
||||
DEFUN (no_set_lcommunity1,
|
||||
no_set_lcommunity1_cmd,
|
||||
"no set large-community AA:BB:CC...",
|
||||
NO_STR
|
||||
SET_STR
|
||||
"BGP large community attribute\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,
|
||||
set_ecommunity_rt_cmd,
|
||||
@ -3992,7 +4399,7 @@ DEFUN (no_set_vpn_nexthop,
|
||||
|
||||
DEFUN (set_ipx_vpn_nexthop,
|
||||
set_ipx_vpn_nexthop_cmd,
|
||||
"set <ipv4|ipv6> vpn next-hop [A.B.C.D|X:X::X:X]",
|
||||
"set <ipv4|ipv6> vpn next-hop [<A.B.C.D|X:X::X:X>]",
|
||||
SET_STR
|
||||
"IPv4 information\n"
|
||||
"IPv6 information\n"
|
||||
@ -4019,7 +4426,7 @@ DEFUN (set_ipx_vpn_nexthop,
|
||||
|
||||
DEFUN (no_set_ipx_vpn_nexthop,
|
||||
no_set_ipx_vpn_nexthop_cmd,
|
||||
"no set <ipv4|ipv6> vpn next-hop [A.B.C.D|X:X::X:X]",
|
||||
"no set <ipv4|ipv6> vpn next-hop [<A.B.C.D|X:X::X:X>]",
|
||||
NO_STR
|
||||
SET_STR
|
||||
"IPv4 information\n"
|
||||
@ -4139,6 +4546,7 @@ bgp_route_map_init (void)
|
||||
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_community_cmd);
|
||||
route_map_install_match (&route_match_lcommunity_cmd);
|
||||
route_map_install_match (&route_match_ecommunity_cmd);
|
||||
route_map_install_match (&route_match_local_pref_cmd);
|
||||
route_map_install_match (&route_match_metric_cmd);
|
||||
@ -4158,6 +4566,8 @@ bgp_route_map_init (void)
|
||||
route_map_install_set (&route_set_aggregator_as_cmd);
|
||||
route_map_install_set (&route_set_community_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_vpnv6_nexthop_cmd);
|
||||
route_map_install_set (&route_set_originator_id_cmd);
|
||||
@ -4180,6 +4590,8 @@ bgp_route_map_init (void)
|
||||
install_element (RMAP_NODE, &match_community_cmd);
|
||||
install_element (RMAP_NODE, &match_community_exact_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, &no_match_ecommunity_cmd);
|
||||
install_element (RMAP_NODE, &match_origin_cmd);
|
||||
@ -4209,6 +4621,12 @@ bgp_route_map_init (void)
|
||||
install_element (RMAP_NODE, &no_set_community_cmd);
|
||||
install_element (RMAP_NODE, &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, &no_set_lcommunity1_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, &no_set_ecommunity_rt_cmd);
|
||||
install_element (RMAP_NODE, &set_ecommunity_soo_cmd);
|
||||
|
570
bgpd/bgp_vty.c
570
bgpd/bgp_vty.c
@ -41,14 +41,15 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "bgpd/bgp_aspath.h"
|
||||
#include "bgpd/bgp_community.h"
|
||||
#include "bgpd/bgp_ecommunity.h"
|
||||
#include "bgpd/bgp_lcommunity.h"
|
||||
#include "bgpd/bgp_damp.h"
|
||||
#include "bgpd/bgp_debug.h"
|
||||
#include "bgpd/bgp_fsm.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
#include "bgpd/bgp_nexthop.h"
|
||||
#include "bgpd/bgp_open.h"
|
||||
#include "bgpd/bgp_regex.h"
|
||||
#include "bgpd/bgp_route.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
#include "bgpd/bgp_zebra.h"
|
||||
#include "bgpd/bgp_table.h"
|
||||
#include "bgpd/bgp_vty.h"
|
||||
@ -167,17 +168,7 @@ bgp_vty_safi_from_arg(const char *safi_str)
|
||||
}
|
||||
|
||||
int
|
||||
bgp_parse_safi(const char *str, safi_t *safi)
|
||||
{
|
||||
*safi = bgp_vty_safi_from_arg(str);
|
||||
if (*safi != SAFI_MAX)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t *safi)
|
||||
argv_find_and_parse_safi (struct cmd_token **argv, int argc, int *index, safi_t *safi)
|
||||
{
|
||||
int ret = 0;
|
||||
if (argv_find (argv, argc, "unicast", index))
|
||||
@ -207,6 +198,80 @@ argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t *
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* bgp_vty_find_and_parse_afi_safi_vrf
|
||||
*
|
||||
* For a given 'show ...' command, correctly parse the afi/safi/vrf out from it
|
||||
* This function *assumes* that the calling function pre-sets the afi/safi/vrf
|
||||
* to appropriate values for the calling function. This is to allow the
|
||||
* calling function to make decisions appropriate for the show command
|
||||
* that is being parsed.
|
||||
*
|
||||
* The show commands are generally of the form:
|
||||
* "show [ip] bgp [<view|vrf> WORD] [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]] ..."
|
||||
*
|
||||
* Since we use argv_find if the show command in particular doesn't have:
|
||||
* [ip]
|
||||
* [<view|vrf> WORD]
|
||||
* [<ipv4|ipv6> [<unicast|multicast|vpn|encap>]]
|
||||
* The command parsing should still be ok.
|
||||
*
|
||||
* vty -> The vty for the command so we can output some useful data in
|
||||
* the event of a parse error in the vrf.
|
||||
* argv -> The command tokens
|
||||
* argc -> How many command tokens we have
|
||||
* idx -> The current place in the command, generally should be 0 for this function
|
||||
* afi -> The parsed afi if it was included in the show command, returned here
|
||||
* safi -> The parsed safi if it was included in the show command, returned here
|
||||
* vrf -> The parsed vrf id if it was included in the show command, returned here
|
||||
*
|
||||
* The function returns the correct location in the parse tree for the
|
||||
* last token found.
|
||||
*
|
||||
* Returns 0 for failure to parse correctly, else the idx position of where
|
||||
* it found the last token.
|
||||
*/
|
||||
int
|
||||
bgp_vty_find_and_parse_afi_safi_vrf (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
|
||||
afi_t *afi, safi_t *safi, vrf_id_t *vrf)
|
||||
{
|
||||
char *vrf_name = NULL;
|
||||
|
||||
assert (afi);
|
||||
assert (safi);
|
||||
assert (vrf && *vrf != VRF_UNKNOWN);
|
||||
|
||||
if (argv_find (argv, argc, "ip", idx))
|
||||
*afi = AFI_IP;
|
||||
|
||||
if (argv_find (argv, argc, "view", idx) || argv_find (argv, argc, "vrf", idx))
|
||||
{
|
||||
vrf_name = argv[*idx + 1]->arg;
|
||||
*idx += 2;
|
||||
}
|
||||
|
||||
if (argv_find_and_parse_afi (argv, argc, idx, afi))
|
||||
argv_find_and_parse_safi (argv, argc, idx, safi);
|
||||
|
||||
if (vrf_name)
|
||||
{
|
||||
if (strmatch(vrf_name, "all"))
|
||||
*vrf = VRF_ALL;
|
||||
else
|
||||
*vrf = vrf_name_to_id (vrf_name);
|
||||
}
|
||||
|
||||
if (*vrf == VRF_UNKNOWN)
|
||||
{
|
||||
vty_out (vty, "View/Vrf specified is unknown: %s", vrf_name);
|
||||
*idx = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*idx += 1;
|
||||
return *idx;
|
||||
}
|
||||
|
||||
static int
|
||||
peer_address_self_check (struct bgp *bgp, union sockunion *su)
|
||||
{
|
||||
@ -3748,13 +3813,15 @@ DEFUN (no_neighbor_send_community,
|
||||
/* neighbor send-community extended. */
|
||||
DEFUN (neighbor_send_community_type,
|
||||
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_ADDR_STR2
|
||||
"Send Community attribute to this neighbor\n"
|
||||
"Send Standard and Extended Community attributes\n"
|
||||
"Send Standard, Large and 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;
|
||||
u_int32_t flag = 0;
|
||||
@ -3765,25 +3832,35 @@ DEFUN (neighbor_send_community_type,
|
||||
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
|
||||
else if (argv_find (argv, argc, "extended", &idx))
|
||||
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
|
||||
{
|
||||
SET_FLAG (flag, PEER_FLAG_SEND_COMMUNITY);
|
||||
SET_FLAG (flag, PEER_FLAG_SEND_EXT_COMMUNITY);
|
||||
}
|
||||
{
|
||||
SET_FLAG (flag, PEER_FLAG_SEND_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);
|
||||
}
|
||||
|
||||
DEFUN (no_neighbor_send_community_type,
|
||||
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
|
||||
NEIGHBOR_STR
|
||||
NEIGHBOR_ADDR_STR2
|
||||
"Send Community attribute to this neighbor\n"
|
||||
"Send Standard and Extended Community attributes\n"
|
||||
"Send Standard, Large and 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_type = 4;
|
||||
@ -3795,11 +3872,21 @@ DEFUN (no_neighbor_send_community_type,
|
||||
return peer_af_flag_unset_vty (vty, argv[idx_peer]->arg, bgp_node_afi (vty),
|
||||
bgp_node_safi (vty),
|
||||
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),
|
||||
bgp_node_safi (vty),
|
||||
(PEER_FLAG_SEND_COMMUNITY |
|
||||
PEER_FLAG_SEND_EXT_COMMUNITY));
|
||||
PEER_FLAG_SEND_EXT_COMMUNITY|
|
||||
PEER_FLAG_SEND_LARGE_COMMUNITY));
|
||||
}
|
||||
|
||||
/* neighbor soft-reconfig. */
|
||||
@ -5586,7 +5673,7 @@ DEFUN (address_family_vpnv6,
|
||||
vty->node = BGP_VPNV6_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
#endif /* KEEP_OLD_VPN_COMMANDS */
|
||||
#endif
|
||||
|
||||
DEFUN (address_family_encap,
|
||||
address_family_encap_cmd,
|
||||
@ -6134,6 +6221,12 @@ DEFUN (show_bgp_memory,
|
||||
mtype_memstr (memstrbuf, sizeof (memstrbuf),
|
||||
count * sizeof (struct ecommunity)),
|
||||
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)))
|
||||
vty_out (vty, "%ld Cluster lists, using %s of memory%s", count,
|
||||
@ -7111,12 +7204,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))
|
||||
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)
|
||||
|| 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");
|
||||
if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_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_EXT_COMMUNITY)
|
||||
&& 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))
|
||||
vty_out (vty, "(extended)%s", VTY_NEWLINE);
|
||||
else
|
||||
@ -8559,7 +8656,7 @@ DEFUN (show_ip_bgp_neighbors,
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
BGP_INSTANCE_ALL_HELP_STR
|
||||
BGP_INSTANCE_HELP_STR
|
||||
"Address Family\n"
|
||||
"Address Family\n"
|
||||
"Address Family\n"
|
||||
@ -8644,6 +8741,36 @@ DEFUN (show_ip_bgp_community_info,
|
||||
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,
|
||||
show_ip_bgp_attr_info_cmd,
|
||||
"show [ip] bgp attribute-info",
|
||||
@ -9195,7 +9322,7 @@ bgp_show_peer_group_vty (struct vty *vty, const char *name,
|
||||
|
||||
DEFUN (show_ip_bgp_peer_groups,
|
||||
show_ip_bgp_peer_groups_cmd,
|
||||
"show [ip] bgp [<view|vrf> VRFNAME] peer-group [PGNAME]",
|
||||
"show [ip] bgp [<view|vrf> WORD] peer-group [PGNAME]",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
@ -9207,7 +9334,7 @@ DEFUN (show_ip_bgp_peer_groups,
|
||||
vrf = pg = NULL;
|
||||
int idx = 0;
|
||||
|
||||
vrf = argv_find (argv, argc, "VRFNAME", &idx) ? argv[idx]->arg : NULL;
|
||||
vrf = argv_find (argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL;
|
||||
pg = argv_find (argv, argc, "PGNAME", &idx) ? argv[idx]->arg : NULL;
|
||||
|
||||
return bgp_show_peer_group_vty (vty, vrf, show_all_groups, pg);
|
||||
@ -10695,6 +10822,7 @@ bgp_vty_init (void)
|
||||
install_element (BGP_NODE, &address_family_vpnv4_cmd);
|
||||
install_element (BGP_NODE, &address_family_vpnv6_cmd);
|
||||
#endif /* KEEP_OLD_VPN_COMMANDS */
|
||||
|
||||
install_element (BGP_NODE, &address_family_encap_cmd);
|
||||
install_element (BGP_NODE, &address_family_encapv6_cmd);
|
||||
|
||||
@ -10745,6 +10873,8 @@ bgp_vty_init (void)
|
||||
/* "show [ip] bgp community" commands. */
|
||||
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. */
|
||||
install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd);
|
||||
|
||||
@ -11077,6 +11207,350 @@ DEFUN (show_ip_community_list_arg,
|
||||
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>",
|
||||
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_standard1,
|
||||
ip_lcommunity_list_standard1_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>",
|
||||
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")
|
||||
{
|
||||
return lcommunity_list_set_vty (vty, argc, argv, LARGE_COMMUNITY_LIST_STANDARD, 1);
|
||||
}
|
||||
|
||||
DEFUN (ip_lcommunity_list_name_standard1,
|
||||
ip_lcommunity_list_name_standard1_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. */
|
||||
#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"
|
||||
@ -11386,6 +11860,30 @@ community_list_config_write (struct vty *vty)
|
||||
community_list_config_str (entry), VTY_NEWLINE);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -11416,4 +11914,20 @@ community_list_vty (void)
|
||||
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_arg_cmd);
|
||||
|
||||
/* Large Community List */
|
||||
install_element (CONFIG_NODE, &ip_lcommunity_list_standard_cmd);
|
||||
install_element (CONFIG_NODE, &ip_lcommunity_list_standard1_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_standard1_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);
|
||||
}
|
||||
|
@ -51,9 +51,6 @@ peer_and_group_lookup_vty (struct vty *vty, const char *peer_str);
|
||||
extern int
|
||||
bgp_parse_afi(const char *str, afi_t *afi);
|
||||
|
||||
extern int
|
||||
bgp_parse_safi(const char *str, safi_t *safi);
|
||||
|
||||
extern afi_t
|
||||
bgp_vty_afi_from_arg(const char *afi_str);
|
||||
|
||||
@ -66,4 +63,7 @@ argv_find_and_parse_afi(struct cmd_token **argv, int argc, int *index, afi_t *af
|
||||
extern int
|
||||
argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, safi_t *safi);
|
||||
|
||||
extern int
|
||||
bgp_vty_find_and_parse_afi_safi_vrf (struct vty *vty, struct cmd_token **argv, int argc, int *idx,
|
||||
afi_t *afi, safi_t *safi, vrf_id_t *vrf);
|
||||
#endif /* _QUAGGA_BGP_VTY_H */
|
||||
|
33
bgpd/bgpd.c
33
bgpd/bgpd.c
@ -348,7 +348,7 @@ time_t bgp_clock (void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv);
|
||||
monotime(&tv);
|
||||
return tv.tv_sec;
|
||||
}
|
||||
|
||||
@ -652,7 +652,7 @@ bgp_listen_limit_unset (struct bgp *bgp)
|
||||
}
|
||||
|
||||
int
|
||||
bgp_map_afi_safi_iana2int (afi_t pkt_afi, safi_t pkt_safi,
|
||||
bgp_map_afi_safi_iana2int (iana_afi_t pkt_afi, safi_t pkt_safi,
|
||||
afi_t *afi, safi_t *safi)
|
||||
{
|
||||
/* Map from IANA values to internal values, return error if
|
||||
@ -668,7 +668,7 @@ bgp_map_afi_safi_iana2int (afi_t pkt_afi, safi_t pkt_safi,
|
||||
|
||||
int
|
||||
bgp_map_afi_safi_int2iana (afi_t afi, safi_t safi,
|
||||
afi_t *pkt_afi, safi_t *pkt_safi)
|
||||
iana_afi_t *pkt_afi, safi_t *pkt_safi)
|
||||
{
|
||||
/* Map from internal values to IANA values, return error if
|
||||
* internal values are bad (unexpected).
|
||||
@ -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_EXT_COMMUNITY);
|
||||
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
|
||||
}
|
||||
|
||||
/* 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_EXT_COMMUNITY);
|
||||
SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
|
||||
}
|
||||
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_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_REFLECTOR_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 (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,
|
||||
" 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);
|
||||
}
|
||||
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) &&
|
||||
(!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) &&
|
||||
(!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,
|
||||
" 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);
|
||||
}
|
||||
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_WEIGHT (1 << 24) /* weight */
|
||||
#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1 << 25) /* allowas-in origin */
|
||||
#define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 26) /* Send large Communities */
|
||||
|
||||
/* MD5 password */
|
||||
char *password;
|
||||
@ -963,6 +964,7 @@ struct bgp_nlri
|
||||
#define BGP_ATTR_AS4_AGGREGATOR 18
|
||||
#define BGP_ATTR_AS_PATHLIMIT 21
|
||||
#define BGP_ATTR_ENCAP 23
|
||||
#define BGP_ATTR_LARGE_COMMUNITIES 32
|
||||
#if ENABLE_BGP_VNC
|
||||
#define BGP_ATTR_VNC 255
|
||||
#endif
|
||||
@ -1355,11 +1357,11 @@ extern void bgp_route_map_terminate(void);
|
||||
extern int peer_cmp (struct peer *p1, struct peer *p2);
|
||||
|
||||
extern int
|
||||
bgp_map_afi_safi_iana2int (afi_t pkt_afi, safi_t pkt_safi,
|
||||
bgp_map_afi_safi_iana2int (iana_afi_t pkt_afi, safi_t pkt_safi,
|
||||
afi_t *afi, safi_t *safi);
|
||||
extern int
|
||||
bgp_map_afi_safi_int2iana (afi_t afi, safi_t safi,
|
||||
afi_t *pkt_afi, safi_t *pkt_safi);
|
||||
iana_afi_t *pkt_afi, safi_t *pkt_safi);
|
||||
|
||||
extern struct peer_af * peer_af_create (struct peer *, afi_t, safi_t);
|
||||
extern struct peer_af * peer_af_find (struct peer *, afi_t, safi_t);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -41,12 +41,21 @@ struct rfapi_l2_group_cfg
|
||||
};
|
||||
DECLARE_QOBJ_TYPE(rfapi_l2_group_cfg)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RFAPI_GROUP_CFG_NVE = 1,
|
||||
RFAPI_GROUP_CFG_VRF,
|
||||
RFAPI_GROUP_CFG_L2,
|
||||
RFAPI_GROUP_CFG_MAX
|
||||
} rfapi_group_cfg_type_t;
|
||||
|
||||
struct rfapi_nve_group_cfg
|
||||
{
|
||||
struct route_node *vn_node; /* backref */
|
||||
struct route_node *un_node; /* backref */
|
||||
|
||||
char *name;
|
||||
rfapi_group_cfg_type_t type; /* NVE|VPN */
|
||||
char *name; /* unique by type! */
|
||||
struct prefix vn_prefix;
|
||||
struct prefix un_prefix;
|
||||
|
||||
@ -54,8 +63,9 @@ struct rfapi_nve_group_cfg
|
||||
uint8_t l2rd; /* 0 = VN addr LSB */
|
||||
uint32_t response_lifetime;
|
||||
uint32_t flags;
|
||||
#define RFAPI_RFG_RESPONSE_LIFETIME 0x1
|
||||
#define RFAPI_RFG_RESPONSE_LIFETIME 0x01 /* bits */
|
||||
#define RFAPI_RFG_L2RD 0x02
|
||||
#define RFAPI_RFG_VPN_NH_SELF 0x04
|
||||
struct ecommunity *rt_import_list;
|
||||
struct ecommunity *rt_export_list;
|
||||
struct rfapi_import_table *rfapi_import_table;
|
||||
@ -99,6 +109,9 @@ struct rfapi_nve_group_cfg
|
||||
char *routemap_redist_name[ZEBRA_ROUTE_MAX];
|
||||
struct route_map *routemap_redist[ZEBRA_ROUTE_MAX];
|
||||
|
||||
/* for VRF type groups */
|
||||
uint32_t label;
|
||||
struct rfapi_descriptor *rfd;
|
||||
QOBJ_FIELDS
|
||||
};
|
||||
DECLARE_QOBJ_TYPE(rfapi_nve_group_cfg)
|
||||
@ -288,6 +301,12 @@ bgp_rfapi_cfg_match_group (
|
||||
struct prefix *vn,
|
||||
struct prefix *un);
|
||||
|
||||
struct rfapi_nve_group_cfg *
|
||||
bgp_rfapi_cfg_match_byname (
|
||||
struct bgp *bgp,
|
||||
const char *name,
|
||||
rfapi_group_cfg_type_t type); /* _MAX = any */
|
||||
|
||||
extern void
|
||||
vnc_prefix_list_update (struct bgp *bgp);
|
||||
|
||||
|
@ -36,13 +36,13 @@
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_ecommunity.h"
|
||||
#include "bgpd/bgp_attr.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
|
||||
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
|
||||
#include "bgpd/rfapi/rfapi.h"
|
||||
#include "bgpd/rfapi/rfapi_backend.h"
|
||||
|
||||
#include "bgpd/bgp_route.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
#include "bgpd/bgp_aspath.h"
|
||||
#include "bgpd/bgp_advertise.h"
|
||||
#include "bgpd/bgp_vnc_types.h"
|
||||
@ -335,6 +335,9 @@ is_valid_rfd (struct rfapi_descriptor *rfd)
|
||||
if (!rfd || rfd->bgp == NULL)
|
||||
return 0;
|
||||
|
||||
if (CHECK_FLAG(rfd->flags, RFAPI_HD_FLAG_IS_VRF)) /* assume VRF/internal are valid */
|
||||
return 1;
|
||||
|
||||
if (rfapi_find_handle (rfd->bgp, &rfd->vn_addr, &rfd->un_addr, &hh))
|
||||
return 0;
|
||||
|
||||
@ -357,6 +360,9 @@ rfapi_check (void *handle)
|
||||
if (!rfd || rfd->bgp == NULL)
|
||||
return EINVAL;
|
||||
|
||||
if (CHECK_FLAG(rfd->flags, RFAPI_HD_FLAG_IS_VRF)) /* assume VRF/internal are valid */
|
||||
return 0;
|
||||
|
||||
if ((rc = rfapi_find_handle (rfd->bgp, &rfd->vn_addr, &rfd->un_addr, &hh)))
|
||||
return rc;
|
||||
|
||||
@ -1347,7 +1353,6 @@ rfapi_rfp_set_cb_methods (void *rfp_start_val,
|
||||
/***********************************************************************
|
||||
* NVE Sessions
|
||||
***********************************************************************/
|
||||
|
||||
/*
|
||||
* Caller must supply an already-allocated rfd with the "caller"
|
||||
* fields already set (vn_addr, un_addr, callback, cookie)
|
||||
@ -1474,6 +1479,57 @@ rfapi_open_inner (
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* moved from rfapi_register */
|
||||
int
|
||||
rfapi_init_and_open(
|
||||
struct bgp *bgp,
|
||||
struct rfapi_descriptor *rfd,
|
||||
struct rfapi_nve_group_cfg *rfg)
|
||||
{
|
||||
struct rfapi *h = bgp->rfapi;
|
||||
char buf_vn[BUFSIZ];
|
||||
char buf_un[BUFSIZ];
|
||||
afi_t afi_vn, afi_un;
|
||||
struct prefix pfx_un;
|
||||
struct route_node *rn;
|
||||
|
||||
|
||||
rfapi_time (&rfd->open_time);
|
||||
|
||||
if (rfg->type == RFAPI_GROUP_CFG_VRF)
|
||||
SET_FLAG(rfd->flags, RFAPI_HD_FLAG_IS_VRF);
|
||||
|
||||
rfapiRfapiIpAddr2Str (&rfd->vn_addr, buf_vn, BUFSIZ);
|
||||
rfapiRfapiIpAddr2Str (&rfd->un_addr, buf_un, BUFSIZ);
|
||||
|
||||
vnc_zlog_debug_verbose ("%s: new RFD with VN=%s UN=%s cookie=%p",
|
||||
__func__, buf_vn, buf_un, rfd->cookie);
|
||||
|
||||
if (rfg->type != RFAPI_GROUP_CFG_VRF) /* unclear if needed for VRF */
|
||||
{
|
||||
listnode_add (&h->descriptors, rfd);
|
||||
if (h->descriptors.count > h->stat.max_descriptors)
|
||||
{
|
||||
h->stat.max_descriptors = h->descriptors.count;
|
||||
}
|
||||
|
||||
/*
|
||||
* attach to UN radix tree
|
||||
*/
|
||||
afi_vn = family2afi (rfd->vn_addr.addr_family);
|
||||
afi_un = family2afi (rfd->un_addr.addr_family);
|
||||
assert (afi_vn && afi_un);
|
||||
assert (!rfapiRaddr2Qprefix (&rfd->un_addr, &pfx_un));
|
||||
|
||||
rn = route_node_get (&(h->un[afi_un]), &pfx_un);
|
||||
assert (rn);
|
||||
rfd->next = rn->info;
|
||||
rn->info = rfd;
|
||||
rfd->un_node = rn;
|
||||
}
|
||||
return rfapi_open_inner (rfd, bgp, h, rfg);
|
||||
}
|
||||
|
||||
struct rfapi_vn_option *
|
||||
rfapiVnOptionsDup (struct rfapi_vn_option *orig)
|
||||
{
|
||||
@ -1991,14 +2047,10 @@ rfapi_open (
|
||||
struct prefix pfx_vn;
|
||||
struct prefix pfx_un;
|
||||
|
||||
struct route_node *rn;
|
||||
int rc;
|
||||
rfapi_handle hh = NULL;
|
||||
int reusing_provisional = 0;
|
||||
|
||||
afi_t afi_vn;
|
||||
afi_t afi_un;
|
||||
|
||||
{
|
||||
char buf[2][INET_ADDRSTRLEN];
|
||||
vnc_zlog_debug_verbose ("%s: VN=%s UN=%s", __func__,
|
||||
@ -2129,40 +2181,7 @@ rfapi_open (
|
||||
|
||||
if (!reusing_provisional)
|
||||
{
|
||||
rfapi_time (&rfd->open_time);
|
||||
|
||||
{
|
||||
char buf_vn[BUFSIZ];
|
||||
char buf_un[BUFSIZ];
|
||||
|
||||
rfapiRfapiIpAddr2Str (vn, buf_vn, BUFSIZ);
|
||||
rfapiRfapiIpAddr2Str (un, buf_un, BUFSIZ);
|
||||
|
||||
vnc_zlog_debug_verbose ("%s: new HD with VN=%s UN=%s cookie=%p",
|
||||
__func__, buf_vn, buf_un, userdata);
|
||||
}
|
||||
|
||||
listnode_add (&h->descriptors, rfd);
|
||||
if (h->descriptors.count > h->stat.max_descriptors)
|
||||
{
|
||||
h->stat.max_descriptors = h->descriptors.count;
|
||||
}
|
||||
|
||||
/*
|
||||
* attach to UN radix tree
|
||||
*/
|
||||
afi_vn = family2afi (rfd->vn_addr.addr_family);
|
||||
afi_un = family2afi (rfd->un_addr.addr_family);
|
||||
assert (afi_vn && afi_un);
|
||||
assert (!rfapiRaddr2Qprefix (&rfd->un_addr, &pfx_un));
|
||||
|
||||
rn = route_node_get (&(h->un[afi_un]), &pfx_un);
|
||||
assert (rn);
|
||||
rfd->next = rn->info;
|
||||
rn->info = rfd;
|
||||
rfd->un_node = rn;
|
||||
|
||||
rc = rfapi_open_inner (rfd, bgp, h, rfg);
|
||||
rc = rfapi_init_and_open(bgp, rfd, rfg);
|
||||
/*
|
||||
* This can fail only if the VN address is IPv6 and the group
|
||||
* specified auto-assignment of RDs, which only works for v4,
|
||||
@ -2777,7 +2796,7 @@ rfapi_register (
|
||||
NULL,
|
||||
action == RFAPI_REGISTER_KILL);
|
||||
|
||||
if (0 == rfapiApDelete (bgp, rfd, &p, pfx_mac, &adv_tunnel))
|
||||
if (0 == rfapiApDelete (bgp, rfd, &p, pfx_mac, &prd, &adv_tunnel))
|
||||
{
|
||||
if (adv_tunnel)
|
||||
rfapiTunnelRouteAnnounce (bgp, rfd, &rfd->max_prefix_lifetime);
|
||||
|
@ -35,13 +35,13 @@
|
||||
#include "bgpd/bgpd.h"
|
||||
#include "bgpd/bgp_ecommunity.h"
|
||||
#include "bgpd/bgp_attr.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
|
||||
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
|
||||
#include "bgpd/rfapi/rfapi.h"
|
||||
#include "bgpd/rfapi/rfapi_backend.h"
|
||||
|
||||
#include "bgpd/bgp_route.h"
|
||||
#include "bgpd/bgp_mplsvpn.h"
|
||||
#include "bgpd/bgp_aspath.h"
|
||||
#include "bgpd/bgp_advertise.h"
|
||||
|
||||
@ -103,12 +103,11 @@ sl_adb_lifetime_cmp (void *adb1, void *adb2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rfapiApInit (struct rfapi_advertised_prefixes *ap)
|
||||
{
|
||||
ap->ipN_by_prefix = skiplist_new (0, vnc_prefix_cmp, NULL);
|
||||
ap->ip0_by_ether = skiplist_new (0, vnc_prefix_cmp, NULL);
|
||||
ap->ipN_by_prefix = skiplist_new (0, rfapi_rib_key_cmp, NULL);
|
||||
ap->ip0_by_ether = skiplist_new (0, rfapi_rib_key_cmp, NULL);
|
||||
ap->by_lifetime = skiplist_new (0, sl_adb_lifetime_cmp, NULL);
|
||||
}
|
||||
|
||||
@ -192,7 +191,7 @@ rfapiApReadvertiseAll (struct bgp *bgp, struct rfapi_descriptor *rfd)
|
||||
* TBD this is not quite right. When pfx_ip is 0/32 or 0/128,
|
||||
* we need to substitute the VN address as the prefix
|
||||
*/
|
||||
add_vnc_route (rfd, bgp, SAFI_MPLS_VPN, &adb->prefix_ip, &prd, /* RD to use (0 for ENCAP) */
|
||||
add_vnc_route (rfd, bgp, SAFI_MPLS_VPN, &adb->u.s.prefix_ip, &prd, /* RD to use (0 for ENCAP) */
|
||||
&rfd->vn_addr, /* nexthop */
|
||||
&local_pref, &adb->lifetime, NULL, NULL, /* struct rfapi_un_option */
|
||||
NULL, /* struct rfapi_vn_option */
|
||||
@ -221,11 +220,11 @@ rfapiApWithdrawAll (struct bgp *bgp, struct rfapi_descriptor *rfd)
|
||||
struct prefix pfx_vn_buf;
|
||||
struct prefix *pfx_ip;
|
||||
|
||||
if (!(RFAPI_0_PREFIX (&adb->prefix_ip) &&
|
||||
RFAPI_HOST_PREFIX (&adb->prefix_ip)))
|
||||
if (!(RFAPI_0_PREFIX (&adb->u.s.prefix_ip) &&
|
||||
RFAPI_HOST_PREFIX (&adb->u.s.prefix_ip)))
|
||||
{
|
||||
|
||||
pfx_ip = &adb->prefix_ip;
|
||||
pfx_ip = &adb->u.s.prefix_ip;
|
||||
|
||||
}
|
||||
else
|
||||
@ -247,7 +246,7 @@ rfapiApWithdrawAll (struct bgp *bgp, struct rfapi_descriptor *rfd)
|
||||
}
|
||||
}
|
||||
|
||||
del_vnc_route (rfd, rfd->peer, bgp, SAFI_MPLS_VPN, pfx_ip ? pfx_ip : &pfx_vn_buf, &adb->prd, /* RD to use (0 for ENCAP) */
|
||||
del_vnc_route (rfd, rfd->peer, bgp, SAFI_MPLS_VPN, pfx_ip ? pfx_ip : &pfx_vn_buf, &adb->u.s.prd, /* RD to use (0 for ENCAP) */
|
||||
ZEBRA_ROUTE_BGP, BGP_ROUTE_RFP, NULL, 0);
|
||||
}
|
||||
}
|
||||
@ -404,19 +403,19 @@ rfapiApAdjustLifetimeStats (
|
||||
{
|
||||
|
||||
void *cursor;
|
||||
struct prefix *prefix;
|
||||
struct rfapi_adb *adb;
|
||||
struct rfapi_rib_key rk;
|
||||
struct rfapi_adb *adb;
|
||||
int rc;
|
||||
|
||||
vnc_zlog_debug_verbose ("%s: walking to find new min/max", __func__);
|
||||
|
||||
cursor = NULL;
|
||||
for (rc = skiplist_next (rfd->advertised.ipN_by_prefix,
|
||||
(void **) &prefix, (void **) &adb,
|
||||
(void **) &rk, (void **) &adb,
|
||||
&cursor); !rc;
|
||||
rc =
|
||||
skiplist_next (rfd->advertised.ipN_by_prefix,
|
||||
(void **) &prefix, (void **) &adb, &cursor))
|
||||
(void **) &rk, (void **) &adb, &cursor))
|
||||
{
|
||||
|
||||
uint32_t lt = adb->lifetime;
|
||||
@ -428,10 +427,10 @@ rfapiApAdjustLifetimeStats (
|
||||
}
|
||||
cursor = NULL;
|
||||
for (rc = skiplist_next (rfd->advertised.ip0_by_ether,
|
||||
(void **) &prefix, (void **) &adb,
|
||||
(void **) &rk, (void **) &adb,
|
||||
&cursor); !rc;
|
||||
rc =
|
||||
skiplist_next (rfd->advertised.ip0_by_ether, (void **) &prefix,
|
||||
skiplist_next (rfd->advertised.ip0_by_ether, (void **) &rk,
|
||||
(void **) &adb, &cursor))
|
||||
{
|
||||
|
||||
@ -483,14 +482,15 @@ rfapiApAdd (
|
||||
struct rfapi_adb *adb;
|
||||
uint32_t old_lifetime = 0;
|
||||
int use_ip0 = 0;
|
||||
struct rfapi_rib_key rk;
|
||||
|
||||
rfapi_rib_key_init(pfx_ip, prd, pfx_eth, &rk);
|
||||
if (RFAPI_0_PREFIX (pfx_ip) && RFAPI_HOST_PREFIX (pfx_ip))
|
||||
{
|
||||
use_ip0 = 1;
|
||||
assert (pfx_eth);
|
||||
|
||||
rc =
|
||||
skiplist_search (rfd->advertised.ip0_by_ether, pfx_eth,
|
||||
skiplist_search (rfd->advertised.ip0_by_ether, &rk,
|
||||
(void **) &adb);
|
||||
|
||||
}
|
||||
@ -499,7 +499,7 @@ rfapiApAdd (
|
||||
|
||||
/* find prefix in advertised prefixes list */
|
||||
rc =
|
||||
skiplist_search (rfd->advertised.ipN_by_prefix, pfx_ip,
|
||||
skiplist_search (rfd->advertised.ipN_by_prefix, &rk,
|
||||
(void **) &adb);
|
||||
}
|
||||
|
||||
@ -510,19 +510,17 @@ rfapiApAdd (
|
||||
adb = XCALLOC (MTYPE_RFAPI_ADB, sizeof (struct rfapi_adb));
|
||||
assert (adb);
|
||||
adb->lifetime = lifetime;
|
||||
adb->prefix_ip = *pfx_ip;
|
||||
if (pfx_eth)
|
||||
adb->prefix_eth = *pfx_eth;
|
||||
adb->u.key = rk;
|
||||
|
||||
if (use_ip0)
|
||||
{
|
||||
assert (pfx_eth);
|
||||
skiplist_insert (rfd->advertised.ip0_by_ether, &adb->prefix_eth,
|
||||
skiplist_insert (rfd->advertised.ip0_by_ether, &adb->u.key,
|
||||
adb);
|
||||
}
|
||||
else
|
||||
{
|
||||
skiplist_insert (rfd->advertised.ipN_by_prefix, &adb->prefix_ip,
|
||||
skiplist_insert (rfd->advertised.ipN_by_prefix, &adb->u.key,
|
||||
adb);
|
||||
}
|
||||
|
||||
@ -537,19 +535,12 @@ rfapiApAdd (
|
||||
adb->lifetime = lifetime;
|
||||
assert (!skiplist_insert (rfd->advertised.by_lifetime, adb, adb));
|
||||
}
|
||||
|
||||
if (!use_ip0 && pfx_eth && prefix_cmp (&adb->prefix_eth, pfx_eth))
|
||||
{
|
||||
/* mac address changed */
|
||||
adb->prefix_eth = *pfx_eth;
|
||||
}
|
||||
}
|
||||
adb->cost = cost;
|
||||
if (l2o)
|
||||
adb->l2o = *l2o;
|
||||
else
|
||||
memset (&adb->l2o, 0, sizeof (struct rfapi_l2address_option));
|
||||
adb->prd = *prd;
|
||||
|
||||
if (rfapiApAdjustLifetimeStats
|
||||
(rfd, (rc ? NULL : &old_lifetime), &lifetime))
|
||||
@ -568,16 +559,19 @@ rfapiApDelete (
|
||||
struct rfapi_descriptor *rfd,
|
||||
struct prefix *pfx_ip,
|
||||
struct prefix *pfx_eth,
|
||||
struct prefix_rd *prd,
|
||||
int *advertise_tunnel) /* out */
|
||||
{
|
||||
int rc;
|
||||
struct rfapi_adb *adb;
|
||||
uint32_t old_lifetime;
|
||||
int use_ip0 = 0;
|
||||
struct rfapi_rib_key rk;
|
||||
|
||||
if (advertise_tunnel)
|
||||
*advertise_tunnel = 0;
|
||||
|
||||
rfapi_rib_key_init(pfx_ip, prd, pfx_eth, &rk);
|
||||
/* find prefix in advertised prefixes list */
|
||||
if (RFAPI_0_PREFIX (pfx_ip) && RFAPI_HOST_PREFIX (pfx_ip))
|
||||
{
|
||||
@ -585,7 +579,7 @@ rfapiApDelete (
|
||||
assert (pfx_eth);
|
||||
|
||||
rc =
|
||||
skiplist_search (rfd->advertised.ip0_by_ether, pfx_eth,
|
||||
skiplist_search (rfd->advertised.ip0_by_ether, &rk,
|
||||
(void **) &adb);
|
||||
|
||||
}
|
||||
@ -594,7 +588,7 @@ rfapiApDelete (
|
||||
|
||||
/* find prefix in advertised prefixes list */
|
||||
rc =
|
||||
skiplist_search (rfd->advertised.ipN_by_prefix, pfx_ip,
|
||||
skiplist_search (rfd->advertised.ipN_by_prefix, &rk,
|
||||
(void **) &adb);
|
||||
}
|
||||
|
||||
@ -607,11 +601,11 @@ rfapiApDelete (
|
||||
|
||||
if (use_ip0)
|
||||
{
|
||||
rc = skiplist_delete (rfd->advertised.ip0_by_ether, pfx_eth, NULL);
|
||||
rc = skiplist_delete (rfd->advertised.ip0_by_ether, &rk, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = skiplist_delete (rfd->advertised.ipN_by_prefix, pfx_ip, NULL);
|
||||
rc = skiplist_delete (rfd->advertised.ipN_by_prefix, &rk, NULL);
|
||||
}
|
||||
assert (!rc);
|
||||
|
||||
|
@ -93,6 +93,7 @@ rfapiApDelete (
|
||||
struct rfapi_descriptor *rfd,
|
||||
struct prefix *pfx_ip,
|
||||
struct prefix *pfx_eth,
|
||||
struct prefix_rd *prd,
|
||||
int *advertise_tunnel); /* out */
|
||||
|
||||
|
||||
|
@ -36,15 +36,6 @@ extern void rfapi_delete (struct bgp *);
|
||||
struct rfapi *bgp_rfapi_new (struct bgp *bgp);
|
||||
void bgp_rfapi_destroy (struct bgp *bgp, struct rfapi *h);
|
||||
|
||||
struct rfapi_import_table *rfapiImportTableRefAdd (struct bgp *bgp,
|
||||
struct ecommunity
|
||||
*rt_import_list);
|
||||
|
||||
void
|
||||
rfapiImportTableRefDelByIt (struct bgp *bgp,
|
||||
struct rfapi_import_table *it_target);
|
||||
|
||||
|
||||
extern void
|
||||
rfapiProcessUpdate (struct peer *peer,
|
||||
void *rfd,
|
||||
|
@ -4644,7 +4644,8 @@ bgp_rfapi_destroy (struct bgp *bgp, struct rfapi *h)
|
||||
}
|
||||
|
||||
struct rfapi_import_table *
|
||||
rfapiImportTableRefAdd (struct bgp *bgp, struct ecommunity *rt_import_list)
|
||||
rfapiImportTableRefAdd (struct bgp *bgp, struct ecommunity *rt_import_list,
|
||||
struct rfapi_nve_group_cfg *rfg)
|
||||
{
|
||||
struct rfapi *h;
|
||||
struct rfapi_import_table *it;
|
||||
@ -4670,6 +4671,7 @@ rfapiImportTableRefAdd (struct bgp *bgp, struct ecommunity *rt_import_list)
|
||||
h->imports = it;
|
||||
|
||||
it->rt_import_list = ecommunity_dup (rt_import_list);
|
||||
it->rfg = rfg;
|
||||
it->monitor_exterior_orphans =
|
||||
skiplist_new (0, NULL, (void (*)(void *)) prefix_free);
|
||||
|
||||
@ -4943,6 +4945,7 @@ rfapiDeleteRemotePrefixesIt (
|
||||
* un if set, tunnel must match this prefix
|
||||
* vn if set, nexthop prefix must match this prefix
|
||||
* p if set, prefix must match this prefix
|
||||
* it if set, only look in this import table
|
||||
*
|
||||
* output
|
||||
* pARcount number of active routes deleted
|
||||
@ -4958,6 +4961,7 @@ rfapiDeleteRemotePrefixes (
|
||||
struct prefix *un,
|
||||
struct prefix *vn,
|
||||
struct prefix *p,
|
||||
struct rfapi_import_table *arg_it,
|
||||
int delete_active,
|
||||
int delete_holddown,
|
||||
uint32_t *pARcount,
|
||||
@ -4995,7 +4999,11 @@ rfapiDeleteRemotePrefixes (
|
||||
* for the afi/safi combination
|
||||
*/
|
||||
|
||||
for (it = h->imports; it; it = it->next)
|
||||
if (arg_it)
|
||||
it = arg_it;
|
||||
else
|
||||
it = h->imports;
|
||||
for (; it; )
|
||||
{
|
||||
|
||||
vnc_zlog_debug_verbose
|
||||
@ -5016,6 +5024,11 @@ rfapiDeleteRemotePrefixes (
|
||||
&deleted_holddown_nve_count,
|
||||
uniq_active_nves,
|
||||
uniq_holddown_nves);
|
||||
|
||||
if (arg_it)
|
||||
it = NULL;
|
||||
else
|
||||
it = it->next;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -38,6 +38,7 @@
|
||||
struct rfapi_import_table
|
||||
{
|
||||
struct rfapi_import_table *next;
|
||||
struct rfapi_nve_group_cfg *rfg;
|
||||
struct ecommunity *rt_import_list; /* copied from nve grp */
|
||||
int refcount; /* nve grps and nves */
|
||||
uint32_t l2_logical_net_id; /* L2 only: EVPN Eth Seg Id */
|
||||
@ -90,6 +91,11 @@ rfapiShowImportTable (
|
||||
struct route_table *rt,
|
||||
int isvpn);
|
||||
|
||||
extern struct rfapi_import_table *
|
||||
rfapiImportTableRefAdd (
|
||||
struct bgp *bgp,
|
||||
struct ecommunity *rt_import_list,
|
||||
struct rfapi_nve_group_cfg *rfg);
|
||||
|
||||
extern void
|
||||
rfapiImportTableRefDelByIt (
|
||||
@ -223,6 +229,7 @@ extern int rfapiEcommunityGetEthernetTag (
|
||||
* un if set, tunnel must match this prefix
|
||||
* vn if set, nexthop prefix must match this prefix
|
||||
* p if set, prefix must match this prefix
|
||||
* it if set, only look in this import table
|
||||
*
|
||||
* output
|
||||
* pARcount number of active routes deleted
|
||||
@ -238,6 +245,7 @@ rfapiDeleteRemotePrefixes (
|
||||
struct prefix *un,
|
||||
struct prefix *vn,
|
||||
struct prefix *p,
|
||||
struct rfapi_import_table *it,
|
||||
int delete_active,
|
||||
int delete_holddown,
|
||||
uint32_t *pARcount, /* active routes */
|
||||
|
@ -34,21 +34,6 @@
|
||||
|
||||
#include "rfapi.h"
|
||||
|
||||
/*
|
||||
* RFAPI Advertisement Data Block
|
||||
*
|
||||
* Holds NVE prefix advertisement information
|
||||
*/
|
||||
struct rfapi_adb
|
||||
{
|
||||
struct prefix prefix_ip;
|
||||
struct prefix prefix_eth; /* now redundant with l2o */
|
||||
struct prefix_rd prd;
|
||||
uint32_t lifetime;
|
||||
uint8_t cost;
|
||||
struct rfapi_l2address_option l2o;
|
||||
};
|
||||
|
||||
/*
|
||||
* Lists of rfapi_adb. Each rfapi_adb is referenced twice:
|
||||
*
|
||||
@ -62,7 +47,6 @@ struct rfapi_advertised_prefixes
|
||||
struct skiplist *by_lifetime; /* all */
|
||||
};
|
||||
|
||||
|
||||
struct rfapi_descriptor
|
||||
{
|
||||
struct route_node *un_node; /* backref to un table */
|
||||
@ -151,6 +135,7 @@ struct rfapi_descriptor
|
||||
#define RFAPI_HD_FLAG_CALLBACK_SCHEDULED_AFI_ETHER 0x00000004
|
||||
#define RFAPI_HD_FLAG_PROVISIONAL 0x00000008
|
||||
#define RFAPI_HD_FLAG_CLOSING_ADMINISTRATIVELY 0x00000010
|
||||
#define RFAPI_HD_FLAG_IS_VRF 0x00000012
|
||||
};
|
||||
|
||||
#define RFAPI_QUEUED_FLAG(afi) ( \
|
||||
@ -378,9 +363,6 @@ rfp_cost_to_localpref (uint8_t cost);
|
||||
extern int
|
||||
rfapi_set_autord_from_vn (struct prefix_rd *rd, struct rfapi_ip_addr *vn);
|
||||
|
||||
extern void
|
||||
rfapiAdbFree (struct rfapi_adb *adb);
|
||||
|
||||
extern struct rfapi_nexthop *
|
||||
rfapi_nexthop_new (struct rfapi_nexthop *copyme);
|
||||
|
||||
@ -452,4 +434,17 @@ DECLARE_MTYPE(RFAPI_L2ADDR_OPT)
|
||||
DECLARE_MTYPE(RFAPI_AP)
|
||||
DECLARE_MTYPE(RFAPI_MONITOR_ETH)
|
||||
|
||||
|
||||
/*
|
||||
* Caller must supply an already-allocated rfd with the "caller"
|
||||
* fields already set (vn_addr, un_addr, callback, cookie)
|
||||
* The advertised_prefixes[] array elements should be NULL to
|
||||
* have this function set them to newly-allocated radix trees.
|
||||
*/
|
||||
extern int
|
||||
rfapi_init_and_open(
|
||||
struct bgp *bgp,
|
||||
struct rfapi_descriptor *rfd,
|
||||
struct rfapi_nve_group_cfg *rfg);
|
||||
|
||||
#endif /* _QUAGGA_BGP_RFAPI_PRIVATE_H */
|
||||
|
@ -405,10 +405,26 @@ rfapiRibStartTimer (
|
||||
assert (ri->timer);
|
||||
}
|
||||
|
||||
extern void
|
||||
rfapi_rib_key_init (struct prefix *prefix, /* may be NULL */
|
||||
struct prefix_rd *rd, /* may be NULL */
|
||||
struct prefix *aux, /* may be NULL */
|
||||
struct rfapi_rib_key *rk)
|
||||
|
||||
{
|
||||
memset((void *)rk, 0, sizeof(struct rfapi_rib_key));
|
||||
if (prefix)
|
||||
rk->vn = *prefix;
|
||||
if (rd)
|
||||
rk->rd = *rd;
|
||||
if (aux)
|
||||
rk->aux_prefix = *aux;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares two <struct rfapi_rib_key>s
|
||||
*/
|
||||
static int
|
||||
int
|
||||
rfapi_rib_key_cmp (void *k1, void *k2)
|
||||
{
|
||||
struct rfapi_rib_key *a = (struct rfapi_rib_key *) k1;
|
||||
@ -498,9 +514,13 @@ rfapi_info_cmp (struct rfapi_info *a, struct rfapi_info *b)
|
||||
void
|
||||
rfapiRibClear (struct rfapi_descriptor *rfd)
|
||||
{
|
||||
struct bgp *bgp = bgp_get_default ();
|
||||
struct bgp *bgp;
|
||||
afi_t afi;
|
||||
|
||||
if (rfd->bgp)
|
||||
bgp = rfd->bgp;
|
||||
else
|
||||
bgp = bgp_get_default ();
|
||||
#if DEBUG_L2_EXTRA
|
||||
vnc_zlog_debug_verbose ("%s: rfd=%p", __func__, rfd);
|
||||
#endif
|
||||
|
@ -45,6 +45,27 @@ struct rfapi_rib_key
|
||||
*/
|
||||
struct prefix aux_prefix;
|
||||
};
|
||||
#include "rfapi.h"
|
||||
|
||||
/*
|
||||
* RFAPI Advertisement Data Block
|
||||
*
|
||||
* Holds NVE prefix advertisement information
|
||||
*/
|
||||
struct rfapi_adb
|
||||
{
|
||||
union {
|
||||
struct {
|
||||
struct prefix prefix_ip;
|
||||
struct prefix_rd prd;
|
||||
struct prefix prefix_eth;
|
||||
} s; /* mainly for legacy use */
|
||||
struct rfapi_rib_key key;
|
||||
} u;
|
||||
uint32_t lifetime;
|
||||
uint8_t cost;
|
||||
struct rfapi_l2address_option l2o;
|
||||
};
|
||||
|
||||
struct rfapi_info
|
||||
{
|
||||
@ -151,4 +172,16 @@ rfapiRibCheckCounts (
|
||||
#define RFAPI_RIB_CHECK_COUNTS(checkstats, offset)
|
||||
#endif
|
||||
|
||||
extern void
|
||||
rfapi_rib_key_init (struct prefix *prefix, /* may be NULL */
|
||||
struct prefix_rd *rd, /* may be NULL */
|
||||
struct prefix *aux, /* may be NULL */
|
||||
struct rfapi_rib_key *rk);
|
||||
|
||||
extern int
|
||||
rfapi_rib_key_cmp (void *k1, void *k2);
|
||||
|
||||
extern void
|
||||
rfapiAdbFree (struct rfapi_adb *adb);
|
||||
|
||||
#endif /* QUAGGA_HGP_RFAPI_RIB_H */
|
||||
|
@ -1447,17 +1447,24 @@ rfapiShowRemoteRegistrationsIt (
|
||||
|
||||
if (pLni)
|
||||
{
|
||||
fp (out, "%s[%s] L2VPN Network 0x%x (%u) RT={%s}%s",
|
||||
HVTY_NEWLINE, type, *pLni, (*pLni & 0xfff), s,
|
||||
HVTY_NEWLINE);
|
||||
fp (out, "%s[%s] L2VPN Network 0x%x (%u) RT={%s}",
|
||||
HVTY_NEWLINE, type, *pLni, (*pLni & 0xfff), s);
|
||||
}
|
||||
else
|
||||
{
|
||||
fp (out, "%s[%s] Prefix RT={%s}%s",
|
||||
HVTY_NEWLINE, type, s, HVTY_NEWLINE);
|
||||
fp (out, "%s[%s] Prefix RT={%s}",
|
||||
HVTY_NEWLINE, type, s);
|
||||
}
|
||||
XFREE (MTYPE_ECOMMUNITY_STR, s);
|
||||
|
||||
if (it->rfg && it->rfg->name)
|
||||
{
|
||||
fp (out, " %s \"%s\"",
|
||||
(it->rfg->type == RFAPI_GROUP_CFG_VRF ?
|
||||
"VRF" : "NVE group"),
|
||||
it->rfg->name);
|
||||
}
|
||||
fp (out, "%s", HVTY_NEWLINE);
|
||||
if (show_expiring)
|
||||
{
|
||||
#if RFAPI_REGISTRATIONS_REPORT_AGE
|
||||
@ -1847,14 +1854,14 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd)
|
||||
{
|
||||
|
||||
/* group like family prefixes together in output */
|
||||
if (family != adb->prefix_ip.family)
|
||||
if (family != adb->u.s.prefix_ip.family)
|
||||
continue;
|
||||
|
||||
prefix2str (&adb->prefix_ip, buf, BUFSIZ);
|
||||
prefix2str (&adb->u.s.prefix_ip, buf, BUFSIZ);
|
||||
buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
|
||||
|
||||
vty_out (vty, " Adv Pfx: %s%s", buf, HVTY_NEWLINE);
|
||||
rfapiPrintAdvertisedInfo (vty, rfd, SAFI_MPLS_VPN, &adb->prefix_ip);
|
||||
rfapiPrintAdvertisedInfo (vty, rfd, SAFI_MPLS_VPN, &adb->u.s.prefix_ip);
|
||||
}
|
||||
}
|
||||
for (rc =
|
||||
@ -1865,14 +1872,14 @@ rfapiPrintDescriptor (struct vty *vty, struct rfapi_descriptor *rfd)
|
||||
&cursor))
|
||||
{
|
||||
|
||||
prefix2str (&adb->prefix_eth, buf, BUFSIZ);
|
||||
prefix2str (&adb->u.s.prefix_eth, buf, BUFSIZ);
|
||||
buf[BUFSIZ - 1] = 0; /* guarantee NUL-terminated */
|
||||
|
||||
vty_out (vty, " Adv Pfx: %s%s", buf, HVTY_NEWLINE);
|
||||
|
||||
/* TBD update the following function to print ethernet info */
|
||||
/* Also need to pass/use rd */
|
||||
rfapiPrintAdvertisedInfo (vty, rfd, SAFI_MPLS_VPN, &adb->prefix_ip);
|
||||
rfapiPrintAdvertisedInfo (vty, rfd, SAFI_MPLS_VPN, &adb->u.s.prefix_ip);
|
||||
}
|
||||
vty_out (vty, "%s", HVTY_NEWLINE);
|
||||
}
|
||||
@ -3005,9 +3012,12 @@ struct rfapi_local_reg_delete_arg
|
||||
/*
|
||||
* match parameters
|
||||
*/
|
||||
struct bgp *bgp;
|
||||
struct rfapi_ip_addr un_address; /* AF==0: wildcard */
|
||||
struct rfapi_ip_addr vn_address; /* AF==0: wildcard */
|
||||
struct prefix prefix; /* AF==0: wildcard */
|
||||
struct prefix_rd rd; /* plen!=64: wildcard */
|
||||
struct rfapi_nve_group_cfg *rfg; /* NULL: wildcard */
|
||||
|
||||
struct rfapi_l2address_option_match l2o;
|
||||
|
||||
@ -3107,22 +3117,26 @@ nve_addr_cmp (void *k1, void *k2)
|
||||
|
||||
static int
|
||||
parse_deleter_args (
|
||||
struct vty *vty,
|
||||
struct cmd_token *carg_prefix,
|
||||
struct cmd_token *carg_vn,
|
||||
struct cmd_token *carg_un,
|
||||
struct cmd_token *carg_l2addr,
|
||||
struct cmd_token *carg_vni,
|
||||
struct rfapi_local_reg_delete_arg *rcdarg)
|
||||
struct vty *vty,
|
||||
struct bgp *bgp,
|
||||
const char *arg_prefix,
|
||||
const char *arg_vn,
|
||||
const char *arg_un,
|
||||
const char *arg_l2addr,
|
||||
const char *arg_vni,
|
||||
const char *arg_rd,
|
||||
struct rfapi_nve_group_cfg *arg_rfg,
|
||||
struct rfapi_local_reg_delete_arg *rcdarg)
|
||||
{
|
||||
const char *arg_prefix = carg_prefix ? carg_prefix->arg : NULL;
|
||||
const char *arg_vn = carg_vn ? carg_vn->arg : NULL;
|
||||
const char *arg_un = carg_un ? carg_un->arg : NULL;
|
||||
const char *arg_l2addr = carg_l2addr ? carg_l2addr->arg : NULL;
|
||||
const char *arg_vni = carg_vni ? carg_vni->arg : NULL;
|
||||
int rc = CMD_WARNING;
|
||||
|
||||
memset (rcdarg, 0, sizeof (struct rfapi_local_reg_delete_arg));
|
||||
memset (rcdarg, 0, sizeof (struct rfapi_local_reg_delete_arg));
|
||||
|
||||
rcdarg->vty = vty;
|
||||
if (bgp == NULL)
|
||||
bgp = bgp_get_default();
|
||||
rcdarg->bgp = bgp;
|
||||
rcdarg->rfg = arg_rfg; /* may be NULL */
|
||||
|
||||
if (arg_vn && strcmp (arg_vn, "*"))
|
||||
{
|
||||
@ -3168,7 +3182,41 @@ parse_deleter_args (
|
||||
rcdarg->l2o.flags |= RFAPI_L2O_LNI;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
if (arg_rd)
|
||||
{
|
||||
if (!str2prefix_rd (arg_rd, &rcdarg->rd))
|
||||
{
|
||||
vty_out (vty, "Malformed RD \"%s\"%s",
|
||||
arg_rd, VTY_NEWLINE);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_deleter_tokens (
|
||||
struct vty *vty,
|
||||
struct bgp *bgp,
|
||||
struct cmd_token *carg_prefix,
|
||||
struct cmd_token *carg_vn,
|
||||
struct cmd_token *carg_un,
|
||||
struct cmd_token *carg_l2addr,
|
||||
struct cmd_token *carg_vni,
|
||||
struct cmd_token *carg_rd,
|
||||
struct rfapi_nve_group_cfg *arg_rfg,
|
||||
struct rfapi_local_reg_delete_arg *rcdarg)
|
||||
{
|
||||
const char *arg_prefix = carg_prefix ? carg_prefix->arg : NULL;
|
||||
const char *arg_vn = carg_vn ? carg_vn->arg : NULL;
|
||||
const char *arg_un = carg_un ? carg_un->arg : NULL;
|
||||
const char *arg_l2addr = carg_l2addr ? carg_l2addr->arg : NULL;
|
||||
const char *arg_vni = carg_vni ? carg_vni->arg : NULL;
|
||||
const char *arg_rd = carg_rd ? carg_rd->arg : NULL;
|
||||
return parse_deleter_args (vty, bgp,arg_prefix, arg_vn, arg_un,
|
||||
arg_l2addr, arg_vni, arg_rd,
|
||||
arg_rfg, rcdarg);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3272,51 +3320,37 @@ clear_vnc_responses (struct rfapi_local_reg_delete_arg *cda)
|
||||
* TBD need to count deleted prefixes and nves?
|
||||
*
|
||||
* ENXIO BGP or VNC not configured
|
||||
*/
|
||||
*/
|
||||
static int
|
||||
rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
|
||||
rfapiDeleteLocalPrefixesByRFD (struct rfapi_local_reg_delete_arg *cda,
|
||||
struct rfapi_descriptor *rfd)
|
||||
{
|
||||
struct rfapi_ip_addr *pUn; /* NULL = wildcard */
|
||||
struct rfapi_ip_addr *pVn; /* NULL = wildcard */
|
||||
struct prefix *pPrefix; /* NULL = wildcard */
|
||||
struct rfapi_ip_addr *pUn; /* NULL = wildcard */
|
||||
struct rfapi_ip_addr *pVn; /* NULL = wildcard */
|
||||
struct prefix *pPrefix; /* NULL = wildcard */
|
||||
struct prefix_rd *pPrd; /* NULL = wildcard */
|
||||
|
||||
struct rfapi *h;
|
||||
struct listnode *node;
|
||||
struct rfapi_descriptor *rfd;
|
||||
struct rfapi_ip_prefix rprefix;
|
||||
struct bgp *bgp_default = bgp_get_default ();
|
||||
struct rfapi_next_hop_entry *head = NULL;
|
||||
struct rfapi_next_hop_entry *tail = NULL;
|
||||
struct rfapi_cfg *rfapi_cfg;
|
||||
|
||||
#if DEBUG_L2_EXTRA
|
||||
vnc_zlog_debug_verbose ("%s: entry", __func__);
|
||||
vnc_zlog_debug_verbose ("%s: entry", __func__);
|
||||
#endif
|
||||
|
||||
if (!bgp_default)
|
||||
return ENXIO;
|
||||
|
||||
pUn = (cda->un_address.addr_family ? &cda->un_address : NULL);
|
||||
pVn = (cda->vn_address.addr_family ? &cda->vn_address : NULL);
|
||||
pPrefix = (cda->prefix.family ? &cda->prefix : NULL);
|
||||
|
||||
h = bgp_default->rfapi;
|
||||
rfapi_cfg = bgp_default->rfapi_cfg;
|
||||
|
||||
if (!h || !rfapi_cfg)
|
||||
return ENXIO;
|
||||
pUn = (cda->un_address.addr_family ? &cda->un_address : NULL);
|
||||
pVn = (cda->vn_address.addr_family ? &cda->vn_address : NULL);
|
||||
pPrefix = (cda->prefix.family ? &cda->prefix : NULL);
|
||||
pPrd = (cda->rd.prefixlen == 64 ? &cda->rd : NULL);
|
||||
|
||||
if (pPrefix)
|
||||
{
|
||||
rfapiQprefix2Rprefix (pPrefix, &rprefix);
|
||||
}
|
||||
|
||||
#if DEBUG_L2_EXTRA
|
||||
vnc_zlog_debug_verbose ("%s: starting descriptor loop", __func__);
|
||||
#endif
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (&h->descriptors, node, rfd))
|
||||
do /* to preserve old code structure */
|
||||
{
|
||||
struct rfapi *h=cda->bgp->rfapi;;
|
||||
struct rfapi_adb *adb;
|
||||
int rc;
|
||||
int deleted_from_this_nve;
|
||||
@ -3376,11 +3410,22 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
|
||||
|
||||
if (pPrefix)
|
||||
{
|
||||
if (!prefix_same (pPrefix, &adb->prefix_ip))
|
||||
if (!prefix_same (pPrefix, &adb->u.s.prefix_ip))
|
||||
{
|
||||
#if DEBUG_L2_EXTRA
|
||||
vnc_zlog_debug_verbose ("%s: adb=%p, prefix doesn't match, skipping",
|
||||
__func__, adb);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (pPrd)
|
||||
{
|
||||
if (memcmp(pPrd->val, adb->u.s.prd.val, 8) != 0)
|
||||
{
|
||||
#if DEBUG_L2_EXTRA
|
||||
vnc_zlog_debug_verbose ("%s: adb=%p, RD doesn't match, skipping",
|
||||
__func__, adb);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
@ -3389,7 +3434,7 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
|
||||
{
|
||||
if (memcmp
|
||||
(cda->l2o.o.macaddr.octet,
|
||||
adb->prefix_eth.u.prefix_eth.octet, ETHER_ADDR_LEN))
|
||||
adb->u.s.prefix_eth.u.prefix_eth.octet, ETHER_ADDR_LEN))
|
||||
{
|
||||
#if DEBUG_L2_EXTRA
|
||||
vnc_zlog_debug_verbose ("%s: adb=%p, macaddr doesn't match, skipping",
|
||||
@ -3423,48 +3468,43 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (adb_delete_list, node, adb))
|
||||
{
|
||||
|
||||
struct rfapi_vn_option vn1;
|
||||
struct rfapi_vn_option vn2;
|
||||
struct rfapi_vn_option *pVn;
|
||||
int this_advertisement_prefix_count;
|
||||
struct rfapi_vn_option optary[3];
|
||||
struct rfapi_vn_option *opt = NULL;
|
||||
int cur_opt = 0;
|
||||
|
||||
this_advertisement_prefix_count = 1;
|
||||
|
||||
rfapiQprefix2Rprefix (&adb->prefix_ip, &rp);
|
||||
rfapiQprefix2Rprefix (&adb->u.s.prefix_ip, &rp);
|
||||
|
||||
memset (optary, 0, sizeof (optary));
|
||||
|
||||
/* if mac addr present in advert, make l2o vn option */
|
||||
if (adb->prefix_eth.family == AF_ETHERNET)
|
||||
if (adb->u.s.prefix_eth.family == AF_ETHERNET)
|
||||
{
|
||||
|
||||
memset (&vn1, 0, sizeof (vn1));
|
||||
memset (&vn2, 0, sizeof (vn2));
|
||||
|
||||
vn1.type = RFAPI_VN_OPTION_TYPE_L2ADDR;
|
||||
vn1.v.l2addr.macaddr = adb->prefix_eth.u.prefix_eth;
|
||||
|
||||
/*
|
||||
* use saved RD value instead of trying to invert
|
||||
* complex L2-style RD computation in rfapi_register()
|
||||
*/
|
||||
vn2.type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
|
||||
vn2.v.internal_rd = adb->prd;
|
||||
|
||||
vn1.next = &vn2;
|
||||
|
||||
pVn = &vn1;
|
||||
if (opt != NULL)
|
||||
opt->next = &optary[cur_opt];
|
||||
opt = &optary[cur_opt++];
|
||||
opt->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
|
||||
opt->v.l2addr.macaddr = adb->u.s.prefix_eth.u.prefix_eth;
|
||||
++this_advertisement_prefix_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
pVn = NULL;
|
||||
}
|
||||
/*
|
||||
* use saved RD value instead of trying to invert
|
||||
* complex RD computation in rfapi_register()
|
||||
*/
|
||||
if (opt != NULL)
|
||||
opt->next = &optary[cur_opt];
|
||||
opt = &optary[cur_opt++];
|
||||
opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
|
||||
opt->v.internal_rd = adb->u.s.prd;
|
||||
|
||||
#if DEBUG_L2_EXTRA
|
||||
vnc_zlog_debug_verbose ("%s: ipN killing reg from adb %p ", __func__, adb);
|
||||
#endif
|
||||
|
||||
rc = rfapi_register (rfd, &rp, 0, NULL, pVn, RFAPI_REGISTER_KILL);
|
||||
rc = rfapi_register (rfd, &rp, 0, NULL,
|
||||
(cur_opt ? optary : NULL), RFAPI_REGISTER_KILL);
|
||||
if (!rc)
|
||||
{
|
||||
cda->pfx_count += this_advertisement_prefix_count;
|
||||
@ -3500,7 +3540,7 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
|
||||
if (CHECK_FLAG (cda->l2o.flags, RFAPI_L2O_MACADDR))
|
||||
{
|
||||
if (memcmp (cda->l2o.o.macaddr.octet,
|
||||
adb->prefix_eth.u.prefix_eth.octet,
|
||||
adb->u.s.prefix_eth.u.prefix_eth.octet,
|
||||
ETHER_ADDR_LEN))
|
||||
{
|
||||
|
||||
@ -3527,7 +3567,7 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
|
||||
|
||||
struct rfapi_vn_option vn;
|
||||
|
||||
rfapiQprefix2Rprefix (&adb->prefix_ip, &rp);
|
||||
rfapiQprefix2Rprefix (&adb->u.s.prefix_ip, &rp);
|
||||
|
||||
memset (&vn, 0, sizeof (vn));
|
||||
vn.type = RFAPI_VN_OPTION_TYPE_L2ADDR;
|
||||
@ -3590,11 +3630,44 @@ rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
|
||||
skiplist_insert (cda->nves, hap, hap);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (0); /* to preserve old code structure */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rfapiDeleteLocalPrefixes (struct rfapi_local_reg_delete_arg *cda)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (cda->rfg)
|
||||
{
|
||||
if (cda->rfg->rfd) /* if not open, nothing to delete */
|
||||
rc = rfapiDeleteLocalPrefixesByRFD (cda, cda->rfg->rfd);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct bgp *bgp = cda->bgp;
|
||||
struct rfapi *h;
|
||||
struct rfapi_cfg *rfapi_cfg;
|
||||
|
||||
struct listnode *node;
|
||||
struct rfapi_descriptor *rfd;
|
||||
if (!bgp)
|
||||
return ENXIO;
|
||||
h = bgp->rfapi;
|
||||
rfapi_cfg = bgp->rfapi_cfg;
|
||||
if (!h || !rfapi_cfg)
|
||||
return ENXIO;
|
||||
vnc_zlog_debug_verbose ("%s: starting descriptor loop", __func__);
|
||||
for (ALL_LIST_ELEMENTS_RO (&h->descriptors, node, rfd))
|
||||
{
|
||||
rc = rfapiDeleteLocalPrefixesByRFD (cda, rfd);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* clear_vnc_prefix
|
||||
*
|
||||
@ -3610,6 +3683,8 @@ clear_vnc_prefix (struct rfapi_local_reg_delete_arg *cda)
|
||||
struct prefix *pVN = NULL;
|
||||
struct prefix *pPrefix = NULL;
|
||||
|
||||
struct rfapi_import_table *it = NULL;
|
||||
|
||||
/*
|
||||
* Delete matching remote prefixes in holddown
|
||||
*/
|
||||
@ -3627,7 +3702,11 @@ clear_vnc_prefix (struct rfapi_local_reg_delete_arg *cda)
|
||||
{
|
||||
pPrefix = &cda->prefix;
|
||||
}
|
||||
rfapiDeleteRemotePrefixes (pUN, pVN, pPrefix,
|
||||
if (cda->rfg)
|
||||
{
|
||||
it = cda->rfg->rfapi_import_table;
|
||||
}
|
||||
rfapiDeleteRemotePrefixes (pUN, pVN, pPrefix, it,
|
||||
0, 1, &cda->remote_active_pfx_count,
|
||||
&cda->remote_active_nve_count,
|
||||
&cda->remote_holddown_pfx_count,
|
||||
@ -3712,7 +3791,7 @@ DEFUN (clear_vnc_nve_all,
|
||||
struct rfapi_local_reg_delete_arg cda;
|
||||
int rc;
|
||||
|
||||
if ((rc = parse_deleter_args (vty, NULL, NULL, NULL, NULL, NULL, &cda)))
|
||||
if ((rc = parse_deleter_args (vty, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &cda)))
|
||||
return rc;
|
||||
|
||||
cda.vty = vty;
|
||||
@ -3745,7 +3824,7 @@ DEFUN (clear_vnc_nve_vn_un,
|
||||
int rc;
|
||||
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, NULL, argv[4], argv[6], NULL, NULL, &cda)))
|
||||
parse_deleter_tokens (vty, NULL, NULL, argv[4], argv[6], NULL, NULL, NULL, NULL, &cda)))
|
||||
return rc;
|
||||
|
||||
cda.vty = vty;
|
||||
@ -3778,7 +3857,7 @@ DEFUN (clear_vnc_nve_un_vn,
|
||||
int rc;
|
||||
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, NULL, argv[6], argv[4], NULL, NULL, &cda)))
|
||||
parse_deleter_tokens (vty, NULL, NULL, argv[6], argv[4], NULL, NULL, NULL, NULL, &cda)))
|
||||
return rc;
|
||||
|
||||
cda.vty = vty;
|
||||
@ -3806,7 +3885,7 @@ DEFUN (clear_vnc_nve_vn,
|
||||
struct rfapi_local_reg_delete_arg cda;
|
||||
int rc;
|
||||
|
||||
if ((rc = parse_deleter_args (vty, NULL, argv[4], NULL, NULL, NULL, &cda)))
|
||||
if ((rc = parse_deleter_tokens (vty, NULL, NULL, argv[4], NULL, NULL, NULL, NULL, NULL, &cda)))
|
||||
return rc;
|
||||
|
||||
cda.vty = vty;
|
||||
@ -3833,7 +3912,7 @@ DEFUN (clear_vnc_nve_un,
|
||||
struct rfapi_local_reg_delete_arg cda;
|
||||
int rc;
|
||||
|
||||
if ((rc = parse_deleter_args (vty, NULL, NULL, argv[6], NULL, NULL, &cda)))
|
||||
if ((rc = parse_deleter_tokens (vty, NULL, NULL, NULL, argv[6], NULL, NULL, NULL, NULL, &cda)))
|
||||
return rc;
|
||||
|
||||
cda.vty = vty;
|
||||
@ -3876,7 +3955,7 @@ DEFUN (clear_vnc_prefix_vn_un,
|
||||
int rc;
|
||||
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, argv[3], argv[5], argv[7], NULL, NULL, &cda)))
|
||||
parse_deleter_tokens (vty, NULL, argv[3], argv[5], argv[7], NULL, NULL, NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -3906,7 +3985,7 @@ DEFUN (clear_vnc_prefix_un_vn,
|
||||
int rc;
|
||||
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, argv[3], argv[7], argv[5], NULL, NULL, &cda)))
|
||||
parse_deleter_tokens (vty, NULL, argv[3], argv[7], argv[5], NULL, NULL, NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -3932,7 +4011,7 @@ DEFUN (clear_vnc_prefix_un,
|
||||
int rc;
|
||||
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, argv[3], NULL, argv[5], NULL, NULL, &cda)))
|
||||
parse_deleter_tokens (vty, NULL, argv[3], NULL, argv[5], NULL, NULL, NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -3958,7 +4037,7 @@ DEFUN (clear_vnc_prefix_vn,
|
||||
int rc;
|
||||
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, argv[3], argv[5], NULL, NULL, NULL, &cda)))
|
||||
parse_deleter_tokens (vty, NULL, argv[3], argv[5], NULL, NULL, NULL, NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -3980,7 +4059,7 @@ DEFUN (clear_vnc_prefix_all,
|
||||
struct rfapi_local_reg_delete_arg cda;
|
||||
int rc;
|
||||
|
||||
if ((rc = parse_deleter_args (vty, argv[3], NULL, NULL, NULL, NULL, &cda)))
|
||||
if ((rc = parse_deleter_tokens (vty, NULL, argv[3], NULL, NULL, NULL, NULL, NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -4022,8 +4101,8 @@ DEFUN (clear_vnc_mac_vn_un,
|
||||
|
||||
/* pfx vn un L2 VNI */
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, NULL, argv[7], argv[9], argv[3], argv[5],
|
||||
&cda)))
|
||||
parse_deleter_tokens (vty, NULL, NULL, argv[7], argv[9], argv[3], argv[5],
|
||||
NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -4056,8 +4135,8 @@ DEFUN (clear_vnc_mac_un_vn,
|
||||
|
||||
/* pfx vn un L2 VNI */
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, NULL, argv[9], argv[7], argv[3], argv[5],
|
||||
&cda)))
|
||||
parse_deleter_tokens (vty, NULL, NULL, argv[9], argv[7], argv[3], argv[5],
|
||||
NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -4086,7 +4165,7 @@ DEFUN (clear_vnc_mac_un,
|
||||
|
||||
/* pfx vn un L2 VNI */
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, NULL, NULL, argv[7], argv[3], argv[5], &cda)))
|
||||
parse_deleter_tokens (vty, NULL, NULL, NULL, argv[7], argv[3], argv[5], NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -4115,7 +4194,7 @@ DEFUN (clear_vnc_mac_vn,
|
||||
|
||||
/* pfx vn un L2 VNI */
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, NULL, argv[7], NULL, argv[3], argv[5], &cda)))
|
||||
parse_deleter_tokens (vty, NULL, NULL, argv[7], NULL, argv[3], argv[5], NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -4141,7 +4220,7 @@ DEFUN (clear_vnc_mac_all,
|
||||
|
||||
/* pfx vn un L2 VNI */
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, NULL, NULL, NULL, argv[3], argv[5], &cda)))
|
||||
parse_deleter_tokens (vty, NULL, NULL, NULL, NULL, argv[3], argv[5], NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -4182,8 +4261,8 @@ DEFUN (clear_vnc_mac_vn_un_prefix,
|
||||
|
||||
/* pfx vn un L2 VNI */
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, argv[11], argv[7], argv[9], argv[3], argv[5],
|
||||
&cda)))
|
||||
parse_deleter_tokens (vty, NULL, argv[11], argv[7], argv[9], argv[3], argv[5],
|
||||
NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -4224,8 +4303,8 @@ DEFUN (clear_vnc_mac_un_vn_prefix,
|
||||
|
||||
/* pfx vn un L2 VNI */
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, argv[11], argv[9], argv[7], argv[3], argv[5],
|
||||
&cda)))
|
||||
parse_deleter_tokens (vty, NULL, argv[11], argv[9], argv[7], argv[3], argv[5],
|
||||
NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -4258,8 +4337,8 @@ DEFUN (clear_vnc_mac_un_prefix,
|
||||
|
||||
/* pfx vn un L2 VNI */
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, argv[9], NULL, argv[7], argv[3], argv[5],
|
||||
&cda)))
|
||||
parse_deleter_tokens (vty, NULL, argv[9], NULL, argv[7], argv[3], argv[5],
|
||||
NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -4292,8 +4371,8 @@ DEFUN (clear_vnc_mac_vn_prefix,
|
||||
|
||||
/* pfx vn un L2 VNI */
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, argv[9], argv[7], NULL, argv[3], argv[5],
|
||||
&cda)))
|
||||
parse_deleter_tokens (vty, NULL, argv[9], argv[7], NULL, argv[3], argv[5],
|
||||
NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -4322,7 +4401,7 @@ DEFUN (clear_vnc_mac_all_prefix,
|
||||
|
||||
/* pfx vn un L2 VNI */
|
||||
if ((rc =
|
||||
parse_deleter_args (vty, argv[7], NULL, NULL, argv[3], argv[5], &cda)))
|
||||
parse_deleter_tokens (vty, NULL, argv[7], NULL, NULL, argv[3], argv[5], NULL, NULL, &cda)))
|
||||
return rc;
|
||||
cda.vty = vty;
|
||||
clear_vnc_prefix (&cda);
|
||||
@ -4930,6 +5009,361 @@ notcfg:
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Add prefix with vrf
|
||||
*
|
||||
* add [vrf <vrf-name>] prefix <prefix>
|
||||
* [rd <value>] [label <value>] [local-preference <0-4294967295>]
|
||||
************************************************************************/
|
||||
static int
|
||||
vnc_add_vrf_prefix (struct vty *vty,
|
||||
const char *arg_vrf,
|
||||
const char *arg_prefix,
|
||||
const char *arg_rd, /* optional */
|
||||
const char *arg_label, /* optional */
|
||||
const char *arg_pref) /* optional */
|
||||
{
|
||||
struct bgp *bgp;
|
||||
struct rfapi_nve_group_cfg *rfg;
|
||||
struct prefix pfx;
|
||||
struct rfapi_ip_prefix rpfx;
|
||||
uint32_t pref = 0;
|
||||
struct rfapi_vn_option optary[3];
|
||||
struct rfapi_vn_option *opt = NULL;
|
||||
int cur_opt = 0;
|
||||
|
||||
bgp = bgp_get_default (); /* assume main instance for now */
|
||||
if (!bgp)
|
||||
{
|
||||
vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (!bgp->rfapi || !bgp->rfapi_cfg)
|
||||
{
|
||||
vty_out (vty, "VRF support not configured%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
rfg = bgp_rfapi_cfg_match_byname (bgp, arg_vrf, RFAPI_GROUP_CFG_VRF);
|
||||
/* arg checks */
|
||||
if (!rfg)
|
||||
{
|
||||
vty_out (vty, "VRF \"%s\" appears not to be configured.%s",
|
||||
arg_vrf, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (!rfg->rt_export_list || !rfg->rfapi_import_table)
|
||||
{
|
||||
vty_out (vty, "VRF \"%s\" is missing RT import/export RT configuration.%s",
|
||||
arg_vrf, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (!rfg->rd.family && !arg_rd)
|
||||
{
|
||||
vty_out (vty, "VRF \"%s\" isn't configured with an RD, so RD must be provided.%s",
|
||||
arg_vrf, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (rfg->label > MPLS_LABEL_MAX && !arg_label)
|
||||
{
|
||||
vty_out (vty, "VRF \"%s\" isn't configured with a default labels, so a label must be provided.%s",
|
||||
arg_vrf, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (!str2prefix (arg_prefix, &pfx))
|
||||
{
|
||||
vty_out (vty, "Malformed prefix \"%s\"%s",
|
||||
arg_prefix, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
rfapiQprefix2Rprefix (&pfx, &rpfx);
|
||||
memset (optary, 0, sizeof (optary));
|
||||
if (arg_rd)
|
||||
{
|
||||
if (opt != NULL)
|
||||
opt->next = &optary[cur_opt];
|
||||
opt = &optary[cur_opt++];
|
||||
opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
|
||||
if (!str2prefix_rd (arg_rd, &opt->v.internal_rd))
|
||||
{
|
||||
vty_out (vty, "Malformed RD \"%s\"%s",
|
||||
arg_rd, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
if (rfg->label <= MPLS_LABEL_MAX || arg_label)
|
||||
{
|
||||
struct rfapi_l2address_option *l2o;
|
||||
if (opt != NULL)
|
||||
opt->next = &optary[cur_opt];
|
||||
opt = &optary[cur_opt++];
|
||||
opt->type = RFAPI_VN_OPTION_TYPE_L2ADDR;
|
||||
l2o = &opt->v.l2addr;
|
||||
if (arg_label)
|
||||
{
|
||||
int32_t label;
|
||||
VTY_GET_INTEGER_RANGE ("Label value", label, arg_label, 0, MPLS_LABEL_MAX);
|
||||
l2o->label = label;
|
||||
}
|
||||
else
|
||||
l2o->label = rfg->label;
|
||||
}
|
||||
if (arg_pref)
|
||||
{
|
||||
char *endptr = NULL;
|
||||
pref = strtoul (arg_pref, &endptr, 10);
|
||||
if (*endptr != '\0')
|
||||
{
|
||||
vty_out (vty, "%% Invalid local-preference value \"%s\"%s", arg_pref, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
rpfx.cost = 255 - (pref & 255) ;
|
||||
if (rfg->rfd == NULL) /* need new rfapi_handle */
|
||||
{
|
||||
/* based on rfapi_open */
|
||||
struct rfapi_descriptor *rfd;
|
||||
rfd = XCALLOC (MTYPE_RFAPI_DESC, sizeof (struct rfapi_descriptor));
|
||||
rfd->bgp = bgp;
|
||||
rfg->rfd = rfd;
|
||||
/* leave most fields empty as will get from (dynamic) config when needed */
|
||||
rfd->default_tunneltype_option.type = BGP_ENCAP_TYPE_MPLS;
|
||||
rfd->cookie = rfg;
|
||||
if (rfg->vn_prefix.family &&
|
||||
!CHECK_FLAG(rfg->flags, RFAPI_RFG_VPN_NH_SELF))
|
||||
{
|
||||
rfapiQprefix2Raddr(&rfg->vn_prefix, &rfd->vn_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(&rfd->vn_addr, 0, sizeof(struct rfapi_ip_addr));
|
||||
rfd->vn_addr.addr_family = AF_INET;
|
||||
rfd->vn_addr.addr.v4 = bgp->router_id;
|
||||
}
|
||||
rfd->un_addr = rfd->vn_addr; /* sigh, need something in UN for lookups */
|
||||
vnc_zlog_debug_verbose ("%s: Opening RFD for VRF %s",
|
||||
__func__, rfg->name);
|
||||
rfapi_init_and_open(bgp, rfd, rfg);
|
||||
}
|
||||
|
||||
if (!rfapi_register (rfg->rfd, &rpfx, RFAPI_INFINITE_LIFETIME, NULL,
|
||||
(cur_opt ? optary : NULL), RFAPI_REGISTER_ADD))
|
||||
{
|
||||
struct rfapi_next_hop_entry *head = NULL;
|
||||
struct rfapi_next_hop_entry *tail = NULL;
|
||||
struct rfapi_vn_option *vn_opt_new;
|
||||
|
||||
vnc_zlog_debug_verbose ("%s: rfapi_register succeeded", __func__);
|
||||
|
||||
if (bgp->rfapi->rfp_methods.local_cb)
|
||||
{
|
||||
struct rfapi_descriptor *r = (struct rfapi_descriptor *) rfg->rfd;
|
||||
vn_opt_new = rfapi_vn_options_dup (opt);
|
||||
|
||||
rfapiAddDeleteLocalRfpPrefix (&r->un_addr, &r->vn_addr, &rpfx,
|
||||
1, RFAPI_INFINITE_LIFETIME,
|
||||
vn_opt_new, &head, &tail);
|
||||
if (head)
|
||||
{
|
||||
bgp->rfapi->flags |= RFAPI_INCALLBACK;
|
||||
(*bgp->rfapi->rfp_methods.local_cb) (head, r->cookie);
|
||||
bgp->rfapi->flags &= ~RFAPI_INCALLBACK;
|
||||
}
|
||||
head = tail = NULL;
|
||||
}
|
||||
vnc_zlog_debug_verbose ("%s completed, count=%d/%d", __func__,
|
||||
rfg->rfapi_import_table->local_count[AFI_IP],
|
||||
rfg->rfapi_import_table->local_count[AFI_IP6]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
vnc_zlog_debug_verbose ("%s: rfapi_register failed", __func__);
|
||||
vty_out (vty, "Add failed.%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN (add_vrf_prefix_rd_label_pref,
|
||||
add_vrf_prefix_rd_label_pref_cmd,
|
||||
"add vrf NAME prefix <A.B.C.D/M|X:X::X:X/M> [rd ASN:nn_or_IP-address] [label (0-1048575)] [preference (0-4294967295)]",
|
||||
"Add\n"
|
||||
"To a VRF\n"
|
||||
"VRF name\n"
|
||||
"Add/modify prefix related information\n"
|
||||
"IPv4 prefix\n"
|
||||
"IPv6 prefix\n"
|
||||
"Override configured VRF Route Distinguisher\n"
|
||||
"<as-number>:<number> or <ip-address>:<number>\n"
|
||||
"Override configured VRF label"
|
||||
"Label Value <0-1048575>\n"
|
||||
"Set advertised local preference\n"
|
||||
"local preference (higher=more preferred)\n")
|
||||
{
|
||||
char *arg_vrf = argv[2]->arg;
|
||||
char *arg_prefix = argv[4]->arg;
|
||||
char *arg_rd = NULL; /* optional */
|
||||
char *arg_label = NULL; /* optional */
|
||||
char *arg_pref = NULL; /* optional */
|
||||
int pargc = 5;
|
||||
argc--; /* don't parse argument */
|
||||
while (pargc < argc)
|
||||
{
|
||||
switch (argv[pargc++]->arg[0])
|
||||
{
|
||||
case 'r':
|
||||
arg_rd = argv[pargc]->arg;
|
||||
break;
|
||||
case 'l':
|
||||
arg_label = argv[pargc]->arg;
|
||||
break;
|
||||
case 'p':
|
||||
arg_pref = argv[pargc]->arg;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pargc ++;
|
||||
}
|
||||
|
||||
return vnc_add_vrf_prefix (vty, arg_vrf, arg_prefix, arg_rd, arg_label, arg_pref);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* del prefix with vrf
|
||||
*
|
||||
* clear [vrf <vrf-name>] prefix <prefix> [rd <value>]
|
||||
************************************************************************/
|
||||
static int
|
||||
rfapi_cfg_group_it_count(struct rfapi_nve_group_cfg *rfg)
|
||||
{
|
||||
int count = 0;
|
||||
afi_t afi = AFI_MAX;
|
||||
while (afi-- > 0)
|
||||
{
|
||||
count += rfg->rfapi_import_table->local_count[afi];
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
clear_vnc_vrf_closer (struct rfapi_nve_group_cfg *rfg)
|
||||
{
|
||||
struct rfapi_descriptor *rfd = rfg->rfd;
|
||||
afi_t afi;
|
||||
|
||||
if (rfd == NULL)
|
||||
return;
|
||||
/* check if IT is empty */
|
||||
for (afi = 0;
|
||||
afi < AFI_MAX && rfg->rfapi_import_table->local_count[afi] == 0;
|
||||
afi++);
|
||||
|
||||
if (afi == AFI_MAX)
|
||||
{
|
||||
vnc_zlog_debug_verbose ("%s: closing RFD for VRF %s",
|
||||
__func__, rfg->name);
|
||||
rfg->rfd = NULL;
|
||||
rfapi_close(rfd);
|
||||
}
|
||||
else
|
||||
{
|
||||
vnc_zlog_debug_verbose ("%s: VRF %s afi=%d count=%d",
|
||||
__func__, rfg->name, afi,
|
||||
rfg->rfapi_import_table->local_count[afi]);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
vnc_clear_vrf (struct vty *vty,
|
||||
struct bgp *bgp,
|
||||
const char *arg_vrf,
|
||||
const char *arg_prefix, /* NULL = all */
|
||||
const char *arg_rd) /* optional */
|
||||
{
|
||||
struct rfapi_nve_group_cfg *rfg;
|
||||
struct rfapi_local_reg_delete_arg cda;
|
||||
int rc;
|
||||
int start_count;
|
||||
|
||||
if (bgp == NULL)
|
||||
bgp = bgp_get_default (); /* assume main instance for now */
|
||||
if (!bgp)
|
||||
{
|
||||
vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (!bgp->rfapi || !bgp->rfapi_cfg)
|
||||
{
|
||||
vty_out (vty, "VRF support not configured%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
rfg = bgp_rfapi_cfg_match_byname (bgp, arg_vrf, RFAPI_GROUP_CFG_VRF);
|
||||
/* arg checks */
|
||||
if (!rfg)
|
||||
{
|
||||
vty_out (vty, "VRF \"%s\" appears not to be configured.%s",
|
||||
arg_vrf, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
rc = parse_deleter_args (vty, bgp, arg_prefix, NULL, NULL, NULL, NULL,
|
||||
arg_rd, rfg, &cda);
|
||||
if (rc != CMD_SUCCESS) /* parse error */
|
||||
return rc;
|
||||
|
||||
start_count = rfapi_cfg_group_it_count(rfg);
|
||||
clear_vnc_prefix (&cda);
|
||||
clear_vnc_vrf_closer (rfg);
|
||||
vty_out (vty, "Cleared %u out of %d prefixes.%s",
|
||||
cda.pfx_count, start_count, VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (clear_vrf_prefix_rd,
|
||||
clear_vrf_prefix_rd_cmd,
|
||||
"clear vrf NAME [prefix <A.B.C.D/M|X:X::X:X/M>] [rd ASN:nn_or_IP-address]",
|
||||
"Clear stored data\n"
|
||||
"From a VRF\n"
|
||||
"VRF name\n"
|
||||
"Prefix related information\n"
|
||||
"IPv4 prefix\n"
|
||||
"IPv6 prefix\n"
|
||||
"Specific VRF Route Distinguisher\n"
|
||||
"<as-number>:<number> or <ip-address>:<number>\n")
|
||||
{
|
||||
char *arg_vrf = argv[2]->arg;
|
||||
char *arg_prefix = NULL; /* optional */
|
||||
char *arg_rd = NULL; /* optional */
|
||||
int pargc = 3;
|
||||
argc--; /* don't check parameter */
|
||||
while (pargc < argc)
|
||||
{
|
||||
switch (argv[pargc++]->arg[0])
|
||||
{
|
||||
case 'r':
|
||||
arg_rd = argv[pargc]->arg;
|
||||
break;
|
||||
case 'p':
|
||||
arg_prefix = argv[pargc]->arg;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pargc ++;
|
||||
}
|
||||
return vnc_clear_vrf (vty, NULL, arg_vrf, arg_prefix, arg_rd);
|
||||
}
|
||||
|
||||
DEFUN (clear_vrf_all,
|
||||
clear_vrf_all_cmd,
|
||||
"clear vrf NAME all",
|
||||
"Clear stored data\n"
|
||||
"From a VRF\n"
|
||||
"VRF name\n"
|
||||
"All prefixes\n")
|
||||
{
|
||||
char *arg_vrf = argv[2]->arg;
|
||||
return vnc_clear_vrf (vty, NULL, arg_vrf, NULL, NULL);
|
||||
}
|
||||
|
||||
void rfapi_vty_init ()
|
||||
{
|
||||
install_element (ENABLE_NODE, &add_vnc_prefix_cost_life_lnh_cmd);
|
||||
@ -4953,6 +5387,8 @@ void rfapi_vty_init ()
|
||||
install_element (ENABLE_NODE, &add_vnc_mac_vni_life_cmd);
|
||||
install_element (ENABLE_NODE, &add_vnc_mac_vni_cmd);
|
||||
|
||||
install_element (ENABLE_NODE, &add_vrf_prefix_rd_label_pref_cmd);
|
||||
|
||||
install_element (ENABLE_NODE, &clear_vnc_nve_all_cmd);
|
||||
install_element (ENABLE_NODE, &clear_vnc_nve_vn_un_cmd);
|
||||
install_element (ENABLE_NODE, &clear_vnc_nve_un_vn_cmd);
|
||||
@ -4977,6 +5413,9 @@ void rfapi_vty_init ()
|
||||
install_element (ENABLE_NODE, &clear_vnc_mac_vn_prefix_cmd);
|
||||
install_element (ENABLE_NODE, &clear_vnc_mac_all_prefix_cmd);
|
||||
|
||||
install_element (ENABLE_NODE, &clear_vrf_prefix_rd_cmd);
|
||||
install_element (ENABLE_NODE, &clear_vrf_all_cmd);
|
||||
|
||||
install_element (ENABLE_NODE, &vnc_clear_counters_cmd);
|
||||
|
||||
install_element (VIEW_NODE, &vnc_show_summary_cmd);
|
||||
|
@ -1459,6 +1459,7 @@ case "x${quagga_ac_bison_version}" in
|
||||
x2.7*)
|
||||
BISON_OPENBRACE='"'
|
||||
BISON_CLOSEBRACE='"'
|
||||
BISON_VERBOSE=''
|
||||
AC_MSG_RESULT([$quagga_ac_bison_version - 2.7 or older])
|
||||
;;
|
||||
x2.*|x1.*)
|
||||
@ -1474,11 +1475,13 @@ case "x${quagga_ac_bison_version}" in
|
||||
*)
|
||||
BISON_OPENBRACE='{'
|
||||
BISON_CLOSEBRACE='}'
|
||||
BISON_VERBOSE='-Dparse.error=verbose'
|
||||
AC_MSG_RESULT([$quagga_ac_bison_version - 3.0 or newer])
|
||||
;;
|
||||
esac
|
||||
AC_SUBST(BISON_OPENBRACE)
|
||||
AC_SUBST(BISON_CLOSEBRACE)
|
||||
AC_SUBST(BISON_VERBOSE)
|
||||
|
||||
if $quagga_ac_bison_missing; then
|
||||
YACC="$SHELL $missing_dir/missing bison -y"
|
||||
|
@ -1149,7 +1149,7 @@ isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid)
|
||||
unsigned long long start_time, end_time;
|
||||
|
||||
/* Get time that can't roll backwards. */
|
||||
quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now);
|
||||
monotime(&time_now);
|
||||
start_time = time_now.tv_sec;
|
||||
start_time = (start_time * 1000000) + time_now.tv_usec;
|
||||
|
||||
@ -1243,7 +1243,7 @@ out:
|
||||
spftree->pending = 0;
|
||||
spftree->runcount++;
|
||||
spftree->last_run_timestamp = time (NULL);
|
||||
quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now);
|
||||
monotime(&time_now);
|
||||
end_time = time_now.tv_sec;
|
||||
end_time = (end_time * 1000000) + time_now.tv_usec;
|
||||
spftree->last_run_duration = end_time - start_time;
|
||||
|
@ -3,7 +3,7 @@
|
||||
AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
|
||||
AM_CFLAGS = $(WERROR)
|
||||
DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
|
||||
AM_YFLAGS = -d -Dapi.prefix=@BISON_OPENBRACE@cmd_yy@BISON_CLOSEBRACE@
|
||||
AM_YFLAGS = -d -Dapi.prefix=@BISON_OPENBRACE@cmd_yy@BISON_CLOSEBRACE@ @BISON_VERBOSE@
|
||||
|
||||
command_lex.h: command_lex.c
|
||||
@if test ! -f $@; then rm -f command_lex.c; else :; fi
|
||||
@ -26,6 +26,7 @@ libzebra_la_SOURCES = \
|
||||
imsg-buffer.c imsg.c skiplist.c \
|
||||
qobj.c wheel.c \
|
||||
event_counter.c \
|
||||
grammar_sandbox.c \
|
||||
strlcpy.c \
|
||||
strlcat.c
|
||||
|
||||
@ -46,14 +47,15 @@ pkginclude_HEADERS = \
|
||||
ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h \
|
||||
fifo.h memory_vty.h mpls.h imsg.h openbsd-queue.h openbsd-tree.h \
|
||||
skiplist.h qobj.h wheel.h \
|
||||
event_counter.h
|
||||
event_counter.h \
|
||||
monotime.h
|
||||
|
||||
noinst_HEADERS = \
|
||||
plist_int.h
|
||||
|
||||
noinst_PROGRAMS = grammar_sandbox
|
||||
|
||||
grammar_sandbox_SOURCES = grammar_sandbox.c
|
||||
grammar_sandbox_SOURCES = grammar_sandbox_main.c
|
||||
grammar_sandbox_LDADD = libzebra.la
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
@ -362,7 +362,7 @@ bfd_last_update (time_t last_update, char *buf, size_t len)
|
||||
}
|
||||
|
||||
/* Get current time. */
|
||||
quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv);
|
||||
monotime(&tv);
|
||||
curr = tv.tv_sec;
|
||||
diff = curr - last_update;
|
||||
tm = gmtime (&diff);
|
||||
|
@ -43,7 +43,10 @@
|
||||
|
||||
DEFINE_MTYPE( LIB, HOST, "Host config")
|
||||
DEFINE_MTYPE( LIB, STRVEC, "String vector")
|
||||
DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc")
|
||||
DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens")
|
||||
DEFINE_MTYPE_STATIC(LIB, CMD_DESC, "Command Token Text")
|
||||
DEFINE_MTYPE_STATIC(LIB, CMD_TEXT, "Command Token Help")
|
||||
DEFINE_MTYPE( LIB, CMD_ARG, "Command Argument")
|
||||
|
||||
/* Command vector which includes some level of command lists. Normally
|
||||
each daemon maintains each own cmdvec. */
|
||||
@ -523,7 +526,7 @@ compare_completions (const void *fst, const void *snd)
|
||||
* @param completions linked list of cmd_token
|
||||
* @return deduplicated and sorted vector with
|
||||
*/
|
||||
static vector
|
||||
vector
|
||||
completions_to_vec (struct list *completions)
|
||||
{
|
||||
vector comps = vector_init (VECTOR_MIN_SIZE);
|
||||
@ -745,6 +748,7 @@ node_parent ( enum node_type node )
|
||||
case BGP_VPNV6_NODE:
|
||||
case BGP_ENCAP_NODE:
|
||||
case BGP_ENCAPV6_NODE:
|
||||
case BGP_VRF_POLICY_NODE:
|
||||
case BGP_VNC_DEFAULTS_NODE:
|
||||
case BGP_VNC_NVE_GROUP_NODE:
|
||||
case BGP_VNC_L2_GROUP_NODE:
|
||||
@ -1110,6 +1114,7 @@ cmd_exit (struct vty *vty)
|
||||
case BGP_VPNV6_NODE:
|
||||
case BGP_ENCAP_NODE:
|
||||
case BGP_ENCAPV6_NODE:
|
||||
case BGP_VRF_POLICY_NODE:
|
||||
case BGP_VNC_DEFAULTS_NODE:
|
||||
case BGP_VNC_NVE_GROUP_NODE:
|
||||
case BGP_VNC_L2_GROUP_NODE:
|
||||
@ -1173,6 +1178,7 @@ DEFUN (config_end,
|
||||
case BGP_NODE:
|
||||
case BGP_ENCAP_NODE:
|
||||
case BGP_ENCAPV6_NODE:
|
||||
case BGP_VRF_POLICY_NODE:
|
||||
case BGP_VNC_DEFAULTS_NODE:
|
||||
case BGP_VNC_NVE_GROUP_NODE:
|
||||
case BGP_VNC_L2_GROUP_NODE:
|
||||
@ -1272,7 +1278,7 @@ permute (struct graph_node *start, struct vty *vty)
|
||||
for (ALL_LIST_ELEMENTS_RO (position,ln,gnn))
|
||||
{
|
||||
struct cmd_token *tt = gnn->data;
|
||||
if (tt->type < SELECTOR_TKN)
|
||||
if (tt->type < SPECIAL_TKN)
|
||||
vty_out (vty, " %s", tt->text);
|
||||
}
|
||||
if (gn == start)
|
||||
@ -2402,16 +2408,21 @@ cmd_init (int terminal)
|
||||
vrf_install_commands ();
|
||||
}
|
||||
srandom(time(NULL));
|
||||
|
||||
#ifdef DEV_BUILD
|
||||
grammar_sandbox_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
struct cmd_token *
|
||||
new_cmd_token (enum cmd_token_type type, u_char attr, char *text, char *desc)
|
||||
new_cmd_token (enum cmd_token_type type, u_char attr,
|
||||
const char *text, const char *desc)
|
||||
{
|
||||
struct cmd_token *token = XCALLOC (MTYPE_CMD_TOKENS, sizeof (struct cmd_token));
|
||||
token->type = type;
|
||||
token->attr = attr;
|
||||
token->text = text;
|
||||
token->desc = desc;
|
||||
token->text = text ? XSTRDUP (MTYPE_CMD_TEXT, text) : NULL;
|
||||
token->desc = desc ? XSTRDUP (MTYPE_CMD_DESC, desc) : NULL;
|
||||
token->arg = NULL;
|
||||
token->allowrepeat = false;
|
||||
|
||||
@ -2424,11 +2435,11 @@ del_cmd_token (struct cmd_token *token)
|
||||
if (!token) return;
|
||||
|
||||
if (token->text)
|
||||
XFREE (MTYPE_CMD_TOKENS, token->text);
|
||||
XFREE (MTYPE_CMD_TEXT, token->text);
|
||||
if (token->desc)
|
||||
XFREE (MTYPE_CMD_TOKENS, token->desc);
|
||||
XFREE (MTYPE_CMD_DESC, token->desc);
|
||||
if (token->arg)
|
||||
XFREE (MTYPE_CMD_TOKENS, token->arg);
|
||||
XFREE (MTYPE_CMD_ARG, token->arg);
|
||||
|
||||
XFREE (MTYPE_CMD_TOKENS, token);
|
||||
}
|
||||
@ -2439,9 +2450,9 @@ copy_cmd_token (struct cmd_token *token)
|
||||
struct cmd_token *copy = new_cmd_token (token->type, token->attr, NULL, NULL);
|
||||
copy->max = token->max;
|
||||
copy->min = token->min;
|
||||
copy->text = token->text ? XSTRDUP (MTYPE_CMD_TOKENS, token->text) : NULL;
|
||||
copy->desc = token->desc ? XSTRDUP (MTYPE_CMD_TOKENS, token->desc) : NULL;
|
||||
copy->arg = token->arg ? XSTRDUP (MTYPE_CMD_TOKENS, token->arg) : NULL;
|
||||
copy->text = token->text ? XSTRDUP (MTYPE_CMD_TEXT, token->text) : NULL;
|
||||
copy->desc = token->desc ? XSTRDUP (MTYPE_CMD_DESC, token->desc) : NULL;
|
||||
copy->arg = token->arg ? XSTRDUP (MTYPE_CMD_ARG, token->arg) : NULL;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "hash.h"
|
||||
|
||||
DECLARE_MTYPE(HOST)
|
||||
DECLARE_MTYPE(CMD_ARG)
|
||||
|
||||
/* for test-commands.c */
|
||||
DECLARE_MTYPE(STRVEC)
|
||||
@ -99,6 +100,7 @@ enum node_type
|
||||
BGP_IPV6M_NODE, /* BGP IPv6 multicast address family. */
|
||||
BGP_ENCAP_NODE, /* BGP ENCAP SAFI */
|
||||
BGP_ENCAPV6_NODE, /* BGP ENCAP SAFI */
|
||||
BGP_VRF_POLICY_NODE, /* BGP VRF policy */
|
||||
BGP_VNC_DEFAULTS_NODE, /* BGP VNC nve defaults */
|
||||
BGP_VNC_NVE_GROUP_NODE, /* BGP VNC nve group */
|
||||
BGP_VNC_L2_GROUP_NODE, /* BGP VNC L2 group */
|
||||
@ -176,11 +178,12 @@ enum cmd_token_type
|
||||
IPV6_PREFIX_TKN, // IPV6 network prefixes
|
||||
|
||||
/* plumbing types */
|
||||
SELECTOR_TKN, // marks beginning of selector
|
||||
OPTION_TKN, // marks beginning of option
|
||||
NUL_TKN, // dummy token
|
||||
FORK_TKN, // marks subgraph beginning
|
||||
JOIN_TKN, // marks subgraph end
|
||||
START_TKN, // first token in line
|
||||
END_TKN, // last token in line
|
||||
|
||||
SPECIAL_TKN = FORK_TKN,
|
||||
};
|
||||
|
||||
/* Command attributes */
|
||||
@ -202,6 +205,8 @@ struct cmd_token
|
||||
char *desc; // token description
|
||||
long long min, max; // for ranges
|
||||
char *arg; // user input that matches this token
|
||||
|
||||
struct graph_node *forkjoin; // paired FORK/JOIN for JOIN/FORK
|
||||
};
|
||||
|
||||
/* Structure of command element. */
|
||||
@ -419,14 +424,16 @@ extern void cmd_terminate (void);
|
||||
extern void cmd_exit (struct vty *vty);
|
||||
extern int cmd_list_cmds (struct vty *vty, int do_permute);
|
||||
|
||||
/* memory management for cmd_token */
|
||||
struct cmd_token *
|
||||
new_cmd_token (enum cmd_token_type, u_char attr, char *, char *);
|
||||
void
|
||||
del_cmd_token (struct cmd_token *);
|
||||
struct cmd_token *
|
||||
copy_cmd_token (struct cmd_token *);
|
||||
/* NOT safe for general use; call this only if DEV_BUILD! */
|
||||
extern void grammar_sandbox_init (void);
|
||||
|
||||
/* memory management for cmd_token */
|
||||
extern struct cmd_token *new_cmd_token (enum cmd_token_type, u_char attr,
|
||||
const char *text, const char *desc);
|
||||
extern void del_cmd_token (struct cmd_token *);
|
||||
extern struct cmd_token *copy_cmd_token (struct cmd_token *);
|
||||
|
||||
extern vector completions_to_vec (struct list *completions);
|
||||
extern void command_parse_format (struct graph *graph, struct cmd_element *cmd);
|
||||
|
||||
/* Export typical functions. */
|
||||
|
@ -24,6 +24,12 @@
|
||||
|
||||
%{
|
||||
#include "command_parse.h"
|
||||
|
||||
#define YY_USER_ACTION yylloc->last_column += yyleng;
|
||||
#define LOC_STEP do { if (yylloc) { \
|
||||
yylloc->first_column = yylloc->last_column; \
|
||||
yylloc->first_line = yylloc->last_line; \
|
||||
} } while(0)
|
||||
%}
|
||||
|
||||
WORD (\-|\+)?[a-z0-9\*][-+_a-zA-Z0-9\*]*
|
||||
@ -45,9 +51,14 @@ RANGE \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
|
||||
%option prefix="cmd_yy"
|
||||
%option reentrant
|
||||
%option bison-bridge
|
||||
%option bison-locations
|
||||
|
||||
%%
|
||||
[ /t] /* ignore whitespace */;
|
||||
%{
|
||||
LOC_STEP;
|
||||
%}
|
||||
|
||||
[ \t]+ LOC_STEP /* ignore whitespace */;
|
||||
{WORD} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return WORD;}
|
||||
{IPV4} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4;}
|
||||
{IPV4_PREFIX} {yylval->string = XSTRDUP(MTYPE_TMP, yytext); return IPV4_PREFIX;}
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "command_match.h"
|
||||
#include "memory.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens")
|
||||
DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack")
|
||||
|
||||
#define MAXDEPTH 64
|
||||
@ -322,7 +321,7 @@ command_match_r (struct graph_node *start, vector vline, unsigned int n,
|
||||
// copy token, set arg and prepend to currbest
|
||||
struct cmd_token *token = start->data;
|
||||
struct cmd_token *copy = copy_cmd_token (token);
|
||||
copy->arg = XSTRDUP (MTYPE_CMD_TOKENS, input_token);
|
||||
copy->arg = XSTRDUP (MTYPE_CMD_ARG, input_token);
|
||||
listnode_add_before (currbest, currbest->head, copy);
|
||||
matcher_rv = MATCHER_OK;
|
||||
}
|
||||
@ -459,7 +458,7 @@ command_complete (struct graph *graph,
|
||||
|
||||
/**
|
||||
* Adds all children that are reachable by one parser hop to the given list.
|
||||
* NUL_TKN, SELECTOR_TKN, and OPTION_TKN nodes are treated as transparent.
|
||||
* special tokens except END_TKN are treated as transparent.
|
||||
*
|
||||
* @param[in] list to add the nexthops to
|
||||
* @param[in] node to start calculating nexthops from
|
||||
@ -490,26 +489,24 @@ add_nexthops (struct list *list, struct graph_node *node,
|
||||
if (j != stackpos)
|
||||
continue;
|
||||
}
|
||||
switch (token->type)
|
||||
if (token->type >= SPECIAL_TKN && token->type != END_TKN)
|
||||
{
|
||||
case OPTION_TKN:
|
||||
case SELECTOR_TKN:
|
||||
case NUL_TKN:
|
||||
added += add_nexthops (list, child, stack, stackpos);
|
||||
break;
|
||||
default:
|
||||
if (stack)
|
||||
{
|
||||
nextstack = XMALLOC (MTYPE_CMD_MATCHSTACK,
|
||||
(stackpos + 1) * sizeof(struct graph_node *));
|
||||
nextstack[0] = child;
|
||||
memcpy(nextstack + 1, stack, stackpos * sizeof(struct graph_node *));
|
||||
added += add_nexthops (list, child, stack, stackpos);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stack)
|
||||
{
|
||||
nextstack = XMALLOC (MTYPE_CMD_MATCHSTACK,
|
||||
(stackpos + 1) * sizeof(struct graph_node *));
|
||||
nextstack[0] = child;
|
||||
memcpy(nextstack + 1, stack, stackpos * sizeof(struct graph_node *));
|
||||
|
||||
listnode_add (list, nextstack);
|
||||
}
|
||||
else
|
||||
listnode_add (list, child);
|
||||
added++;
|
||||
listnode_add (list, nextstack);
|
||||
}
|
||||
else
|
||||
listnode_add (list, child);
|
||||
added++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,8 @@
|
||||
#define YYDEBUG 1
|
||||
%}
|
||||
|
||||
%locations
|
||||
/* define parse.error verbose */
|
||||
%define api.pure full
|
||||
/* define api.prefix {cmd_yy} */
|
||||
|
||||
@ -49,14 +51,20 @@
|
||||
#include "graph.h"
|
||||
|
||||
#define YYSTYPE CMD_YYSTYPE
|
||||
#define YYLTYPE CMD_YYLTYPE
|
||||
struct parser_ctx;
|
||||
|
||||
/* subgraph semantic value */
|
||||
struct subgraph {
|
||||
struct graph_node *start, *end;
|
||||
};
|
||||
}
|
||||
|
||||
%union {
|
||||
long long number;
|
||||
char *string;
|
||||
struct graph_node *node;
|
||||
struct subgraph *subgraph;
|
||||
struct subgraph subgraph;
|
||||
}
|
||||
|
||||
%code provides {
|
||||
@ -94,28 +102,19 @@
|
||||
%type <node> literal_token
|
||||
%type <node> placeholder_token
|
||||
%type <node> simple_token
|
||||
%type <subgraph> option
|
||||
%type <subgraph> option_token
|
||||
%type <subgraph> option_token_seq
|
||||
%type <subgraph> selector
|
||||
%type <subgraph> selector_token
|
||||
%type <subgraph> selector_token_seq
|
||||
%type <subgraph> selector_seq_seq
|
||||
%type <subgraph> compound_token
|
||||
|
||||
%code {
|
||||
|
||||
/* bison declarations */
|
||||
void
|
||||
cmd_yyerror (struct parser_ctx *ctx, char const *msg);
|
||||
|
||||
/* subgraph semantic value */
|
||||
struct subgraph {
|
||||
struct graph_node *start, *end;
|
||||
};
|
||||
cmd_yyerror (CMD_YYLTYPE *locp, struct parser_ctx *ctx, char const *msg);
|
||||
|
||||
/* helper functions for parser */
|
||||
static char *
|
||||
static const char *
|
||||
doc_next (struct parser_ctx *ctx);
|
||||
|
||||
static struct graph_node *
|
||||
@ -130,11 +129,11 @@
|
||||
static struct graph_node *
|
||||
new_token_node (struct parser_ctx *,
|
||||
enum cmd_token_type type,
|
||||
char *text,
|
||||
char *doc);
|
||||
const char *text,
|
||||
const char *doc);
|
||||
|
||||
static void
|
||||
terminate_graph (struct parser_ctx *ctx,
|
||||
terminate_graph (CMD_YYLTYPE *locp, struct parser_ctx *ctx,
|
||||
struct graph_node *);
|
||||
|
||||
static void
|
||||
@ -173,7 +172,7 @@ start:
|
||||
cmd_token_seq
|
||||
{
|
||||
// tack on the command element
|
||||
terminate_graph (ctx, ctx->currnode);
|
||||
terminate_graph (&@1, ctx, ctx->currnode);
|
||||
}
|
||||
| cmd_token_seq placeholder_token '.' '.' '.'
|
||||
{
|
||||
@ -187,7 +186,7 @@ start:
|
||||
add_edge_dedup (ctx->currnode, ctx->currnode);
|
||||
|
||||
// tack on the command element
|
||||
terminate_graph (ctx, ctx->currnode);
|
||||
terminate_graph (&@1, ctx, ctx->currnode);
|
||||
}
|
||||
;
|
||||
|
||||
@ -202,11 +201,10 @@ cmd_token:
|
||||
if ((ctx->currnode = add_edge_dedup (ctx->currnode, $1)) != $1)
|
||||
graph_delete_node (ctx->graph, $1);
|
||||
}
|
||||
| compound_token
|
||||
| selector
|
||||
{
|
||||
graph_add_edge (ctx->currnode, $1->start);
|
||||
ctx->currnode = $1->end;
|
||||
free ($1);
|
||||
graph_add_edge (ctx->currnode, $1.start);
|
||||
ctx->currnode = $1.end;
|
||||
}
|
||||
;
|
||||
|
||||
@ -215,14 +213,9 @@ simple_token:
|
||||
| placeholder_token
|
||||
;
|
||||
|
||||
compound_token:
|
||||
selector
|
||||
| option
|
||||
;
|
||||
|
||||
literal_token: WORD
|
||||
{
|
||||
$$ = new_token_node (ctx, WORD_TKN, strdup($1), doc_next(ctx));
|
||||
$$ = new_token_node (ctx, WORD_TKN, $1, doc_next(ctx));
|
||||
free ($1);
|
||||
}
|
||||
;
|
||||
@ -230,32 +223,32 @@ literal_token: WORD
|
||||
placeholder_token:
|
||||
IPV4
|
||||
{
|
||||
$$ = new_token_node (ctx, IPV4_TKN, strdup($1), doc_next(ctx));
|
||||
$$ = new_token_node (ctx, IPV4_TKN, $1, doc_next(ctx));
|
||||
free ($1);
|
||||
}
|
||||
| IPV4_PREFIX
|
||||
{
|
||||
$$ = new_token_node (ctx, IPV4_PREFIX_TKN, strdup($1), doc_next(ctx));
|
||||
$$ = new_token_node (ctx, IPV4_PREFIX_TKN, $1, doc_next(ctx));
|
||||
free ($1);
|
||||
}
|
||||
| IPV6
|
||||
{
|
||||
$$ = new_token_node (ctx, IPV6_TKN, strdup($1), doc_next(ctx));
|
||||
$$ = new_token_node (ctx, IPV6_TKN, $1, doc_next(ctx));
|
||||
free ($1);
|
||||
}
|
||||
| IPV6_PREFIX
|
||||
{
|
||||
$$ = new_token_node (ctx, IPV6_PREFIX_TKN, strdup($1), doc_next(ctx));
|
||||
$$ = new_token_node (ctx, IPV6_PREFIX_TKN, $1, doc_next(ctx));
|
||||
free ($1);
|
||||
}
|
||||
| VARIABLE
|
||||
{
|
||||
$$ = new_token_node (ctx, VARIABLE_TKN, strdup($1), doc_next(ctx));
|
||||
$$ = new_token_node (ctx, VARIABLE_TKN, $1, doc_next(ctx));
|
||||
free ($1);
|
||||
}
|
||||
| RANGE
|
||||
{
|
||||
$$ = new_token_node (ctx, RANGE_TKN, strdup($1), doc_next(ctx));
|
||||
$$ = new_token_node (ctx, RANGE_TKN, $1, doc_next(ctx));
|
||||
struct cmd_token *token = $$->data;
|
||||
|
||||
// get the numbers out
|
||||
@ -265,7 +258,7 @@ placeholder_token:
|
||||
token->max = strtoll (yylval.string, &yylval.string, 10);
|
||||
|
||||
// validate range
|
||||
if (token->min > token->max) cmd_yyerror (ctx, "Invalid range.");
|
||||
if (token->min > token->max) cmd_yyerror (&@1, ctx, "Invalid range.");
|
||||
|
||||
free ($1);
|
||||
}
|
||||
@ -273,143 +266,68 @@ placeholder_token:
|
||||
/* <selector|set> productions */
|
||||
selector: '<' selector_seq_seq '>'
|
||||
{
|
||||
$$ = malloc (sizeof (struct subgraph));
|
||||
$$->start = new_token_node (ctx, SELECTOR_TKN, NULL, NULL);
|
||||
$$->end = new_token_node (ctx, NUL_TKN, NULL, NULL);
|
||||
for (unsigned int i = 0; i < vector_active ($2->start->to); i++)
|
||||
{
|
||||
struct graph_node *sn = vector_slot ($2->start->to, i),
|
||||
*en = vector_slot ($2->end->from, i);
|
||||
graph_add_edge ($$->start, sn);
|
||||
graph_add_edge (en, $$->end);
|
||||
}
|
||||
graph_delete_node (ctx->graph, $2->start);
|
||||
graph_delete_node (ctx->graph, $2->end);
|
||||
free ($2);
|
||||
$$ = $2;
|
||||
};
|
||||
|
||||
selector_seq_seq:
|
||||
selector_seq_seq '|' selector_token_seq
|
||||
{
|
||||
$$ = malloc (sizeof (struct subgraph));
|
||||
$$->start = graph_new_node (ctx->graph, NULL, NULL);
|
||||
$$->end = graph_new_node (ctx->graph, NULL, NULL);
|
||||
|
||||
// link in last sequence
|
||||
graph_add_edge ($$->start, $3->start);
|
||||
graph_add_edge ($3->end, $$->end);
|
||||
|
||||
for (unsigned int i = 0; i < vector_active ($1->start->to); i++)
|
||||
{
|
||||
struct graph_node *sn = vector_slot ($1->start->to, i),
|
||||
*en = vector_slot ($1->end->from, i);
|
||||
graph_add_edge ($$->start, sn);
|
||||
graph_add_edge (en, $$->end);
|
||||
}
|
||||
graph_delete_node (ctx->graph, $1->start);
|
||||
graph_delete_node (ctx->graph, $1->end);
|
||||
free ($1);
|
||||
free ($3);
|
||||
$$ = $1;
|
||||
graph_add_edge ($$.start, $3.start);
|
||||
graph_add_edge ($3.end, $$.end);
|
||||
}
|
||||
| selector_token_seq '|' selector_token_seq
|
||||
| selector_token_seq
|
||||
{
|
||||
$$ = malloc (sizeof (struct subgraph));
|
||||
$$->start = graph_new_node (ctx->graph, NULL, NULL);
|
||||
$$->end = graph_new_node (ctx->graph, NULL, NULL);
|
||||
graph_add_edge ($$->start, $1->start);
|
||||
graph_add_edge ($1->end, $$->end);
|
||||
graph_add_edge ($$->start, $3->start);
|
||||
graph_add_edge ($3->end, $$->end);
|
||||
free ($1);
|
||||
free ($3);
|
||||
$$.start = new_token_node (ctx, FORK_TKN, NULL, NULL);
|
||||
$$.end = new_token_node (ctx, JOIN_TKN, NULL, NULL);
|
||||
((struct cmd_token *)$$.start->data)->forkjoin = $$.end;
|
||||
((struct cmd_token *)$$.end->data)->forkjoin = $$.start;
|
||||
|
||||
graph_add_edge ($$.start, $1.start);
|
||||
graph_add_edge ($1.end, $$.end);
|
||||
}
|
||||
;
|
||||
|
||||
/* {keyword} productions */
|
||||
selector: '{' selector_seq_seq '}'
|
||||
{
|
||||
$$ = malloc (sizeof (struct subgraph));
|
||||
$$->start = new_token_node (ctx, SELECTOR_TKN, NULL, NULL);
|
||||
$$->end = new_token_node (ctx, NUL_TKN, NULL, NULL);
|
||||
graph_add_edge ($$->start, $$->end);
|
||||
for (unsigned int i = 0; i < vector_active ($2->start->to); i++)
|
||||
{
|
||||
struct graph_node *sn = vector_slot ($2->start->to, i),
|
||||
*en = vector_slot ($2->end->from, i);
|
||||
graph_add_edge ($$->start, sn);
|
||||
graph_add_edge (en, $$->start);
|
||||
}
|
||||
graph_delete_node (ctx->graph, $2->start);
|
||||
graph_delete_node (ctx->graph, $2->end);
|
||||
free ($2);
|
||||
$$ = $2;
|
||||
graph_add_edge ($$.end, $$.start);
|
||||
/* there is intentionally no start->end link, for two reasons:
|
||||
* 1) this allows "at least 1 of" semantics, which are otherwise impossible
|
||||
* 2) this would add a start->end->start loop in the graph that the current
|
||||
* loop-avoidal fails to handle
|
||||
* just use [{a|b}] if neccessary, that will work perfectly fine, and reason
|
||||
* #1 is good enough to keep it this way. */
|
||||
};
|
||||
|
||||
|
||||
selector_token_seq:
|
||||
simple_token
|
||||
{
|
||||
$$ = malloc (sizeof (struct subgraph));
|
||||
$$->start = $$->end = $1;
|
||||
}
|
||||
| selector_token_seq selector_token
|
||||
{
|
||||
$$ = malloc (sizeof (struct subgraph));
|
||||
graph_add_edge ($1->end, $2->start);
|
||||
$$->start = $1->start;
|
||||
$$->end = $2->end;
|
||||
free ($1);
|
||||
free ($2);
|
||||
}
|
||||
;
|
||||
|
||||
selector_token:
|
||||
simple_token
|
||||
{
|
||||
$$ = malloc (sizeof (struct subgraph));
|
||||
$$->start = $$->end = $1;
|
||||
$$.start = $$.end = $1;
|
||||
}
|
||||
| option
|
||||
| selector
|
||||
;
|
||||
|
||||
selector_token_seq:
|
||||
selector_token_seq selector_token
|
||||
{
|
||||
graph_add_edge ($1.end, $2.start);
|
||||
$$.start = $1.start;
|
||||
$$.end = $2.end;
|
||||
}
|
||||
| selector_token
|
||||
;
|
||||
|
||||
/* [option] productions */
|
||||
option: '[' option_token_seq ']'
|
||||
selector: '[' selector_seq_seq ']'
|
||||
{
|
||||
// make a new option
|
||||
$$ = malloc (sizeof (struct subgraph));
|
||||
$$->start = new_token_node (ctx, OPTION_TKN, NULL, NULL);
|
||||
$$->end = new_token_node (ctx, NUL_TKN, NULL, NULL);
|
||||
// add a path through the sequence to the end
|
||||
graph_add_edge ($$->start, $2->start);
|
||||
graph_add_edge ($2->end, $$->end);
|
||||
// add a path directly from the start to the end
|
||||
graph_add_edge ($$->start, $$->end);
|
||||
free ($2);
|
||||
$$ = $2;
|
||||
graph_add_edge ($$.start, $$.end);
|
||||
}
|
||||
;
|
||||
|
||||
option_token_seq:
|
||||
option_token
|
||||
| option_token_seq option_token
|
||||
{
|
||||
$$ = malloc (sizeof (struct subgraph));
|
||||
graph_add_edge ($1->end, $2->start);
|
||||
$$->start = $1->start;
|
||||
$$->end = $2->end;
|
||||
free ($1);
|
||||
free ($2);
|
||||
}
|
||||
;
|
||||
|
||||
option_token:
|
||||
simple_token
|
||||
{
|
||||
$$ = malloc (sizeof (struct subgraph));
|
||||
$$->start = $$->end = $1;
|
||||
}
|
||||
| compound_token
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
#undef scanner
|
||||
@ -437,11 +355,39 @@ command_parse_format (struct graph *graph, struct cmd_element *cmd)
|
||||
/* parser helper functions */
|
||||
|
||||
void
|
||||
yyerror (struct parser_ctx *ctx, char const *msg)
|
||||
yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
|
||||
{
|
||||
char *tmpstr = strdup(ctx->el->string);
|
||||
char *line, *eol;
|
||||
char spacing[256];
|
||||
int lineno = 0;
|
||||
|
||||
zlog_err ("%s: FATAL parse error: %s", __func__, msg);
|
||||
zlog_err ("while parsing this command definition: \n\t%s\n", ctx->el->string);
|
||||
//exit(EXIT_FAILURE);
|
||||
zlog_err ("%s: %d:%d-%d of this command definition:", __func__, loc->first_line, loc->first_column, loc->last_column);
|
||||
|
||||
line = tmpstr;
|
||||
do {
|
||||
lineno++;
|
||||
eol = strchr(line, '\n');
|
||||
if (eol)
|
||||
*eol++ = '\0';
|
||||
|
||||
zlog_err ("%s: | %s", __func__, line);
|
||||
if (lineno == loc->first_line && lineno == loc->last_line
|
||||
&& loc->first_column < (int)sizeof(spacing) - 1
|
||||
&& loc->last_column < (int)sizeof(spacing) - 1) {
|
||||
|
||||
int len = loc->last_column - loc->first_column;
|
||||
if (len == 0)
|
||||
len = 1;
|
||||
|
||||
memset(spacing, ' ', loc->first_column - 1);
|
||||
memset(spacing + loc->first_column - 1, '^', len);
|
||||
spacing[loc->first_column - 1 + len] = '\0';
|
||||
zlog_err ("%s: | %s", __func__, spacing);
|
||||
}
|
||||
} while ((line = eol));
|
||||
free(tmpstr);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -456,27 +402,25 @@ cleanup (struct parser_ctx *ctx)
|
||||
}
|
||||
|
||||
static void
|
||||
terminate_graph (struct parser_ctx *ctx, struct graph_node *finalnode)
|
||||
terminate_graph (CMD_YYLTYPE *locp, struct parser_ctx *ctx,
|
||||
struct graph_node *finalnode)
|
||||
{
|
||||
// end of graph should look like this
|
||||
// * -> finalnode -> END_TKN -> cmd_element
|
||||
struct cmd_element *element = ctx->el;
|
||||
struct graph_node *end_token_node =
|
||||
new_token_node (ctx,
|
||||
END_TKN,
|
||||
strdup (CMD_CR_TEXT),
|
||||
strdup (""));
|
||||
new_token_node (ctx, END_TKN, CMD_CR_TEXT, "");
|
||||
struct graph_node *end_element_node =
|
||||
graph_new_node (ctx->graph, element, NULL);
|
||||
|
||||
if (node_adjacent (finalnode, end_token_node))
|
||||
cmd_yyerror (ctx, "Duplicate command.");
|
||||
cmd_yyerror (locp, ctx, "Duplicate command.");
|
||||
|
||||
graph_add_edge (finalnode, end_token_node);
|
||||
graph_add_edge (end_token_node, end_element_node);
|
||||
}
|
||||
|
||||
static char *
|
||||
static const char *
|
||||
doc_next (struct parser_ctx *ctx)
|
||||
{
|
||||
const char *piece = ctx->docstr ? strsep (&ctx->docstr, "\n") : "";
|
||||
@ -486,12 +430,12 @@ doc_next (struct parser_ctx *ctx)
|
||||
piece = "";
|
||||
}
|
||||
|
||||
return strdup (piece);
|
||||
return piece;
|
||||
}
|
||||
|
||||
static struct graph_node *
|
||||
new_token_node (struct parser_ctx *ctx, enum cmd_token_type type,
|
||||
char *text, char *doc)
|
||||
const char *text, const char *doc)
|
||||
{
|
||||
struct cmd_token *token = new_cmd_token (type, ctx->el->attr, text, doc);
|
||||
return graph_new_node (ctx->graph, token, (void (*)(void *)) &del_cmd_token);
|
||||
@ -575,8 +519,7 @@ cmp_token (struct cmd_token *first, struct cmd_token *second)
|
||||
* cases; ultimately this forks the graph, but the matcher can handle
|
||||
* this regardless
|
||||
*/
|
||||
case SELECTOR_TKN:
|
||||
case OPTION_TKN:
|
||||
case FORK_TKN:
|
||||
return 0;
|
||||
|
||||
/* end nodes are always considered equal, since each node may only
|
||||
@ -584,7 +527,7 @@ cmp_token (struct cmd_token *first, struct cmd_token *second)
|
||||
*/
|
||||
case START_TKN:
|
||||
case END_TKN:
|
||||
case NUL_TKN:
|
||||
case JOIN_TKN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -3,11 +3,6 @@
|
||||
*
|
||||
* This unit defines a number of commands in the old engine that can
|
||||
* be used to test and interact with the new engine.
|
||||
*
|
||||
* This shim should be removed upon integration. It is currently hooked in
|
||||
* vtysh/vtysh.c. It has no header, vtysh.c merely includes this entire unit
|
||||
* since it clutters up the makefiles less and this is only a temporary shim.
|
||||
*
|
||||
* --
|
||||
* Copyright (C) 2016 Cumulus Networks, Inc.
|
||||
*
|
||||
@ -45,15 +40,15 @@ void
|
||||
grammar_sandbox_init (void);
|
||||
void
|
||||
pretty_print_graph (struct vty *vty, struct graph_node *, int, int, struct graph_node **, size_t);
|
||||
static void
|
||||
pretty_print_dot (FILE *ofd, unsigned opts, struct graph_node *start,
|
||||
struct graph_node **stack, size_t stackpos,
|
||||
struct graph_node **visited, size_t *visitpos);
|
||||
void
|
||||
init_cmdgraph (struct vty *, struct graph **);
|
||||
vector
|
||||
completions_to_vec (struct list *);
|
||||
int
|
||||
compare_completions (const void *, const void *);
|
||||
|
||||
/** shim interface commands **/
|
||||
struct graph *nodegraph;
|
||||
struct graph *nodegraph = NULL, *nodegraph_free = NULL;
|
||||
|
||||
DEFUN (grammar_test,
|
||||
grammar_test_cmd,
|
||||
@ -240,17 +235,77 @@ DEFUN (grammar_test_show,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (grammar_test_dot,
|
||||
grammar_test_dot_cmd,
|
||||
"grammar dotfile OUTNAME",
|
||||
GRAMMAR_STR
|
||||
"print current graph for dot\n"
|
||||
".dot filename\n")
|
||||
{
|
||||
struct graph_node *stack[MAXDEPTH];
|
||||
struct graph_node *visited[MAXDEPTH*MAXDEPTH];
|
||||
size_t vpos = 0;
|
||||
|
||||
if (!nodegraph) {
|
||||
vty_out(vty, "nodegraph uninitialized\r\n");
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
FILE *ofd = fopen(argv[2]->arg, "w");
|
||||
if (!ofd) {
|
||||
vty_out(vty, "%s: %s\r\n", argv[2]->arg, strerror(errno));
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
fprintf(ofd, "digraph {\n graph [ rankdir = LR ];\n node [ fontname = \"Fira Mono\", fontsize = 9 ];\n\n");
|
||||
pretty_print_dot (ofd, 0,
|
||||
vector_slot (nodegraph->nodes, 0),
|
||||
stack, 0, visited, &vpos);
|
||||
fprintf(ofd, "}\n");
|
||||
fclose(ofd);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (grammar_init_graph,
|
||||
grammar_init_graph_cmd,
|
||||
"grammar init",
|
||||
GRAMMAR_STR
|
||||
"(re)initialize graph\n")
|
||||
{
|
||||
graph_delete_graph (nodegraph);
|
||||
if (nodegraph_free)
|
||||
graph_delete_graph (nodegraph_free);
|
||||
nodegraph_free = NULL;
|
||||
|
||||
init_cmdgraph (vty, &nodegraph);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
extern vector cmdvec;
|
||||
|
||||
DEFUN (grammar_access,
|
||||
grammar_access_cmd,
|
||||
"grammar access (0-65535)",
|
||||
GRAMMAR_STR
|
||||
"access node graph\n"
|
||||
"node number\n")
|
||||
{
|
||||
if (nodegraph_free)
|
||||
graph_delete_graph (nodegraph_free);
|
||||
nodegraph_free = NULL;
|
||||
|
||||
struct cmd_node *cnode;
|
||||
|
||||
cnode = vector_slot (cmdvec, atoi (argv[2]->arg));
|
||||
if (!cnode)
|
||||
{
|
||||
vty_out (vty, "%% no such node%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
vty_out (vty, "node %d%s", (int)cnode->node, VTY_NEWLINE);
|
||||
nodegraph = cnode->cmdgraph;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* this is called in vtysh.c to set up the testing shim */
|
||||
void grammar_sandbox_init(void) {
|
||||
init_cmdgraph (NULL, &nodegraph);
|
||||
@ -258,10 +313,12 @@ void grammar_sandbox_init(void) {
|
||||
// install all enable elements
|
||||
install_element (ENABLE_NODE, &grammar_test_cmd);
|
||||
install_element (ENABLE_NODE, &grammar_test_show_cmd);
|
||||
install_element (ENABLE_NODE, &grammar_test_dot_cmd);
|
||||
install_element (ENABLE_NODE, &grammar_test_match_cmd);
|
||||
install_element (ENABLE_NODE, &grammar_test_complete_cmd);
|
||||
install_element (ENABLE_NODE, &grammar_test_doc_cmd);
|
||||
install_element (ENABLE_NODE, &grammar_init_graph_cmd);
|
||||
install_element (ENABLE_NODE, &grammar_access_cmd);
|
||||
}
|
||||
|
||||
#define item(x) { x, #x }
|
||||
@ -275,9 +332,8 @@ struct message tokennames[] = {
|
||||
item(IPV6_PREFIX_TKN), // IPV6 network prefixes
|
||||
|
||||
/* plumbing types */
|
||||
item(SELECTOR_TKN), // marks beginning of selector
|
||||
item(OPTION_TKN), // marks beginning of option
|
||||
item(NUL_TKN), // dummy token
|
||||
item(FORK_TKN),
|
||||
item(JOIN_TKN),
|
||||
item(START_TKN), // first token in line
|
||||
item(END_TKN), // last token in line
|
||||
{ 0, NULL }
|
||||
@ -292,7 +348,7 @@ size_t tokennames_max = array_size(tokennames);
|
||||
*/
|
||||
void
|
||||
pretty_print_graph (struct vty *vty, struct graph_node *start, int level,
|
||||
int desc, struct graph_node **stack, size_t stackpos)
|
||||
int desc, struct graph_node **stack, size_t stackpos)
|
||||
{
|
||||
// print this node
|
||||
char tokennum[32];
|
||||
@ -346,92 +402,92 @@ pretty_print_graph (struct vty *vty, struct graph_node *start, int level,
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static void
|
||||
pretty_print_dot (FILE *ofd, unsigned opts, struct graph_node *start,
|
||||
struct graph_node **stack, size_t stackpos,
|
||||
struct graph_node **visited, size_t *visitpos)
|
||||
{
|
||||
// print this node
|
||||
char tokennum[32];
|
||||
struct cmd_token *tok = start->data;
|
||||
const char *color;
|
||||
|
||||
for (size_t i = 0; i < (*visitpos); i++)
|
||||
if (visited[i] == start)
|
||||
return;
|
||||
visited[(*visitpos)++] = start;
|
||||
if ((*visitpos) == MAXDEPTH*MAXDEPTH)
|
||||
return;
|
||||
|
||||
snprintf(tokennum, sizeof(tokennum), "%d?", tok->type);
|
||||
fprintf(ofd, " n%016llx [ shape=box, label=<", (unsigned long long)start);
|
||||
|
||||
fprintf(ofd, "<b>%s</b>", LOOKUP_DEF(tokennames, tok->type, tokennum));
|
||||
if (tok->attr == CMD_ATTR_DEPRECATED)
|
||||
fprintf(ofd, " (d)");
|
||||
else if (tok->attr == CMD_ATTR_HIDDEN)
|
||||
fprintf(ofd, " (h)");
|
||||
if (tok->text) {
|
||||
if (tok->type == WORD_TKN)
|
||||
fprintf(ofd, "<br/>\"<font color=\"#0055ff\" point-size=\"11\"><b>%s</b></font>\"", tok->text);
|
||||
else
|
||||
fprintf(ofd, "<br/>%s", tok->text);
|
||||
}
|
||||
/* if (desc)
|
||||
fprintf(ofd, " ?'%s'", tok->desc); */
|
||||
switch (tok->type) {
|
||||
case START_TKN: color = "#ccffcc"; break;
|
||||
case FORK_TKN: color = "#aaddff"; break;
|
||||
case JOIN_TKN: color = "#ddaaff"; break;
|
||||
case WORD_TKN: color = "#ffffff"; break;
|
||||
default: color = "#ffffff"; break;
|
||||
}
|
||||
fprintf(ofd, ">, style = filled, fillcolor = \"%s\" ];\n", color);
|
||||
|
||||
if (stackpos == MAXDEPTH)
|
||||
return;
|
||||
stack[stackpos++] = start;
|
||||
|
||||
for (unsigned int i = 0; i < vector_active (start->to); i++)
|
||||
{
|
||||
struct graph_node *adj = vector_slot (start->to, i);
|
||||
// if this node is a vararg, just print *
|
||||
if (adj == start) {
|
||||
fprintf(ofd, " n%016llx -> n%016llx;\n",
|
||||
(unsigned long long)start,
|
||||
(unsigned long long)start);
|
||||
} else if (((struct cmd_token *)adj->data)->type == END_TKN) {
|
||||
//struct cmd_token *et = adj->data;
|
||||
fprintf(ofd, " n%016llx -> end%016llx;\n",
|
||||
(unsigned long long)start,
|
||||
(unsigned long long)adj);
|
||||
fprintf(ofd, " end%016llx [ shape=box, label=<end>, style = filled, fillcolor = \"#ffddaa\" ];\n",
|
||||
(unsigned long long)adj);
|
||||
} else {
|
||||
fprintf(ofd, " n%016llx -> n%016llx;\n",
|
||||
(unsigned long long)start,
|
||||
(unsigned long long)adj);
|
||||
size_t k;
|
||||
for (k = 0; k < stackpos; k++)
|
||||
if (stack[k] == adj)
|
||||
break;
|
||||
if (k == stackpos) {
|
||||
pretty_print_dot (ofd, opts, adj, stack, stackpos, visited, visitpos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** stuff that should go in command.c + command.h */
|
||||
void
|
||||
init_cmdgraph (struct vty *vty, struct graph **graph)
|
||||
{
|
||||
// initialize graph, add start noe
|
||||
*graph = graph_new ();
|
||||
nodegraph_free = *graph;
|
||||
struct cmd_token *token = new_cmd_token (START_TKN, 0, NULL, NULL);
|
||||
graph_new_node (*graph, token, (void (*)(void *)) &del_cmd_token);
|
||||
if (vty)
|
||||
vty_out (vty, "initialized graph%s", VTY_NEWLINE);
|
||||
}
|
||||
|
||||
int
|
||||
compare_completions (const void *fst, const void *snd)
|
||||
{
|
||||
struct cmd_token *first = *(struct cmd_token **) fst,
|
||||
*secnd = *(struct cmd_token **) snd;
|
||||
return strcmp (first->text, secnd->text);
|
||||
}
|
||||
|
||||
vector
|
||||
completions_to_vec (struct list *completions)
|
||||
{
|
||||
vector comps = vector_init (VECTOR_MIN_SIZE);
|
||||
|
||||
struct listnode *ln;
|
||||
struct cmd_token *token;
|
||||
unsigned int i, exists;
|
||||
for (ALL_LIST_ELEMENTS_RO(completions,ln,token))
|
||||
{
|
||||
// linear search for token in completions vector
|
||||
exists = 0;
|
||||
for (i = 0; i < vector_active (comps) && !exists; i++)
|
||||
{
|
||||
struct cmd_token *curr = vector_slot (comps, i);
|
||||
exists = !strcmp (curr->text, token->text) &&
|
||||
!strcmp (curr->desc, token->desc);
|
||||
}
|
||||
|
||||
if (!exists)
|
||||
vector_set (comps, copy_cmd_token (token));
|
||||
}
|
||||
|
||||
// sort completions
|
||||
qsort (comps->index,
|
||||
vector_active (comps),
|
||||
sizeof (void *),
|
||||
&compare_completions);
|
||||
|
||||
return comps;
|
||||
}
|
||||
|
||||
static void vty_do_exit(void)
|
||||
{
|
||||
printf ("\nend.\n");
|
||||
exit (0);
|
||||
}
|
||||
|
||||
struct thread_master *master;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct thread thread;
|
||||
|
||||
master = thread_master_create ();
|
||||
|
||||
zlog_default = openzlog ("grammar_sandbox", ZLOG_NONE, 0,
|
||||
LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
|
||||
zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
|
||||
zlog_set_level (NULL, ZLOG_DEST_STDOUT, LOG_DEBUG);
|
||||
zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
|
||||
|
||||
/* Library inits. */
|
||||
cmd_init (1);
|
||||
host.name = strdup ("test");
|
||||
|
||||
vty_init (master);
|
||||
memory_init ();
|
||||
grammar_sandbox_init();
|
||||
|
||||
vty_stdio (vty_do_exit);
|
||||
|
||||
/* Fetch next active thread. */
|
||||
while (thread_fetch (master, &thread))
|
||||
thread_call (&thread);
|
||||
|
||||
/* Not reached. */
|
||||
exit (0);
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
#ifndef _GRAMMAR_SANDBOX_H
|
||||
#define _GRAMMAR_SANDBOX_H
|
||||
|
||||
/**
|
||||
* Houses functionality for testing shim as well as code that should go into
|
||||
* command.h and command.c during integration.
|
||||
*/
|
||||
#include "memory.h"
|
||||
|
||||
#define CMD_CR_TEXT "<cr>"
|
||||
|
||||
void
|
||||
grammar_sandbox_init (void);
|
||||
|
||||
/**
|
||||
* Types for tokens.
|
||||
*
|
||||
* The type determines what kind of data the token can match (in the
|
||||
* matching use case) or hold (in the argv use case).
|
||||
*/
|
||||
enum cmd_token_type_t
|
||||
{
|
||||
WORD_TKN, // words
|
||||
NUMBER_TKN, // integral numbers
|
||||
VARIABLE_TKN, // almost anything
|
||||
RANGE_TKN, // integer range
|
||||
IPV4_TKN, // IPV4 addresses
|
||||
IPV4_PREFIX_TKN, // IPV4 network prefixes
|
||||
IPV6_TKN, // IPV6 prefixes
|
||||
IPV6_PREFIX_TKN, // IPV6 network prefixes
|
||||
|
||||
/* plumbing types */
|
||||
SELECTOR_TKN, // marks beginning of selector
|
||||
OPTION_TKN, // marks beginning of option
|
||||
NUL_TKN, // dummy token
|
||||
START_TKN, // first token in line
|
||||
END_TKN, // last token in line
|
||||
};
|
||||
|
||||
/**
|
||||
* Token struct.
|
||||
*/
|
||||
struct cmd_token_t
|
||||
{
|
||||
enum cmd_token_type_t type; // token type
|
||||
|
||||
char *text; // token text
|
||||
char *desc; // token description
|
||||
|
||||
long long value; // for numeric types
|
||||
long long min, max; // for ranges
|
||||
|
||||
char *arg; // user input that matches this token
|
||||
};
|
||||
|
||||
#endif /* _GRAMMAR_SANDBOX_H */
|
64
lib/grammar_sandbox_main.c
Normal file
64
lib/grammar_sandbox_main.c
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Testing shim and API examples for the new CLI backend.
|
||||
*
|
||||
* Minimal main() to run grammar_sandbox standalone.
|
||||
* [split off grammar_sandbox.c 2017-01-23]
|
||||
* --
|
||||
* Copyright (C) 2016 Cumulus Networks, Inc.
|
||||
* Copyright (C) 2017 David Lamparter for NetDEF, Inc.
|
||||
*
|
||||
* This file is part of FreeRangeRouting (FRR).
|
||||
*
|
||||
* FRR 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.
|
||||
*
|
||||
* FRR 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 FRR; see the file COPYING. If not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "command.h"
|
||||
#include "memory_vty.h"
|
||||
|
||||
static void vty_do_exit(void)
|
||||
{
|
||||
printf ("\nend.\n");
|
||||
exit (0);
|
||||
}
|
||||
|
||||
struct thread_master *master;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct thread thread;
|
||||
|
||||
master = thread_master_create ();
|
||||
|
||||
zlog_default = openzlog ("grammar_sandbox", ZLOG_NONE, 0,
|
||||
LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
|
||||
zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
|
||||
zlog_set_level (NULL, ZLOG_DEST_STDOUT, LOG_DEBUG);
|
||||
zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
|
||||
|
||||
/* Library inits. */
|
||||
cmd_init (1);
|
||||
host.name = strdup ("test");
|
||||
|
||||
vty_init (master);
|
||||
memory_init ();
|
||||
|
||||
vty_stdio (vty_do_exit);
|
||||
|
||||
/* Fetch next active thread. */
|
||||
while (thread_fetch (master, &thread))
|
||||
thread_call (&thread);
|
||||
|
||||
/* Not reached. */
|
||||
exit (0);
|
||||
}
|
48
lib/graph.c
48
lib/graph.c
@ -55,11 +55,16 @@ graph_new_node (struct graph *graph, void *data, void (*del) (void*))
|
||||
static void
|
||||
vector_remove (vector v, unsigned int ix)
|
||||
{
|
||||
vector_unset (v, ix);
|
||||
if (ix == vector_active (v)) return;
|
||||
for (; ix < vector_active (v) - 1; ix++)
|
||||
v->index[ix] = v->index[ix+1];
|
||||
if (ix >= v->active)
|
||||
return;
|
||||
|
||||
/* v->active is guaranteed >= 1 because ix can't be lower than 0
|
||||
* and v->active is > ix. */
|
||||
v->active--;
|
||||
/* if ix == v->active--, we set the item to itself, then to NULL...
|
||||
* still correct, no check neccessary. */
|
||||
v->index[ix] = v->index[v->active];
|
||||
v->index[v->active] = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
@ -71,22 +76,18 @@ graph_delete_node (struct graph *graph, struct graph_node *node)
|
||||
struct graph_node *adj;
|
||||
|
||||
// remove all edges from other nodes to us
|
||||
vector edges = vector_copy (node->from);
|
||||
for (unsigned int i = 0; i < vector_active (edges); i++)
|
||||
for (unsigned int i = vector_active (node->from); i--; /**/)
|
||||
{
|
||||
adj = vector_slot (edges, i);
|
||||
adj = vector_slot (node->from, i);
|
||||
graph_remove_edge (adj, node);
|
||||
}
|
||||
vector_free (edges);
|
||||
|
||||
// remove all edges from us to other nodes
|
||||
edges = vector_copy (node->to);
|
||||
for (unsigned int i = 0; i < vector_active (edges); i++)
|
||||
for (unsigned int i = vector_active (node->to); i--; /**/)
|
||||
{
|
||||
adj = vector_slot (edges, i);
|
||||
adj = vector_slot (node->to, i);
|
||||
graph_remove_edge (node, adj);
|
||||
}
|
||||
vector_free (edges);
|
||||
|
||||
// if there is a deletion callback, call it
|
||||
if (node->del && node->data)
|
||||
@ -97,9 +98,12 @@ graph_delete_node (struct graph *graph, struct graph_node *node)
|
||||
vector_free (node->from);
|
||||
|
||||
// remove node from graph->nodes
|
||||
for (unsigned int i = 0; i < vector_active (graph->nodes); i++)
|
||||
for (unsigned int i = vector_active (graph->nodes); i--; /**/)
|
||||
if (vector_slot (graph->nodes, i) == node)
|
||||
vector_remove (graph->nodes, i);
|
||||
{
|
||||
vector_remove (graph->nodes, i);
|
||||
break;
|
||||
}
|
||||
|
||||
// free the node itself
|
||||
XFREE (MTYPE_GRAPH_NODE, node);
|
||||
@ -117,20 +121,26 @@ void
|
||||
graph_remove_edge (struct graph_node *from, struct graph_node *to)
|
||||
{
|
||||
// remove from from to->from
|
||||
for (unsigned int i = 0; i < vector_active (to->from); i++)
|
||||
for (unsigned int i = vector_active (to->from); i--; /**/)
|
||||
if (vector_slot (to->from, i) == from)
|
||||
vector_remove (to->from, i);
|
||||
{
|
||||
vector_remove (to->from, i);
|
||||
break;
|
||||
}
|
||||
// remove to from from->to
|
||||
for (unsigned int i = 0; i < vector_active (from->to); i++)
|
||||
for (unsigned int i = vector_active (from->to); i--; /**/)
|
||||
if (vector_slot (from->to, i) == to)
|
||||
vector_remove (from->to, i);
|
||||
{
|
||||
vector_remove (from->to, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
graph_delete_graph (struct graph *graph)
|
||||
{
|
||||
// delete each node in the graph
|
||||
for (unsigned int i = 0; i < vector_active (graph->nodes); i++)
|
||||
for (unsigned int i = vector_active (graph->nodes); i--; /**/)
|
||||
graph_delete_node (graph, vector_slot (graph->nodes, i));
|
||||
|
||||
vector_free (graph->nodes);
|
||||
|
@ -118,7 +118,6 @@ quagga_timestamp(int timestamp_precision, char *buf, size_t buflen)
|
||||
} cache;
|
||||
struct timeval clock;
|
||||
|
||||
/* would it be sufficient to use global 'recent_time' here? I fear not... */
|
||||
gettimeofday(&clock, NULL);
|
||||
|
||||
/* first, we update the cache if the time has changed */
|
||||
@ -989,6 +988,7 @@ static const struct zebra_desc_table command_types[] = {
|
||||
DESC_ENTRY (ZEBRA_IPV4_NEXTHOP_DELETE),
|
||||
DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_ADD),
|
||||
DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_DELETE),
|
||||
DESC_ENTRY (ZEBRA_IPMR_ROUTE_STATS),
|
||||
};
|
||||
#undef DESC_ENTRY
|
||||
|
||||
|
77
lib/monotime.h
Normal file
77
lib/monotime.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2017 David Lamparter, for NetDEF, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _FRR_MONOTIME_H
|
||||
#define _FRR_MONOTIME_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifndef TIMESPEC_TO_TIMEVAL
|
||||
/* should be in sys/time.h on BSD & Linux libcs */
|
||||
#define TIMESPEC_TO_TIMEVAL(tv, ts) do { \
|
||||
(tv)->tv_sec = (ts)->tv_sec; \
|
||||
(tv)->tv_usec = (ts)->tv_nsec / 1000; \
|
||||
} while (0)
|
||||
#endif
|
||||
#ifndef TIMEVAL_TO_TIMESPEC
|
||||
/* should be in sys/time.h on BSD & Linux libcs */
|
||||
#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
|
||||
(ts)->tv_sec = (tv)->tv_sec; \
|
||||
(ts)->tv_nsec = (tv)->tv_usec * 1000; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static inline time_t monotime(struct timeval *tvo)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
if (tvo) {
|
||||
TIMESPEC_TO_TIMEVAL(tvo, &ts);
|
||||
}
|
||||
return ts.tv_sec;
|
||||
}
|
||||
|
||||
/* the following two return microseconds, not time_t!
|
||||
*
|
||||
* also, they're negative forms of each other, but having both makes the
|
||||
* code more readable
|
||||
*/
|
||||
static inline int64_t monotime_since(const struct timeval *ref,
|
||||
struct timeval *out)
|
||||
{
|
||||
struct timeval tv;
|
||||
monotime(&tv);
|
||||
timersub(&tv, ref, &tv);
|
||||
if (out)
|
||||
*out = tv;
|
||||
return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
|
||||
}
|
||||
|
||||
static inline int64_t monotime_until(const struct timeval *ref,
|
||||
struct timeval *out)
|
||||
{
|
||||
struct timeval tv;
|
||||
monotime(&tv);
|
||||
timersub(ref, &tv, &tv);
|
||||
if (out)
|
||||
*out = tv;
|
||||
return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
|
||||
}
|
||||
|
||||
#endif /* _FRR_MONOTIME_H */
|
@ -62,8 +62,13 @@ writen(int fd, const u_char *ptr, int nbytes)
|
||||
while (nleft > 0)
|
||||
{
|
||||
nwritten = write(fd, ptr, nleft);
|
||||
|
||||
if (nwritten <= 0)
|
||||
|
||||
if (nwritten < 0)
|
||||
{
|
||||
if (!ERRNO_IO_RETRY(errno))
|
||||
return nwritten;
|
||||
}
|
||||
if (nwritten == 0)
|
||||
return (nwritten);
|
||||
|
||||
nleft -= nwritten;
|
||||
|
@ -710,6 +710,7 @@ enum route_map_dep_type
|
||||
ROUTE_MAP_DEP_RMAP = 1,
|
||||
ROUTE_MAP_DEP_CLIST,
|
||||
ROUTE_MAP_DEP_ECLIST,
|
||||
ROUTE_MAP_DEP_LCLIST,
|
||||
ROUTE_MAP_DEP_PLIST,
|
||||
ROUTE_MAP_DEP_ASPATH,
|
||||
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_ECLIST_ADDED:
|
||||
case RMAP_EVENT_ASLIST_ADDED:
|
||||
case RMAP_EVENT_LLIST_ADDED:
|
||||
case RMAP_EVENT_CALL_ADDED:
|
||||
case RMAP_EVENT_FILTER_ADDED:
|
||||
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_ECLIST_DELETED:
|
||||
case RMAP_EVENT_ASLIST_DELETED:
|
||||
case RMAP_EVENT_LLIST_DELETED:
|
||||
case RMAP_EVENT_CALL_DELETED:
|
||||
case RMAP_EVENT_FILTER_DELETED:
|
||||
if (rmap_debug)
|
||||
@ -1902,6 +1905,10 @@ route_map_get_dep_hash (route_map_event_t event)
|
||||
case RMAP_EVENT_ASLIST_DELETED:
|
||||
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_ASPATH];
|
||||
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_DELETED:
|
||||
upd8_hash = route_map_dep_hash[ROUTE_MAP_DEP_RMAP];
|
||||
|
@ -84,6 +84,8 @@ typedef enum
|
||||
RMAP_EVENT_CLIST_DELETED,
|
||||
RMAP_EVENT_ECLIST_ADDED,
|
||||
RMAP_EVENT_ECLIST_DELETED,
|
||||
RMAP_EVENT_LLIST_ADDED,
|
||||
RMAP_EVENT_LLIST_DELETED,
|
||||
RMAP_EVENT_ASLIST_ADDED,
|
||||
RMAP_EVENT_ASLIST_DELETED,
|
||||
RMAP_EVENT_FILTER_ADDED,
|
||||
|
200
lib/thread.c
200
lib/thread.c
@ -41,151 +41,16 @@ DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
|
||||
/* Recent absolute time of day */
|
||||
struct timeval recent_time;
|
||||
/* Relative time, since startup */
|
||||
static struct timeval relative_time;
|
||||
|
||||
static struct hash *cpu_record = NULL;
|
||||
|
||||
/* Adjust so that tv_usec is in the range [0,TIMER_SECOND_MICRO).
|
||||
And change negative values to 0. */
|
||||
static struct timeval
|
||||
timeval_adjust (struct timeval a)
|
||||
{
|
||||
while (a.tv_usec >= TIMER_SECOND_MICRO)
|
||||
{
|
||||
a.tv_usec -= TIMER_SECOND_MICRO;
|
||||
a.tv_sec++;
|
||||
}
|
||||
|
||||
while (a.tv_usec < 0)
|
||||
{
|
||||
a.tv_usec += TIMER_SECOND_MICRO;
|
||||
a.tv_sec--;
|
||||
}
|
||||
|
||||
if (a.tv_sec < 0)
|
||||
/* Change negative timeouts to 0. */
|
||||
a.tv_sec = a.tv_usec = 0;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static struct timeval
|
||||
timeval_subtract (struct timeval a, struct timeval b)
|
||||
{
|
||||
struct timeval ret;
|
||||
|
||||
ret.tv_usec = a.tv_usec - b.tv_usec;
|
||||
ret.tv_sec = a.tv_sec - b.tv_sec;
|
||||
|
||||
return timeval_adjust (ret);
|
||||
}
|
||||
|
||||
static long
|
||||
timeval_cmp (struct timeval a, struct timeval b)
|
||||
{
|
||||
return (a.tv_sec == b.tv_sec
|
||||
? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
|
||||
}
|
||||
|
||||
unsigned long
|
||||
static unsigned long
|
||||
timeval_elapsed (struct timeval a, struct timeval b)
|
||||
{
|
||||
return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
|
||||
+ (a.tv_usec - b.tv_usec));
|
||||
}
|
||||
|
||||
/* gettimeofday wrapper, to keep recent_time updated */
|
||||
static int
|
||||
quagga_gettimeofday (struct timeval *tv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert (tv);
|
||||
|
||||
if (!(ret = gettimeofday (&recent_time, NULL)))
|
||||
{
|
||||
/* avoid copy if user passed recent_time pointer.. */
|
||||
if (tv != &recent_time)
|
||||
*tv = recent_time;
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
quagga_get_relative (struct timeval *tv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef HAVE_CLOCK_MONOTONIC
|
||||
{
|
||||
struct timespec tp;
|
||||
if (!(ret = clock_gettime (CLOCK_MONOTONIC, &tp)))
|
||||
{
|
||||
relative_time.tv_sec = tp.tv_sec;
|
||||
relative_time.tv_usec = tp.tv_nsec / 1000;
|
||||
}
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
{
|
||||
uint64_t ticks;
|
||||
uint64_t useconds;
|
||||
static mach_timebase_info_data_t timebase_info;
|
||||
|
||||
ticks = mach_absolute_time();
|
||||
if (timebase_info.denom == 0)
|
||||
mach_timebase_info(&timebase_info);
|
||||
|
||||
useconds = ticks * timebase_info.numer / timebase_info.denom / 1000;
|
||||
relative_time.tv_sec = useconds / 1000000;
|
||||
relative_time.tv_usec = useconds % 1000000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* !HAVE_CLOCK_MONOTONIC && !__APPLE__ */
|
||||
#error no monotonic clock on this system
|
||||
#endif /* HAVE_CLOCK_MONOTONIC */
|
||||
|
||||
if (tv)
|
||||
*tv = relative_time;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Exported Quagga timestamp function.
|
||||
* Modelled on POSIX clock_gettime.
|
||||
*/
|
||||
int
|
||||
quagga_gettime (enum quagga_clkid clkid, struct timeval *tv)
|
||||
{
|
||||
switch (clkid)
|
||||
{
|
||||
case QUAGGA_CLK_MONOTONIC:
|
||||
return quagga_get_relative (tv);
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
time_t
|
||||
quagga_monotime (void)
|
||||
{
|
||||
struct timeval tv;
|
||||
quagga_get_relative(&tv);
|
||||
return tv.tv_sec;
|
||||
}
|
||||
|
||||
/* Public export of recent_relative_time by value */
|
||||
struct timeval
|
||||
recent_relative_time (void)
|
||||
{
|
||||
return relative_time;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
cpu_record_hash_key (struct cpu_thread_history *a)
|
||||
{
|
||||
@ -437,11 +302,9 @@ thread_timer_cmp(void *a, void *b)
|
||||
struct thread *thread_a = a;
|
||||
struct thread *thread_b = b;
|
||||
|
||||
long cmp = timeval_cmp(thread_a->u.sands, thread_b->u.sands);
|
||||
|
||||
if (cmp < 0)
|
||||
if (timercmp (&thread_a->u.sands, &thread_b->u.sands, <))
|
||||
return -1;
|
||||
if (cmp > 0)
|
||||
if (timercmp (&thread_a->u.sands, &thread_b->u.sands, >))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@ -671,12 +534,8 @@ thread_master_free (struct thread_master *m)
|
||||
unsigned long
|
||||
thread_timer_remain_second (struct thread *thread)
|
||||
{
|
||||
quagga_get_relative (NULL);
|
||||
|
||||
if (thread->u.sands.tv_sec - relative_time.tv_sec > 0)
|
||||
return thread->u.sands.tv_sec - relative_time.tv_sec;
|
||||
else
|
||||
return 0;
|
||||
int64_t remain = monotime_until(&thread->u.sands, NULL) / 1000000LL;
|
||||
return remain < 0 ? 0 : remain;
|
||||
}
|
||||
|
||||
#define debugargdef const char *funcname, const char *schedfrom, int fromln
|
||||
@ -685,9 +544,9 @@ thread_timer_remain_second (struct thread *thread)
|
||||
struct timeval
|
||||
thread_timer_remain(struct thread *thread)
|
||||
{
|
||||
quagga_get_relative(NULL);
|
||||
|
||||
return timeval_subtract(thread->u.sands, relative_time);
|
||||
struct timeval remain;
|
||||
monotime_until(&thread->u.sands, &remain);
|
||||
return remain;
|
||||
}
|
||||
|
||||
/* Get new thread. */
|
||||
@ -887,7 +746,6 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
|
||||
{
|
||||
struct thread *thread;
|
||||
struct pqueue *queue;
|
||||
struct timeval alarm_time;
|
||||
|
||||
assert (m != NULL);
|
||||
|
||||
@ -897,11 +755,8 @@ funcname_thread_add_timer_timeval (struct thread_master *m,
|
||||
queue = ((type == THREAD_TIMER) ? m->timer : m->background);
|
||||
thread = thread_get (m, type, func, arg, debugargpass);
|
||||
|
||||
/* Do we need jitter here? */
|
||||
quagga_get_relative (NULL);
|
||||
alarm_time.tv_sec = relative_time.tv_sec + time_relative->tv_sec;
|
||||
alarm_time.tv_usec = relative_time.tv_usec + time_relative->tv_usec;
|
||||
thread->u.sands = timeval_adjust(alarm_time);
|
||||
monotime(&thread->u.sands);
|
||||
timeradd(&thread->u.sands, time_relative, &thread->u.sands);
|
||||
|
||||
pqueue_enqueue(thread, queue);
|
||||
return thread;
|
||||
@ -1137,7 +992,7 @@ thread_timer_wait (struct pqueue *queue, struct timeval *timer_val)
|
||||
if (queue->size)
|
||||
{
|
||||
struct thread *next_timer = queue->array[0];
|
||||
*timer_val = timeval_subtract (next_timer->u.sands, relative_time);
|
||||
monotime_until(&next_timer->u.sands, timer_val);
|
||||
return timer_val;
|
||||
}
|
||||
return NULL;
|
||||
@ -1265,7 +1120,7 @@ thread_timer_process (struct pqueue *queue, struct timeval *timenow)
|
||||
while (queue->size)
|
||||
{
|
||||
thread = queue->array[0];
|
||||
if (timeval_cmp (*timenow, thread->u.sands) < 0)
|
||||
if (timercmp (timenow, &thread->u.sands, <))
|
||||
return ready;
|
||||
pqueue_dequeue(queue);
|
||||
thread->type = THREAD_READY;
|
||||
@ -1303,6 +1158,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
|
||||
thread_fd_set readfd;
|
||||
thread_fd_set writefd;
|
||||
thread_fd_set exceptfd;
|
||||
struct timeval now;
|
||||
struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
|
||||
struct timeval timer_val_bg;
|
||||
struct timeval *timer_wait = &timer_val;
|
||||
@ -1339,15 +1195,20 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
|
||||
/* Calculate select wait timer if nothing else to do */
|
||||
if (m->ready.count == 0)
|
||||
{
|
||||
quagga_get_relative (NULL);
|
||||
timer_wait = thread_timer_wait (m->timer, &timer_val);
|
||||
timer_wait_bg = thread_timer_wait (m->background, &timer_val_bg);
|
||||
|
||||
if (timer_wait_bg &&
|
||||
(!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
|
||||
(!timer_wait || (timercmp (timer_wait, timer_wait_bg, >))))
|
||||
timer_wait = timer_wait_bg;
|
||||
}
|
||||
|
||||
if (timer_wait && timer_wait->tv_sec < 0)
|
||||
{
|
||||
timerclear(&timer_val);
|
||||
timer_wait = &timer_val;
|
||||
}
|
||||
|
||||
num = fd_select (m, FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
|
||||
|
||||
/* Signals should get quick treatment */
|
||||
@ -1362,8 +1223,8 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
|
||||
/* Check foreground timers. Historically, they have had higher
|
||||
priority than I/O threads, so let's push them onto the ready
|
||||
list in front of the I/O threads. */
|
||||
quagga_get_relative (NULL);
|
||||
thread_timer_process (m->timer, &relative_time);
|
||||
monotime(&now);
|
||||
thread_timer_process (m->timer, &now);
|
||||
|
||||
/* Got IO, process it */
|
||||
if (num > 0)
|
||||
@ -1379,7 +1240,7 @@ thread_fetch (struct thread_master *m, struct thread *fetch)
|
||||
#endif
|
||||
|
||||
/* Background timer/events, lowest priority */
|
||||
thread_timer_process (m->background, &relative_time);
|
||||
thread_timer_process (m->background, &now);
|
||||
|
||||
if ((thread = thread_trim_head (&m->ready)) != NULL)
|
||||
return thread_run (m, thread, fetch);
|
||||
@ -1408,9 +1269,7 @@ thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime)
|
||||
int
|
||||
thread_should_yield (struct thread *thread)
|
||||
{
|
||||
quagga_get_relative (NULL);
|
||||
return (timeval_elapsed(relative_time, thread->real) >
|
||||
thread->yield);
|
||||
return monotime_since(&thread->real, NULL) > (int64_t)thread->yield;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1422,17 +1281,8 @@ thread_set_yield_time (struct thread *thread, unsigned long yield_time)
|
||||
void
|
||||
thread_getrusage (RUSAGE_T *r)
|
||||
{
|
||||
quagga_get_relative (NULL);
|
||||
monotime(&r->real);
|
||||
getrusage(RUSAGE_SELF, &(r->cpu));
|
||||
r->real = relative_time;
|
||||
|
||||
#ifdef HAVE_CLOCK_MONOTONIC
|
||||
/* quagga_get_relative() only updates recent_time if gettimeofday
|
||||
* based, not when using CLOCK_MONOTONIC. As we export recent_time
|
||||
* and guarantee to update it before threads are run...
|
||||
*/
|
||||
quagga_gettimeofday(&recent_time);
|
||||
#endif /* HAVE_CLOCK_MONOTONIC */
|
||||
}
|
||||
|
||||
struct thread *thread_current = NULL;
|
||||
|
11
lib/thread.h
11
lib/thread.h
@ -23,6 +23,7 @@
|
||||
#define _ZEBRA_THREAD_H
|
||||
|
||||
#include <zebra.h>
|
||||
#include "monotime.h"
|
||||
|
||||
struct rusage_t
|
||||
{
|
||||
@ -239,7 +240,6 @@ extern void thread_call (struct thread *);
|
||||
extern unsigned long thread_timer_remain_second (struct thread *);
|
||||
extern struct timeval thread_timer_remain(struct thread*);
|
||||
extern int thread_should_yield (struct thread *);
|
||||
extern unsigned long timeval_elapsed (struct timeval a, struct timeval b);
|
||||
/* set yield time for thread */
|
||||
extern void thread_set_yield_time (struct thread *, unsigned long);
|
||||
|
||||
@ -247,13 +247,6 @@ extern void thread_set_yield_time (struct thread *, unsigned long);
|
||||
extern void thread_getrusage (RUSAGE_T *);
|
||||
extern void thread_cmd_init (void);
|
||||
|
||||
/* replacements for the system gettimeofday(), clock_gettime() and
|
||||
* time() functions, providing support for non-decrementing clock on
|
||||
* all systems, and fully monotonic on /some/ systems.
|
||||
*/
|
||||
extern int quagga_gettime (enum quagga_clkid, struct timeval *);
|
||||
extern time_t quagga_monotime (void);
|
||||
|
||||
/* Returns elapsed real (wall clock) time. */
|
||||
extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
|
||||
unsigned long *cpu_time_elapsed);
|
||||
@ -262,8 +255,6 @@ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
|
||||
be used instead of calling gettimeofday if a recent value is sufficient.
|
||||
This is guaranteed to be refreshed before a thread is called. */
|
||||
extern struct timeval recent_time;
|
||||
/* Similar to recent_time, but a monotonically increasing time value */
|
||||
extern struct timeval recent_relative_time (void);
|
||||
|
||||
/* only for use in logging functions! */
|
||||
extern struct thread *thread_current;
|
||||
|
@ -34,6 +34,7 @@
|
||||
/* The default VRF ID */
|
||||
#define VRF_DEFAULT 0
|
||||
#define VRF_UNKNOWN UINT16_MAX
|
||||
#define VRF_ALL UINT16_MAX - 1
|
||||
|
||||
/* Pending: May need to refine this. */
|
||||
#ifndef IFLA_VRF_MAX
|
||||
|
@ -742,6 +742,7 @@ vty_end_config (struct vty *vty)
|
||||
case BGP_VPNV6_NODE:
|
||||
case BGP_ENCAP_NODE:
|
||||
case BGP_ENCAPV6_NODE:
|
||||
case BGP_VRF_POLICY_NODE:
|
||||
case BGP_VNC_DEFAULTS_NODE:
|
||||
case BGP_VNC_NVE_GROUP_NODE:
|
||||
case BGP_VNC_L2_GROUP_NODE:
|
||||
|
@ -1626,6 +1626,7 @@ zclient_read (struct thread *thread)
|
||||
case ZEBRA_REDISTRIBUTE_IPV6_DEL:
|
||||
if (zclient->redistribute_route_ipv6_del)
|
||||
(*zclient->redistribute_route_ipv6_del) (command, zclient, length, vrf_id);
|
||||
break;
|
||||
case ZEBRA_INTERFACE_LINK_PARAMS:
|
||||
if (zclient->interface_link_params)
|
||||
(*zclient->interface_link_params) (command, zclient, length);
|
||||
|
25
lib/zebra.h
25
lib/zebra.h
@ -405,6 +405,7 @@ typedef enum {
|
||||
ZEBRA_IPV4_NEXTHOP_DELETE,
|
||||
ZEBRA_IPV6_NEXTHOP_ADD,
|
||||
ZEBRA_IPV6_NEXTHOP_DELETE,
|
||||
ZEBRA_IPMR_ROUTE_STATS,
|
||||
} zebra_message_types_t;
|
||||
|
||||
/* Marker value used in new Zserv, in the byte location corresponding
|
||||
@ -477,6 +478,12 @@ typedef enum {
|
||||
#define SAFI_RESERVED_5 5
|
||||
#define SAFI_MAX 6
|
||||
|
||||
#define IANA_SAFI_RESERVED 0
|
||||
#define IANA_SAFI_UNICAST 1
|
||||
#define IANA_SAFI_MULTICAST 2
|
||||
#define IANA_SAFI_ENCAP 7
|
||||
#define IANA_SAFI_MPLS_VPN 128
|
||||
|
||||
/*
|
||||
* The above AFI and SAFI definitions are for internal use. The protocol
|
||||
* definitions (IANA values) as for example used in BGP protocol packets
|
||||
@ -486,12 +493,14 @@ typedef enum {
|
||||
* not optimal for use in data-structure sizing.
|
||||
* Note: Only useful (i.e., supported) values are defined below.
|
||||
*/
|
||||
#define IANA_AFI_RESERVED 0
|
||||
#define IANA_AFI_IPV4 1
|
||||
#define IANA_AFI_IPV6 2
|
||||
#define IANA_AFI_L2VPN 25
|
||||
#define IANA_AFI_IPMR 128
|
||||
#define IANA_AFI_IP6MR 129
|
||||
typedef enum {
|
||||
IANA_AFI_RESERVED = 0,
|
||||
IANA_AFI_IPV4 = 1,
|
||||
IANA_AFI_IPV6 = 2,
|
||||
IANA_AFI_L2VPN = 25,
|
||||
IANA_AFI_IPMR = 128,
|
||||
IANA_AFI_IP6MR = 129
|
||||
} iana_afi_t;
|
||||
|
||||
#define IANA_SAFI_RESERVED 0
|
||||
#define IANA_SAFI_UNICAST 1
|
||||
@ -531,7 +540,7 @@ typedef uint32_t route_tag_t;
|
||||
#define ROUTE_TAG_MAX UINT32_MAX
|
||||
#define ROUTE_TAG_PRI PRIu32
|
||||
|
||||
static inline afi_t afi_iana2int (afi_t afi)
|
||||
static inline afi_t afi_iana2int (iana_afi_t afi)
|
||||
{
|
||||
if (afi == IANA_AFI_IPV4)
|
||||
return AFI_IP;
|
||||
@ -540,7 +549,7 @@ static inline afi_t afi_iana2int (afi_t afi)
|
||||
return AFI_MAX;
|
||||
}
|
||||
|
||||
static inline afi_t afi_int2iana (afi_t afi)
|
||||
static inline iana_afi_t afi_int2iana (afi_t afi)
|
||||
{
|
||||
if (afi == AFI_IP)
|
||||
return IANA_AFI_IPV4;
|
||||
|
@ -433,7 +433,7 @@ ospf6_abr_originate_summary_to_area (struct ospf6_route *route,
|
||||
else
|
||||
{
|
||||
summary->type = route->type;
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &summary->changed);
|
||||
monotime(&summary->changed);
|
||||
}
|
||||
|
||||
summary->path.router_bits = route->path.router_bits;
|
||||
|
@ -388,7 +388,7 @@ ospf6_area_show (struct vty *vty, struct ospf6_area *oa)
|
||||
|
||||
if (oa->ts_spf.tv_sec || oa->ts_spf.tv_usec)
|
||||
{
|
||||
result = timeval_elapsed (recent_relative_time (), oa->ts_spf);
|
||||
result = monotime_since(&oa->ts_spf, NULL);
|
||||
if (result/TIMER_SECOND_MICRO > 0)
|
||||
{
|
||||
vty_out (vty, "SPF last executed %ld.%lds ago%s",
|
||||
|
@ -245,7 +245,7 @@ ospf6_bfd_interface_dest_update (int command, struct zclient *zclient,
|
||||
|
||||
old_status = bfd_info->status;
|
||||
bfd_info->status = status;
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv);
|
||||
monotime(&tv);
|
||||
bfd_info->last_update = tv.tv_sec;
|
||||
|
||||
if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP))
|
||||
|
@ -224,7 +224,7 @@ ospf6_install_lsa (struct ospf6_lsa *lsa)
|
||||
ospf6_flood_clear (old);
|
||||
}
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
monotime(&now);
|
||||
if (! OSPF6_LSA_IS_MAXAGE (lsa))
|
||||
lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa,
|
||||
OSPF_LSA_MAXAGE + lsa->birth.tv_sec - now.tv_sec);
|
||||
@ -862,7 +862,7 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
|
||||
if (old)
|
||||
{
|
||||
struct timeval now, res;
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
monotime(&now);
|
||||
timersub (&now, &old->installed, &res);
|
||||
time_delta_ms = (res.tv_sec * 1000) + (int)(res.tv_usec/1000);
|
||||
if (time_delta_ms < from->ospf6_if->area->ospf6->lsa_minarrival)
|
||||
@ -875,7 +875,7 @@ ospf6_receive_lsa (struct ospf6_neighbor *from,
|
||||
}
|
||||
}
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &new->received);
|
||||
monotime(&new->received);
|
||||
|
||||
if (is_debug)
|
||||
zlog_debug ("Install, Flood, Possibly acknowledge the received LSA");
|
||||
|
@ -961,7 +961,7 @@ ospf6_interface_show (struct vty *vty, struct interface *ifp)
|
||||
vty_out (vty, " Number of I/F scoped LSAs is %u%s",
|
||||
oi->lsdb->count, VNL);
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
monotime(&now);
|
||||
|
||||
timerclear (&res);
|
||||
if (oi->thread_send_lsupdate)
|
||||
|
@ -1485,11 +1485,11 @@ ospf6_brouter_debug_print (struct ospf6_route *brouter)
|
||||
ospf6_linkstate_prefix2str (&brouter->prefix, destination,
|
||||
sizeof (destination));
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
monotime(&now);
|
||||
timersub (&now, &brouter->installed, &res);
|
||||
timerstring (&res, installed, sizeof (installed));
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
monotime(&now);
|
||||
timersub (&now, &brouter->changed, &res);
|
||||
timerstring (&res, changed, sizeof (changed));
|
||||
|
||||
|
@ -207,9 +207,7 @@ ospf6_lsa_age_set (struct ospf6_lsa *lsa)
|
||||
|
||||
assert (lsa && lsa->header);
|
||||
|
||||
if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &now) < 0)
|
||||
zlog_warn ("LSA: quagga_gettime failed, may fail LSA AGEs: %s",
|
||||
safe_strerror (errno));
|
||||
monotime(&now);
|
||||
|
||||
lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age);
|
||||
lsa->birth.tv_usec = now.tv_usec;
|
||||
@ -230,9 +228,7 @@ ospf6_lsa_age_current (struct ospf6_lsa *lsa)
|
||||
assert (lsa->header);
|
||||
|
||||
/* current time */
|
||||
if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &now) < 0)
|
||||
zlog_warn ("LSA: quagga_gettime failed, may fail LSA AGEs: %s",
|
||||
safe_strerror (errno));
|
||||
monotime(&now);
|
||||
|
||||
if (ntohs (lsa->header->age) >= OSPF_LSA_MAXAGE)
|
||||
{
|
||||
@ -513,7 +509,7 @@ ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
|
||||
inet_ntop (AF_INET, &lsa->header->adv_router,
|
||||
adv_router, sizeof (adv_router));
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
monotime(&now);
|
||||
timersub (&now, &lsa->installed, &res);
|
||||
timerstring (&res, duration, sizeof (duration));
|
||||
|
||||
|
@ -1817,10 +1817,7 @@ ospf6_dbdesc_send (struct thread *thread)
|
||||
if (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT) &&
|
||||
(on->dbdesc_seqnum == 0))
|
||||
{
|
||||
struct timeval tv;
|
||||
if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv) < 0)
|
||||
tv.tv_sec = 1;
|
||||
on->dbdesc_seqnum = tv.tv_sec;
|
||||
on->dbdesc_seqnum = monotime(NULL);
|
||||
}
|
||||
|
||||
dbdesc->options[0] = on->ospf6_if->area->options[0];
|
||||
|
@ -97,7 +97,7 @@ ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *oi)
|
||||
on->ospf6_if = oi;
|
||||
on->state = OSPF6_NEIGHBOR_DOWN;
|
||||
on->state_change = 0;
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &on->last_changed);
|
||||
monotime(&on->last_changed);
|
||||
on->router_id = router_id;
|
||||
|
||||
on->summary_list = ospf6_lsdb_create (on);
|
||||
@ -163,7 +163,7 @@ ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on, int e
|
||||
return;
|
||||
|
||||
on->state_change++;
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &on->last_changed);
|
||||
monotime(&on->last_changed);
|
||||
|
||||
/* log */
|
||||
if (IS_OSPF6_DEBUG_NEIGHBOR (STATE))
|
||||
@ -633,7 +633,7 @@ ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *on)
|
||||
{
|
||||
char router_id[16];
|
||||
char duration[16];
|
||||
struct timeval now, res;
|
||||
struct timeval res;
|
||||
char nstate[16];
|
||||
char deadtime[16];
|
||||
long h, m, s;
|
||||
@ -645,13 +645,11 @@ ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *on)
|
||||
}
|
||||
#endif /*HAVE_GETNAMEINFO*/
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
|
||||
/* Dead time */
|
||||
h = m = s = 0;
|
||||
if (on->inactivity_timer)
|
||||
{
|
||||
s = on->inactivity_timer->u.sands.tv_sec - recent_relative_time().tv_sec;
|
||||
s = monotime_until(&on->inactivity_timer->u.sands, NULL) / 1000000LL;
|
||||
h = s / 3600;
|
||||
s -= h * 3600;
|
||||
m = s / 60;
|
||||
@ -673,7 +671,7 @@ ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *on)
|
||||
}
|
||||
|
||||
/* Duration */
|
||||
timersub (&now, &on->last_changed, &res);
|
||||
monotime_since(&on->last_changed, &res);
|
||||
timerstring (&res, duration, sizeof (duration));
|
||||
|
||||
/*
|
||||
@ -707,7 +705,7 @@ ospf6_neighbor_show_drchoice (struct vty *vty, struct ospf6_neighbor *on)
|
||||
inet_ntop (AF_INET, &on->drouter, drouter, sizeof (drouter));
|
||||
inet_ntop (AF_INET, &on->bdrouter, bdrouter, sizeof (bdrouter));
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
monotime(&now);
|
||||
timersub (&now, &on->last_changed, &res);
|
||||
timerstring (&res, duration, sizeof (duration));
|
||||
|
||||
@ -731,7 +729,7 @@ ospf6_neighbor_show_detail (struct vty *vty, struct ospf6_neighbor *on)
|
||||
inet_ntop (AF_INET, &on->drouter, drouter, sizeof (drouter));
|
||||
inet_ntop (AF_INET, &on->bdrouter, bdrouter, sizeof (bdrouter));
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
monotime(&now);
|
||||
timersub (&now, &on->last_changed, &res);
|
||||
timerstring (&res, duration, sizeof (duration));
|
||||
|
||||
|
@ -600,7 +600,7 @@ ospf6_route_add (struct ospf6_route *route,
|
||||
else if (IS_OSPF6_DEBUG_ROUTE (TABLE))
|
||||
zlog_debug ("%s: route add: %s", ospf6_route_table_name (table), buf);
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
monotime(&now);
|
||||
|
||||
node = route_node_get (table->table, &route->prefix);
|
||||
route->rnode = node;
|
||||
@ -1020,7 +1020,7 @@ ospf6_route_show (struct vty *vty, struct ospf6_route *route)
|
||||
struct listnode *node;
|
||||
struct ospf6_nexthop *nh;
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
monotime(&now);
|
||||
timersub (&now, &route->changed, &res);
|
||||
timerstring (&res, duration, sizeof (duration));
|
||||
|
||||
@ -1068,7 +1068,7 @@ ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
|
||||
struct listnode *node;
|
||||
struct ospf6_nexthop *nh;
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
monotime(&now);
|
||||
|
||||
/* destination */
|
||||
if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
|
||||
|
@ -603,7 +603,7 @@ ospf6_spf_calculation_thread (struct thread *t)
|
||||
ospf6->t_spf_calc = NULL;
|
||||
|
||||
/* execute SPF calculation */
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &start);
|
||||
monotime(&start);
|
||||
|
||||
if (ospf6_is_router_abr (ospf6))
|
||||
ospf6_abr_range_reset_cost (ospf6);
|
||||
@ -644,7 +644,7 @@ ospf6_spf_calculation_thread (struct thread *t)
|
||||
if (ospf6_is_router_abr (ospf6))
|
||||
ospf6_abr_defaults_to_stub (ospf6);
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &end);
|
||||
monotime(&end);
|
||||
timersub (&end, &start, &runtime);
|
||||
|
||||
ospf6->ts_spf_duration = runtime;
|
||||
@ -670,7 +670,6 @@ void
|
||||
ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason)
|
||||
{
|
||||
unsigned long delay, elapsed, ht;
|
||||
struct timeval now, result;
|
||||
|
||||
ospf6_set_spf_reason(ospf6, reason);
|
||||
|
||||
@ -694,11 +693,7 @@ ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason)
|
||||
return;
|
||||
}
|
||||
|
||||
/* XXX Monotic timers: we only care about relative time here. */
|
||||
now = recent_relative_time ();
|
||||
timersub (&now, &ospf6->ts_spf, &result);
|
||||
|
||||
elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
|
||||
elapsed = monotime_since(&ospf6->ts_spf, NULL) / 1000LL;
|
||||
ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier;
|
||||
|
||||
if (ht > ospf6->spf_max_holdtime)
|
||||
|
@ -124,7 +124,7 @@ ospf6_create (void)
|
||||
o = XCALLOC (MTYPE_OSPF6_TOP, sizeof (struct ospf6));
|
||||
|
||||
/* initialize */
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &o->starttime);
|
||||
monotime(&o->starttime);
|
||||
o->area_list = list_new ();
|
||||
o->area_list->cmp = ospf6_area_cmp;
|
||||
o->lsdb = ospf6_lsdb_create (o);
|
||||
@ -891,7 +891,7 @@ ospf6_show (struct vty *vty, struct ospf6 *o)
|
||||
router_id, VNL);
|
||||
|
||||
/* running time */
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
monotime(&now);
|
||||
timersub (&now, &o->starttime, &running);
|
||||
timerstring (&running, duration, sizeof (duration));
|
||||
vty_out (vty, " Running %s%s", duration, VNL);
|
||||
|
@ -58,21 +58,6 @@ extern struct thread_master *master;
|
||||
#define OSPF6_NEIGHBOR(x) ((struct ospf6_neighbor *) (x))
|
||||
|
||||
/* operation on timeval structure */
|
||||
#ifndef timerclear
|
||||
#define timerclear(a) (a)->tv_sec = (tvp)->tv_usec = 0
|
||||
#endif /*timerclear*/
|
||||
#ifndef timersub
|
||||
#define timersub(a, b, res) \
|
||||
do { \
|
||||
(res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
|
||||
(res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
|
||||
if ((res)->tv_usec < 0) \
|
||||
{ \
|
||||
(res)->tv_sec--; \
|
||||
(res)->tv_usec += 1000000; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif /*timersub*/
|
||||
#define timerstring(tv, buf, size) \
|
||||
do { \
|
||||
if ((tv)->tv_sec / 60 / 60 / 24) \
|
||||
@ -87,15 +72,6 @@ extern struct thread_master *master;
|
||||
(tv)->tv_sec / 60LL % 60, \
|
||||
(tv)->tv_sec % 60LL); \
|
||||
} while (0)
|
||||
#define timerstring_local(tv, buf, size) \
|
||||
do { \
|
||||
int ret; \
|
||||
struct tm *tm; \
|
||||
tm = localtime (&(tv)->tv_sec); \
|
||||
ret = strftime (buf, size, "%Y/%m/%d %H:%M:%S", tm); \
|
||||
if (ret == 0) \
|
||||
zlog_warn ("strftime error"); \
|
||||
} while (0)
|
||||
|
||||
#define threadtimer_string(now, t, buf, size) \
|
||||
do { \
|
||||
|
@ -649,7 +649,7 @@ ospf_ase_calculate_timer (struct thread *t)
|
||||
{
|
||||
ospf->ase_calc = 0;
|
||||
|
||||
quagga_gettime(QUAGGA_CLK_MONOTONIC, &start_time);
|
||||
monotime(&start_time);
|
||||
|
||||
/* Calculate external route for each AS-external-LSA */
|
||||
LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa)
|
||||
@ -681,7 +681,7 @@ ospf_ase_calculate_timer (struct thread *t)
|
||||
ospf->old_external_route = ospf->new_external_route;
|
||||
ospf->new_external_route = route_table_init ();
|
||||
|
||||
quagga_gettime(QUAGGA_CLK_MONOTONIC, &stop_time);
|
||||
monotime(&stop_time);
|
||||
|
||||
zlog_info ("SPF Processing Time(usecs): External Routes: %lld\n",
|
||||
(stop_time.tv_sec - start_time.tv_sec)*1000000LL+
|
||||
|
@ -249,7 +249,7 @@ ospf_bfd_interface_dest_update (int command, struct zclient *zclient,
|
||||
|
||||
old_status = bfd_info->status;
|
||||
bfd_info->status = status;
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv);
|
||||
monotime(&tv);
|
||||
bfd_info->last_update = tv.tv_sec;
|
||||
|
||||
if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP))
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "monotime.h"
|
||||
#include "linklist.h"
|
||||
#include "thread.h"
|
||||
#include "prefix.h"
|
||||
@ -317,8 +318,8 @@ ospf_timer_dump (struct thread *t, char *buf, size_t size)
|
||||
struct timeval result;
|
||||
if (!t)
|
||||
return "inactive";
|
||||
|
||||
result = tv_sub (t->u.sands, recent_relative_time());
|
||||
|
||||
monotime_until (&t->u.sands, &result);
|
||||
return ospf_timeval_dump (&result, buf, size);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "monotime.h"
|
||||
#include "linklist.h"
|
||||
#include "prefix.h"
|
||||
#include "if.h"
|
||||
@ -277,8 +278,8 @@ ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr,
|
||||
"while local one is initial instance.");
|
||||
; /* Accept this LSA for quick LSDB resynchronization. */
|
||||
}
|
||||
else if (tv_cmp (tv_sub (recent_relative_time (), current->tv_recv),
|
||||
msec2tv (ospf->min_ls_arrival)) < 0)
|
||||
else if (monotime_since (¤t->tv_recv, NULL)
|
||||
< ospf->min_ls_arrival * 1000LL)
|
||||
{
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug ("LSA[Flooding]: LSA is received recently.");
|
||||
@ -969,7 +970,7 @@ ospf_lsa_flush_area (struct ospf_lsa *lsa, struct ospf_area *area)
|
||||
more time for the ACK to be received and avoid
|
||||
retransmissions */
|
||||
lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
|
||||
lsa->tv_recv = recent_relative_time ();
|
||||
monotime(&lsa->tv_recv);
|
||||
lsa->tv_orig = lsa->tv_recv;
|
||||
ospf_flood_through_area (area, NULL, lsa);
|
||||
ospf_lsa_maxage (area->ospf, lsa);
|
||||
@ -982,7 +983,7 @@ ospf_lsa_flush_as (struct ospf *ospf, struct ospf_lsa *lsa)
|
||||
more time for the ACK to be received and avoid
|
||||
retransmissions */
|
||||
lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
|
||||
lsa->tv_recv = recent_relative_time ();
|
||||
monotime(&lsa->tv_recv);
|
||||
lsa->tv_orig = lsa->tv_recv;
|
||||
ospf_flood_through_as (ospf, NULL, lsa);
|
||||
ospf_lsa_maxage (ospf, lsa);
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "monotime.h"
|
||||
#include "linklist.h"
|
||||
#include "prefix.h"
|
||||
#include "if.h"
|
||||
@ -62,40 +63,6 @@ get_metric (u_char *metric)
|
||||
}
|
||||
|
||||
|
||||
struct timeval
|
||||
tv_adjust (struct timeval a)
|
||||
{
|
||||
while (a.tv_usec >= 1000000)
|
||||
{
|
||||
a.tv_usec -= 1000000;
|
||||
a.tv_sec++;
|
||||
}
|
||||
|
||||
while (a.tv_usec < 0)
|
||||
{
|
||||
a.tv_usec += 1000000;
|
||||
a.tv_sec--;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
int
|
||||
tv_ceil (struct timeval a)
|
||||
{
|
||||
a = tv_adjust (a);
|
||||
|
||||
return (a.tv_usec ? a.tv_sec + 1 : a.tv_sec);
|
||||
}
|
||||
|
||||
int
|
||||
tv_floor (struct timeval a)
|
||||
{
|
||||
a = tv_adjust (a);
|
||||
|
||||
return a.tv_sec;
|
||||
}
|
||||
|
||||
struct timeval
|
||||
int2tv (int a)
|
||||
{
|
||||
@ -115,50 +82,22 @@ msec2tv (int a)
|
||||
ret.tv_sec = a/1000;
|
||||
ret.tv_usec = (a%1000) * 1000;
|
||||
|
||||
return tv_adjust (ret);
|
||||
}
|
||||
|
||||
struct timeval
|
||||
tv_add (struct timeval a, struct timeval b)
|
||||
{
|
||||
struct timeval ret;
|
||||
|
||||
ret.tv_sec = a.tv_sec + b.tv_sec;
|
||||
ret.tv_usec = a.tv_usec + b.tv_usec;
|
||||
|
||||
return tv_adjust (ret);
|
||||
}
|
||||
|
||||
struct timeval
|
||||
tv_sub (struct timeval a, struct timeval b)
|
||||
{
|
||||
struct timeval ret;
|
||||
|
||||
ret.tv_sec = a.tv_sec - b.tv_sec;
|
||||
ret.tv_usec = a.tv_usec - b.tv_usec;
|
||||
|
||||
return tv_adjust (ret);
|
||||
}
|
||||
|
||||
int
|
||||
tv_cmp (struct timeval a, struct timeval b)
|
||||
{
|
||||
return (a.tv_sec == b.tv_sec ?
|
||||
a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ospf_lsa_refresh_delay (struct ospf_lsa *lsa)
|
||||
{
|
||||
struct timeval delta, now;
|
||||
struct timeval delta;
|
||||
int delay = 0;
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
delta = tv_sub (now, lsa->tv_orig);
|
||||
|
||||
if (tv_cmp (delta, msec2tv (OSPF_MIN_LS_INTERVAL)) < 0)
|
||||
if (monotime_since (&lsa->tv_orig, &delta) < OSPF_MIN_LS_INTERVAL * 1000LL)
|
||||
{
|
||||
delay = tv_ceil (tv_sub (msec2tv (OSPF_MIN_LS_INTERVAL), delta));
|
||||
struct timeval minv = msec2tv (OSPF_MIN_LS_INTERVAL);
|
||||
timersub (&minv, &delta, &minv);
|
||||
|
||||
/* TBD: remove padding to full sec, return timeval instead */
|
||||
delay = minv.tv_sec + !!minv.tv_usec;
|
||||
|
||||
if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
|
||||
zlog_debug ("LSA[Type%d:%s]: Refresh timer delay %d seconds",
|
||||
@ -174,12 +113,10 @@ ospf_lsa_refresh_delay (struct ospf_lsa *lsa)
|
||||
int
|
||||
get_age (struct ospf_lsa *lsa)
|
||||
{
|
||||
int age;
|
||||
struct timeval rel;
|
||||
|
||||
age = ntohs (lsa->data->ls_age)
|
||||
+ tv_floor (tv_sub (recent_relative_time (), lsa->tv_recv));
|
||||
|
||||
return age;
|
||||
monotime_since (&lsa->tv_recv, &rel);
|
||||
return ntohs (lsa->data->ls_age) + rel.tv_sec;
|
||||
}
|
||||
|
||||
|
||||
@ -228,7 +165,7 @@ ospf_lsa_new ()
|
||||
new->flags = 0;
|
||||
new->lock = 1;
|
||||
new->retransmit_counter = 0;
|
||||
new->tv_recv = recent_relative_time ();
|
||||
monotime(&new->tv_recv);
|
||||
new->tv_orig = new->tv_recv;
|
||||
new->refresh_list = -1;
|
||||
|
||||
@ -3701,8 +3638,8 @@ ospf_refresher_register_lsa (struct ospf *ospf, struct ospf_lsa *lsa)
|
||||
*/
|
||||
delay = (random() % (max_delay - min_delay)) + min_delay;
|
||||
|
||||
current_index = ospf->lsa_refresh_queue.index + (quagga_monotime ()
|
||||
- ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY;
|
||||
current_index = ospf->lsa_refresh_queue.index + (monotime(NULL)
|
||||
- ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY;
|
||||
|
||||
index = (current_index + delay/OSPF_LSA_REFRESHER_GRANULARITY)
|
||||
% (OSPF_LSA_REFRESHER_SLOTS);
|
||||
@ -3765,7 +3702,7 @@ ospf_lsa_refresh_walker (struct thread *t)
|
||||
modulus. */
|
||||
ospf->lsa_refresh_queue.index =
|
||||
((unsigned long)(ospf->lsa_refresh_queue.index +
|
||||
(quagga_monotime () - ospf->lsa_refresher_started)
|
||||
(monotime(NULL) - ospf->lsa_refresher_started)
|
||||
/ OSPF_LSA_REFRESHER_GRANULARITY))
|
||||
% OSPF_LSA_REFRESHER_SLOTS;
|
||||
|
||||
@ -3806,7 +3743,7 @@ ospf_lsa_refresh_walker (struct thread *t)
|
||||
|
||||
ospf->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker,
|
||||
ospf, ospf->lsa_refresh_interval);
|
||||
ospf->lsa_refresher_started = quagga_monotime ();
|
||||
ospf->lsa_refresher_started = monotime(NULL);
|
||||
|
||||
for (ALL_LIST_ELEMENTS (lsa_to_refresh, node, nnode, lsa))
|
||||
{
|
||||
|
@ -227,14 +227,8 @@ struct as_external_lsa
|
||||
|
||||
/* Prototypes. */
|
||||
/* XXX: Eek, time functions, similar are in lib/thread.c */
|
||||
extern struct timeval tv_adjust (struct timeval);
|
||||
extern int tv_ceil (struct timeval);
|
||||
extern int tv_floor (struct timeval);
|
||||
extern struct timeval int2tv (int);
|
||||
extern struct timeval msec2tv (int);
|
||||
extern struct timeval tv_add (struct timeval, struct timeval);
|
||||
extern struct timeval tv_sub (struct timeval, struct timeval);
|
||||
extern int tv_cmp (struct timeval, struct timeval);
|
||||
|
||||
extern int get_age (struct ospf_lsa *);
|
||||
extern u_int16_t ospf_lsa_checksum (struct lsa_header *);
|
||||
|
@ -630,10 +630,10 @@ nsm_notice_state_change (struct ospf_neighbor *nbr, int next_state, int event)
|
||||
|
||||
/* Advance in NSM */
|
||||
if (next_state > nbr->state)
|
||||
nbr->ts_last_progress = recent_relative_time ();
|
||||
monotime(&nbr->ts_last_progress);
|
||||
else /* regression in NSM */
|
||||
{
|
||||
nbr->ts_last_regress = recent_relative_time ();
|
||||
monotime(&nbr->ts_last_regress);
|
||||
nbr->last_regress_str = ospf_nsm_event_str [event];
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "monotime.h"
|
||||
#include "thread.h"
|
||||
#include "memory.h"
|
||||
#include "linklist.h"
|
||||
@ -521,16 +522,18 @@ ospf_ls_upd_timer (struct thread *thread)
|
||||
struct ospf_lsa *lsa;
|
||||
|
||||
if ((lsa = rn->info) != NULL)
|
||||
/* Don't retransmit an LSA if we received it within
|
||||
the last RxmtInterval seconds - this is to allow the
|
||||
neighbour a chance to acknowledge the LSA as it may
|
||||
have ben just received before the retransmit timer
|
||||
fired. This is a small tweak to what is in the RFC,
|
||||
but it will cut out out a lot of retransmit traffic
|
||||
- MAG */
|
||||
if (tv_cmp (tv_sub (recent_relative_time (), lsa->tv_recv),
|
||||
int2tv (retransmit_interval)) >= 0)
|
||||
listnode_add (update, rn->info);
|
||||
{
|
||||
/* Don't retransmit an LSA if we received it within
|
||||
the last RxmtInterval seconds - this is to allow the
|
||||
neighbour a chance to acknowledge the LSA as it may
|
||||
have ben just received before the retransmit timer
|
||||
fired. This is a small tweak to what is in the RFC,
|
||||
but it will cut out out a lot of retransmit traffic
|
||||
- MAG */
|
||||
if (monotime_since (&lsa->tv_recv, NULL)
|
||||
>= retransmit_interval * 1000000LL)
|
||||
listnode_add (update, rn->info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1469,10 +1472,8 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
|
||||
}
|
||||
else
|
||||
{
|
||||
struct timeval t, now;
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
t = tv_sub (now, nbr->last_send_ts);
|
||||
if (tv_cmp (t, int2tv (nbr->v_inactivity)) < 0)
|
||||
if (monotime_since (&nbr->last_send_ts, NULL)
|
||||
< nbr->v_inactivity * 1000000LL)
|
||||
{
|
||||
/* In states Loading and Full the slave must resend
|
||||
its last Database Description packet in response to
|
||||
@ -2074,12 +2075,8 @@ ospf_ls_upd (struct ospf *ospf, struct ip *iph, struct ospf_header *ospfh,
|
||||
recent) LSA instance. */
|
||||
else
|
||||
{
|
||||
struct timeval now;
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
|
||||
|
||||
if (tv_cmp (tv_sub (now, current->tv_orig),
|
||||
msec2tv (ospf->min_ls_arrival)) >= 0)
|
||||
if (monotime_since (¤t->tv_orig, NULL)
|
||||
>= ospf->min_ls_arrival * 1000LL)
|
||||
/* Trap NSSA type later.*/
|
||||
ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT);
|
||||
DISCARD_LSA (lsa, 8);
|
||||
@ -3577,7 +3574,7 @@ ospf_db_desc_send (struct ospf_neighbor *nbr)
|
||||
if (nbr->last_send)
|
||||
ospf_packet_free (nbr->last_send);
|
||||
nbr->last_send = ospf_packet_dup (op);
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &nbr->last_send_ts);
|
||||
monotime(&nbr->last_send_ts);
|
||||
}
|
||||
|
||||
/* Re-send Database Description. */
|
||||
|
@ -20,6 +20,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "monotime.h"
|
||||
#include "thread.h"
|
||||
#include "memory.h"
|
||||
#include "hash.h"
|
||||
@ -1279,7 +1280,7 @@ ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table,
|
||||
/* Increment SPF Calculation Counter. */
|
||||
area->spf_calculation++;
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf);
|
||||
monotime(&area->ospf->ts_spf);
|
||||
area->ts_spf = area->ospf->ts_spf;
|
||||
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
@ -1300,7 +1301,7 @@ ospf_spf_calculate_timer (struct thread *thread)
|
||||
struct route_table *new_table, *new_rtrs;
|
||||
struct ospf_area *area;
|
||||
struct listnode *node, *nnode;
|
||||
struct timeval start_time, stop_time, spf_start_time;
|
||||
struct timeval start_time, spf_start_time;
|
||||
int areas_processed = 0;
|
||||
unsigned long ia_time, prune_time, rt_time;
|
||||
unsigned long abr_time, total_spf_time, spf_time;
|
||||
@ -1311,7 +1312,7 @@ ospf_spf_calculate_timer (struct thread *thread)
|
||||
|
||||
ospf->t_spf_calc = NULL;
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &spf_start_time);
|
||||
monotime(&spf_start_time);
|
||||
/* Allocate new table tree. */
|
||||
new_table = route_table_init ();
|
||||
new_rtrs = route_table_init ();
|
||||
@ -1338,24 +1339,19 @@ ospf_spf_calculate_timer (struct thread *thread)
|
||||
areas_processed++;
|
||||
}
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time);
|
||||
spf_time = timeval_elapsed (stop_time, spf_start_time);
|
||||
spf_time = monotime_since(&spf_start_time, NULL);
|
||||
|
||||
ospf_vl_shut_unapproved (ospf);
|
||||
|
||||
start_time = stop_time; /* saving a call */
|
||||
|
||||
monotime(&start_time);
|
||||
ospf_ia_routing (ospf, new_table, new_rtrs);
|
||||
ia_time = monotime_since(&start_time, NULL);
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time);
|
||||
ia_time = timeval_elapsed (stop_time, start_time);
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time);
|
||||
monotime(&start_time);
|
||||
ospf_prune_unreachable_networks (new_table);
|
||||
ospf_prune_unreachable_routers (new_rtrs);
|
||||
prune_time = monotime_since(&start_time, NULL);
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time);
|
||||
prune_time = timeval_elapsed (stop_time, start_time);
|
||||
/* AS-external-LSA calculation should not be performed here. */
|
||||
|
||||
/* If new Router Route is installed,
|
||||
@ -1365,13 +1361,11 @@ ospf_spf_calculate_timer (struct thread *thread)
|
||||
|
||||
ospf_ase_calculate_timer_add (ospf);
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time);
|
||||
|
||||
/* Update routing table. */
|
||||
monotime(&start_time);
|
||||
ospf_route_install (ospf, new_table);
|
||||
rt_time = monotime_since(&start_time, NULL);
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time);
|
||||
rt_time = timeval_elapsed (stop_time, start_time);
|
||||
/* Update ABR/ASBR routing table */
|
||||
if (ospf->old_rtrs)
|
||||
{
|
||||
@ -1383,17 +1377,12 @@ ospf_spf_calculate_timer (struct thread *thread)
|
||||
ospf->old_rtrs = ospf->new_rtrs;
|
||||
ospf->new_rtrs = new_rtrs;
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time);
|
||||
monotime(&start_time);
|
||||
if (IS_OSPF_ABR (ospf))
|
||||
ospf_abr_task (ospf);
|
||||
abr_time = monotime_since(&start_time, NULL);
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time);
|
||||
abr_time = timeval_elapsed (stop_time, start_time);
|
||||
|
||||
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time);
|
||||
total_spf_time = timeval_elapsed (stop_time, spf_start_time);
|
||||
ospf->ts_spf_duration.tv_sec = total_spf_time/1000000;
|
||||
ospf->ts_spf_duration.tv_usec = total_spf_time % 1000000;
|
||||
total_spf_time = monotime_since(&spf_start_time, &ospf->ts_spf_duration);
|
||||
|
||||
ospf_get_spf_reason_str (rbuf);
|
||||
|
||||
@ -1421,7 +1410,6 @@ void
|
||||
ospf_spf_calculate_schedule (struct ospf *ospf, ospf_spf_reason_t reason)
|
||||
{
|
||||
unsigned long delay, elapsed, ht;
|
||||
struct timeval result;
|
||||
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug ("SPF: calculation timer scheduled");
|
||||
@ -1440,11 +1428,9 @@ ospf_spf_calculate_schedule (struct ospf *ospf, ospf_spf_reason_t reason)
|
||||
(void *)ospf->t_spf_calc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* XXX Monotic timers: we only care about relative time here. */
|
||||
result = tv_sub (recent_relative_time (), ospf->ts_spf);
|
||||
|
||||
elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
|
||||
|
||||
elapsed = monotime_since (&ospf->ts_spf, NULL) / 1000;
|
||||
|
||||
ht = ospf->spf_holdtime * ospf->spf_hold_multiplier;
|
||||
|
||||
if (ht > ospf->spf_max_holdtime)
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <zebra.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "monotime.h"
|
||||
#include "memory.h"
|
||||
#include "thread.h"
|
||||
#include "prefix.h"
|
||||
@ -2809,10 +2810,8 @@ show_ip_ospf_area (struct vty *vty, struct ospf_area *area, json_object *json_ar
|
||||
json_object_boolean_true_add(json_area, "indefiniteActiveAdmin");
|
||||
if (area->t_stub_router)
|
||||
{
|
||||
struct timeval result;
|
||||
unsigned long time_store = 0;
|
||||
result = tv_sub (area->t_stub_router->u.sands, recent_relative_time());
|
||||
time_store = (1000 * result.tv_sec) + (result.tv_usec / 1000);
|
||||
long time_store;
|
||||
time_store = monotime_until(&area->t_stub_router->u.sands, NULL) / 1000LL;
|
||||
json_object_int_add(json_area, "activeStartupRemainderMsecs", time_store);
|
||||
}
|
||||
}
|
||||
@ -2971,9 +2970,8 @@ show_ip_ospf_common (struct vty *vty, struct ospf *ospf, u_char use_json)
|
||||
{
|
||||
if (use_json)
|
||||
{
|
||||
unsigned long time_store = 0;
|
||||
result = tv_sub (ospf->t_deferred_shutdown->u.sands, recent_relative_time());
|
||||
time_store = (1000 * result.tv_sec) + (result.tv_usec / 1000);
|
||||
long time_store;
|
||||
time_store = monotime_until(&ospf->t_deferred_shutdown->u.sands, NULL) / 1000LL;
|
||||
json_object_int_add(json, "deferredShutdownMsecs", time_store);
|
||||
}
|
||||
else
|
||||
@ -3066,11 +3064,9 @@ show_ip_ospf_common (struct vty *vty, struct ospf *ospf, u_char use_json)
|
||||
{
|
||||
if (ospf->ts_spf.tv_sec || ospf->ts_spf.tv_usec)
|
||||
{
|
||||
unsigned long time_store = 0;
|
||||
long time_store = 0;
|
||||
|
||||
result = tv_sub (recent_relative_time(), ospf->ts_spf);
|
||||
result = tv_sub (result, recent_relative_time());
|
||||
time_store = (1000 * result.tv_sec) + (result.tv_usec / 1000);
|
||||
time_store = monotime_since(&ospf->ts_spf, NULL) / 1000LL;
|
||||
json_object_int_add(json, "spfLastExecutedMsecs", time_store);
|
||||
|
||||
time_store = (1000 * ospf->ts_spf_duration.tv_sec) + (ospf->ts_spf_duration.tv_usec / 1000);
|
||||
@ -3084,7 +3080,7 @@ show_ip_ospf_common (struct vty *vty, struct ospf *ospf, u_char use_json)
|
||||
vty_out (vty, " SPF algorithm ");
|
||||
if (ospf->ts_spf.tv_sec || ospf->ts_spf.tv_usec)
|
||||
{
|
||||
result = tv_sub (recent_relative_time(), ospf->ts_spf);
|
||||
monotime_since(&ospf->ts_spf, &result);
|
||||
vty_out (vty, "last executed %s ago%s",
|
||||
ospf_timeval_dump (&result, timebuf, sizeof (timebuf)),
|
||||
VTY_NEWLINE);
|
||||
@ -3098,13 +3094,10 @@ show_ip_ospf_common (struct vty *vty, struct ospf *ospf, u_char use_json)
|
||||
|
||||
if (use_json)
|
||||
{
|
||||
struct timeval temp_time;
|
||||
unsigned long time_store = 0;
|
||||
|
||||
if (ospf->t_spf_calc)
|
||||
{
|
||||
temp_time = tv_sub (ospf->t_spf_calc->u.sands, recent_relative_time());
|
||||
time_store = (1000 * temp_time.tv_sec) + (temp_time.tv_usec / 1000);
|
||||
long time_store;
|
||||
time_store = monotime_until(&ospf->t_spf_calc->u.sands, NULL) / 1000LL;
|
||||
json_object_int_add(json, "spfTimerDueInMsecs", time_store);
|
||||
}
|
||||
|
||||
@ -3509,16 +3502,9 @@ show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf, struct interface
|
||||
char timebuf[OSPF_TIME_DUMP_SIZE];
|
||||
if (use_json)
|
||||
{
|
||||
struct timeval result;
|
||||
unsigned long time_store = 0;
|
||||
if (oi->t_hello)
|
||||
result = tv_sub (oi->t_hello->u.sands, recent_relative_time());
|
||||
else
|
||||
{
|
||||
result.tv_sec = 0;
|
||||
result.tv_usec = 0;
|
||||
}
|
||||
time_store = (1000 * result.tv_sec) + (result.tv_usec / 1000);
|
||||
long time_store = 0;
|
||||
if (oi->t_hello)
|
||||
time_store = monotime_until(&oi->t_hello->u.sands, NULL) / 1000LL;
|
||||
json_object_int_add(json_interface_sub, "timerHelloInMsecs", time_store);
|
||||
}
|
||||
else
|
||||
@ -3708,11 +3694,9 @@ show_ip_ospf_neighbor_sub (struct vty *vty, struct ospf_interface *oi, json_obje
|
||||
json_neighbor = json_object_new_object();
|
||||
ospf_nbr_state_message (nbr, msgbuf, 16);
|
||||
|
||||
struct timeval result;
|
||||
unsigned long time_store = 0;
|
||||
long time_store;
|
||||
|
||||
result = tv_sub (nbr->t_inactivity->u.sands, recent_relative_time());
|
||||
time_store = (1000 * result.tv_sec) + (result.tv_usec / 1000);
|
||||
time_store = monotime_until(&nbr->t_inactivity->u.sands, NULL) / 1000LL;
|
||||
|
||||
json_object_int_add (json_neighbor, "priority", nbr->priority);
|
||||
json_object_string_add (json_neighbor, "state", msgbuf);
|
||||
@ -4093,9 +4077,8 @@ show_ip_ospf_nbr_nbma_detail_sub (struct vty *vty, struct ospf_interface *oi, st
|
||||
/* Show poll-interval timer. */
|
||||
if (use_json)
|
||||
{
|
||||
struct timeval res = tv_sub (nbr_nbma->t_poll->u.sands, recent_relative_time ());
|
||||
unsigned long time_store = 0;
|
||||
time_store = (1000 * res.tv_sec) + (res.tv_usec / 1000);
|
||||
long time_store;
|
||||
time_store = monotime_until(&nbr_nbma->t_poll->u.sands, NULL) / 1000LL;
|
||||
json_object_int_add(json_sub, "pollIntervalTimerDueMsec", time_store);
|
||||
}
|
||||
else
|
||||
@ -4170,11 +4153,12 @@ show_ip_ospf_neighbor_detail_sub (struct vty *vty, struct ospf_interface *oi,
|
||||
|
||||
if (nbr->ts_last_progress.tv_sec || nbr->ts_last_progress.tv_usec)
|
||||
{
|
||||
struct timeval res = tv_sub (recent_relative_time (), nbr->ts_last_progress);
|
||||
struct timeval res;
|
||||
long time_store;
|
||||
|
||||
time_store = monotime_since(&nbr->ts_last_progress, &res) / 1000LL;
|
||||
if (use_json)
|
||||
{
|
||||
unsigned long time_store = 0;
|
||||
time_store = (1000 * res.tv_sec) + (res.tv_usec / 1000);
|
||||
json_object_int_add(json_sub, "lastPrgrsvChangeMsec", time_store);
|
||||
}
|
||||
else
|
||||
@ -4189,11 +4173,12 @@ show_ip_ospf_neighbor_detail_sub (struct vty *vty, struct ospf_interface *oi,
|
||||
|
||||
if (nbr->ts_last_regress.tv_sec || nbr->ts_last_regress.tv_usec)
|
||||
{
|
||||
struct timeval res = tv_sub (recent_relative_time (), nbr->ts_last_regress);
|
||||
struct timeval res;
|
||||
long time_store;
|
||||
|
||||
time_store = monotime_since(&nbr->ts_last_regress, &res) / 1000LL;
|
||||
if (use_json)
|
||||
{
|
||||
unsigned long time_store = 0;
|
||||
time_store = (1000 * res.tv_sec) + (res.tv_usec / 1000);
|
||||
json_object_int_add(json_sub, "lastRegressiveChangeMsec", time_store);
|
||||
if (nbr->last_regress_str)
|
||||
json_object_string_add(json_sub, "lastRegressiveChangeReason", nbr->last_regress_str);
|
||||
@ -4234,9 +4219,8 @@ show_ip_ospf_neighbor_detail_sub (struct vty *vty, struct ospf_interface *oi,
|
||||
{
|
||||
if (nbr->t_inactivity)
|
||||
{
|
||||
struct timeval res = tv_sub (nbr->t_inactivity->u.sands, recent_relative_time ());
|
||||
unsigned long time_store = 0;
|
||||
time_store = (1000 * res.tv_sec) + (res.tv_usec / 1000);
|
||||
long time_store;
|
||||
time_store = monotime_until(&nbr->t_inactivity->u.sands, NULL) / 1000LL;
|
||||
json_object_int_add(json_sub, "routerDeadIntervalTimerDueMsec", time_store);
|
||||
}
|
||||
else
|
||||
|
@ -273,7 +273,7 @@ ospf_new (u_short instance)
|
||||
new->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT;
|
||||
new->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker,
|
||||
new, new->lsa_refresh_interval);
|
||||
new->lsa_refresher_started = quagga_monotime ();
|
||||
new->lsa_refresher_started = monotime(NULL);
|
||||
|
||||
if ((new->fd = ospf_sock_init()) < 0)
|
||||
{
|
||||
@ -1583,7 +1583,7 @@ ospf_timers_refresh_set (struct ospf *ospf, int interval)
|
||||
return 1;
|
||||
|
||||
time_left = ospf->lsa_refresh_interval -
|
||||
(quagga_monotime () - ospf->lsa_refresher_started);
|
||||
(monotime(NULL) - ospf->lsa_refresher_started);
|
||||
|
||||
if (time_left > interval)
|
||||
{
|
||||
@ -1602,7 +1602,7 @@ ospf_timers_refresh_unset (struct ospf *ospf)
|
||||
int time_left;
|
||||
|
||||
time_left = ospf->lsa_refresh_interval -
|
||||
(quagga_monotime () - ospf->lsa_refresher_started);
|
||||
(monotime(NULL) - ospf->lsa_refresher_started);
|
||||
|
||||
if (time_left > OSPF_LSA_REFRESH_INTERVAL_DEFAULT)
|
||||
{
|
||||
|
@ -19,7 +19,6 @@
|
||||
# 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
# PIM_DEBUG_BYDEFAULT: Automatically enables all pimd "debug ..." commands
|
||||
# PIM_ZCLIENT_DEBUG: Support for internal ZEBRA client debugging
|
||||
# PIM_CHECK_RECV_IFINDEX_SANITY: Compare socket ifindex with recv ifindex
|
||||
# PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch
|
||||
# PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries
|
||||
@ -27,9 +26,8 @@
|
||||
|
||||
PIM_DEFS =
|
||||
#PIM_DEFS += -DPIM_DEBUG_BYDEFAULT
|
||||
PIM_DEFS += -DPIM_CHECK_RECV_IFINDEX_SANITY
|
||||
#PIM_DEFS += -DPIM_CHECK_RECV_IFINDEX_SANITY
|
||||
#PIM_DEFS += -DPIM_REPORT_RECV_IFINDEX_MISMATCH
|
||||
PIM_DEFS += -DPIM_ZCLIENT_DEBUG
|
||||
PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC
|
||||
#PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL
|
||||
|
||||
@ -47,24 +45,26 @@ noinst_PROGRAMS = test_igmpv3_join
|
||||
libpim_a_SOURCES = \
|
||||
pim_memory.c \
|
||||
pimd.c pim_version.c pim_cmd.c pim_signals.c pim_iface.c \
|
||||
pim_vty.c pim_igmp.c pim_sock.c pim_zebra.c \
|
||||
pim_vty.c pim_igmp.c pim_sock.c pim_zebra.c pim_igmpv2.c \
|
||||
pim_igmpv3.c pim_str.c pim_mroute.c pim_util.c pim_time.c \
|
||||
pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \
|
||||
pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \
|
||||
pim_msg.c pim_upstream.c pim_rpf.c pim_macro.c \
|
||||
pim_ssmpingd.c pim_int.c pim_rp.c \
|
||||
pim_static.c pim_br.c pim_register.c pim_routemap.c
|
||||
pim_static.c pim_br.c pim_register.c pim_routemap.c \
|
||||
pim_msdp.c pim_msdp_socket.c pim_msdp_packet.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
pim_memory.h \
|
||||
pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \
|
||||
pim_vty.h pim_igmp.h pim_sock.h pim_zebra.h \
|
||||
pim_vty.h pim_igmp.h pim_sock.h pim_zebra.h pim_igmpv2.h \
|
||||
pim_igmpv3.h pim_str.h pim_mroute.h pim_util.h pim_time.h \
|
||||
pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \
|
||||
pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \
|
||||
pim_msg.h pim_upstream.h pim_rpf.h pim_macro.h \
|
||||
pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_rp.h \
|
||||
pim_static.h pim_br.h pim_register.h
|
||||
pim_static.h pim_br.h pim_register.h \
|
||||
pim_msdp.h pim_msdp_socket.h pim_msdp_packet.h
|
||||
|
||||
pimd_SOURCES = \
|
||||
pim_main.c $(libpim_a_SOURCES)
|
||||
|
81
pimd/README
81
pimd/README
@ -1,18 +1,17 @@
|
||||
INTRODUCTION
|
||||
|
||||
qpimd aims to implement a PIM (Protocol Independent Multicast)
|
||||
daemon for the Quagga Routing Suite.
|
||||
daemon for the FRR Routing Suite.
|
||||
|
||||
Initially qpimd targets only PIM SSM (Source-Specific
|
||||
Multicast) mode as defined in section 4.8.2 (PIM-SSM-Only
|
||||
Routers) of RFC 4601.
|
||||
qpimd implements PIM-SM (Sparse Mode) of RFC 4601.
|
||||
Additionally MSDP has been implemented.
|
||||
|
||||
In order to deliver end-to-end multicast routing control
|
||||
plane, qpimd includes the router-side of IGMPv3 (RFC 3376).
|
||||
plane, qpimd includes the router-side of IGMPv[2|3] (RFC 3376).
|
||||
|
||||
LICENSE
|
||||
|
||||
qpimd - pimd for quagga
|
||||
qpimd - pimd for FRR
|
||||
Copyright (C) 2008 Everton da Silva Marques
|
||||
|
||||
qpimd is free software; you can redistribute it and/or modify
|
||||
@ -34,78 +33,16 @@ HOME SITE
|
||||
|
||||
qpimd lives at:
|
||||
|
||||
https://github.com/udhos/qpimd
|
||||
https://github.com/freerangerouting/frr
|
||||
|
||||
PLATFORMS
|
||||
|
||||
qpimd has been tested with Debian Lenny under Linux 2.6.
|
||||
qpimd has been tested with Debian Jessie.
|
||||
|
||||
REQUIREMENTS
|
||||
|
||||
qpimd requires Quagga (0.99.11 or higher from http://www.quagga.net)
|
||||
qpimd requires FRR (2.0 or higher)
|
||||
|
||||
The GNU Build System (Autotools) is required to build from
|
||||
source code repository.
|
||||
|
||||
gawk is also needed to build with Autotools. Any other awk
|
||||
usually won't work.
|
||||
|
||||
BUILDING FROM QUAGGA GIT REPOSITORY
|
||||
|
||||
1) Get the latest quagga source tree
|
||||
|
||||
# git clone git://code.quagga.net/quagga.git quagga
|
||||
|
||||
2) Apply qpimd patch into quagga source tree
|
||||
|
||||
# patch -p1 -d quagga < pimd-0.153-quagga-git20090623.patch
|
||||
|
||||
3) Compile and install quagga
|
||||
|
||||
# cd quagga
|
||||
# ./bootstrap.sh
|
||||
# ./configure --prefix=/usr/local/quagga --enable-pimd
|
||||
# make
|
||||
# make install
|
||||
|
||||
BUILDING FROM QUAGGA TARBALL
|
||||
|
||||
1) Get the latest quagga tarball
|
||||
|
||||
# wget http://www.quagga.net/download/quagga-0.99.13.tar.gz
|
||||
|
||||
2) Unpack the quagga tarball
|
||||
|
||||
# tar xzf quagga-0.99.13.tar.gz
|
||||
|
||||
3) Apply qpimd patch into quagga source tree
|
||||
|
||||
# patch -p1 -d quagga-0.99.13 < pimd-0.153-quagga-0.99.13.patch
|
||||
|
||||
4) Compile and install quagga
|
||||
|
||||
# cd quagga-0.99.13
|
||||
# ./configure --prefix=/usr/local/quagga --enable-pimd
|
||||
# make
|
||||
# make install
|
||||
|
||||
USAGE
|
||||
|
||||
1) Configure and start the zebra daemon
|
||||
|
||||
# cp /usr/local/quagga/etc/zebra.conf.sample /usr/local/quagga/etc/zebra.conf
|
||||
# vi /usr/local/quagga/etc/zebra.conf
|
||||
# /usr/local/quagga/sbin/zebra
|
||||
|
||||
2) Configure and start the pimd daemon
|
||||
|
||||
# cp /usr/local/quagga/etc/pimd.conf.sample /usr/local/quagga/etc/pimd.conf
|
||||
# vi /usr/local/quagga/etc/pimd.conf
|
||||
# /usr/local/quagga/sbin/pimd
|
||||
|
||||
3) Access pimd vty interface at port TCP 2611
|
||||
|
||||
# telnet localhost 2611
|
||||
|
||||
CONFIGURATION COMMANDS
|
||||
|
||||
@ -120,7 +57,7 @@ SUPPORT
|
||||
Please post comments, questions, patches, bug reports at the
|
||||
support site:
|
||||
|
||||
https://github.com/udhos/qpimd
|
||||
https://freerangerouting/frr
|
||||
|
||||
RELATED WORK
|
||||
|
||||
|
@ -54,31 +54,23 @@ void pim_ifassert_winner_set(struct pim_ifchannel *ch,
|
||||
|
||||
if (PIM_DEBUG_PIM_EVENTS) {
|
||||
if (ch->ifassert_state != new_state) {
|
||||
char src_str[100];
|
||||
char grp_str[100];
|
||||
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
|
||||
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
|
||||
zlog_debug("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
src_str, grp_str,
|
||||
pim_ifchannel_ifassert_name(ch->ifassert_state),
|
||||
pim_ifchannel_ifassert_name(new_state),
|
||||
ch->interface->name);
|
||||
zlog_debug("%s: (S,G)=%s assert state changed from %s to %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
ch->sg_str,
|
||||
pim_ifchannel_ifassert_name(ch->ifassert_state),
|
||||
pim_ifchannel_ifassert_name(new_state),
|
||||
ch->interface->name);
|
||||
}
|
||||
|
||||
if (winner_changed) {
|
||||
char src_str[100];
|
||||
char grp_str[100];
|
||||
char was_str[100];
|
||||
char winner_str[100];
|
||||
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
|
||||
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
|
||||
char was_str[INET_ADDRSTRLEN];
|
||||
char winner_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<was?>", ch->ifassert_winner, was_str, sizeof(was_str));
|
||||
pim_inet4_dump("<winner?>", winner, winner_str, sizeof(winner_str));
|
||||
zlog_debug("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
src_str, grp_str,
|
||||
was_str, winner_str, ch->interface->name);
|
||||
zlog_debug("%s: (S,G)=%s assert winner changed from %s to %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
ch->sg_str,
|
||||
was_str, winner_str, ch->interface->name);
|
||||
}
|
||||
} /* PIM_DEBUG_PIM_EVENTS */
|
||||
|
||||
@ -98,7 +90,7 @@ static void on_trace(const char *label,
|
||||
struct interface *ifp, struct in_addr src)
|
||||
{
|
||||
if (PIM_DEBUG_PIM_TRACE) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: from %s on %s",
|
||||
label, src_str, ifp->name);
|
||||
@ -138,13 +130,9 @@ static void if_could_assert_do_a1(const char *caller,
|
||||
{
|
||||
if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
|
||||
if (assert_action_a1(ch)) {
|
||||
char src_str[100];
|
||||
char grp_str[100];
|
||||
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
|
||||
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
|
||||
zlog_warn("%s: %s: (S,G)=(%s,%s) assert_action_a1 failure on interface %s",
|
||||
zlog_warn("%s: %s: (S,G)=%s assert_action_a1 failure on interface %s",
|
||||
__PRETTY_FUNCTION__, caller,
|
||||
src_str, grp_str, ch->interface->name);
|
||||
ch->sg_str, ch->interface->name);
|
||||
/* log warning only */
|
||||
}
|
||||
}
|
||||
@ -156,16 +144,16 @@ static int dispatch_assert(struct interface *ifp,
|
||||
struct pim_assert_metric recv_metric)
|
||||
{
|
||||
struct pim_ifchannel *ch;
|
||||
struct prefix_sg sg;
|
||||
|
||||
ch = pim_ifchannel_add(ifp, source_addr, group_addr);
|
||||
memset (&sg, 0, sizeof (struct prefix_sg));
|
||||
sg.src = source_addr;
|
||||
sg.grp = group_addr;
|
||||
ch = pim_ifchannel_add(ifp, &sg, 0);
|
||||
if (!ch) {
|
||||
char source_str[100];
|
||||
char group_str[100];
|
||||
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
|
||||
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
|
||||
zlog_warn("%s: (S,G)=(%s,%s) failure creating channel on interface %s",
|
||||
zlog_warn("%s: (S,G)=%s failure creating channel on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
source_str, group_str, ifp->name);
|
||||
pim_str_sg_dump (&sg), ifp->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -193,7 +181,6 @@ static int dispatch_assert(struct interface *ifp,
|
||||
}
|
||||
else {
|
||||
if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) {
|
||||
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
|
||||
assert_action_a3(ch);
|
||||
}
|
||||
}
|
||||
@ -222,13 +209,9 @@ static int dispatch_assert(struct interface *ifp,
|
||||
break;
|
||||
default:
|
||||
{
|
||||
char source_str[100];
|
||||
char group_str[100];
|
||||
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
|
||||
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
|
||||
zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
|
||||
zlog_warn("%s: (S,G)=%s invalid assert state %d on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
source_str, group_str, ch->ifassert_state, ifp->name);
|
||||
ch->sg_str, ch->ifassert_state, ifp->name);
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
@ -241,7 +224,7 @@ int pim_assert_recv(struct interface *ifp,
|
||||
struct in_addr src_addr,
|
||||
uint8_t *buf, int buf_size)
|
||||
{
|
||||
struct prefix msg_group_addr;
|
||||
struct prefix_sg sg;
|
||||
struct prefix msg_source_addr;
|
||||
struct pim_assert_metric msg_metric;
|
||||
int offset;
|
||||
@ -256,9 +239,10 @@ int pim_assert_recv(struct interface *ifp,
|
||||
/*
|
||||
Parse assert group addr
|
||||
*/
|
||||
offset = pim_parse_addr_group (&msg_group_addr, curr, curr_size);
|
||||
memset (&sg, 0, sizeof (struct prefix_sg));
|
||||
offset = pim_parse_addr_group (&sg, curr, curr_size);
|
||||
if (offset < 1) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
@ -273,7 +257,7 @@ int pim_assert_recv(struct interface *ifp,
|
||||
*/
|
||||
offset = pim_parse_addr_ucast (&msg_source_addr, curr, curr_size);
|
||||
if (offset < 1) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
@ -284,7 +268,7 @@ int pim_assert_recv(struct interface *ifp,
|
||||
curr_size -= offset;
|
||||
|
||||
if (curr_size != 8) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
@ -311,12 +295,12 @@ int pim_assert_recv(struct interface *ifp,
|
||||
msg_metric.route_metric = pim_read_uint32_host(curr);
|
||||
|
||||
if (PIM_DEBUG_PIM_TRACE) {
|
||||
char neigh_str[100];
|
||||
char source_str[100];
|
||||
char group_str[100];
|
||||
char neigh_str[INET_ADDRSTRLEN];
|
||||
char source_str[INET_ADDRSTRLEN];
|
||||
char group_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<neigh?>", src_addr, neigh_str, sizeof(neigh_str));
|
||||
pim_inet4_dump("<src?>", msg_source_addr.u.prefix4, source_str, sizeof(source_str));
|
||||
pim_inet4_dump("<grp?>", msg_group_addr.u.prefix4, group_str, sizeof(group_str));
|
||||
pim_inet4_dump("<grp?>", sg.grp, group_str, sizeof(group_str));
|
||||
zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
|
||||
__PRETTY_FUNCTION__, neigh_str, ifp->name,
|
||||
source_str, group_str,
|
||||
@ -329,7 +313,7 @@ int pim_assert_recv(struct interface *ifp,
|
||||
|
||||
return dispatch_assert(ifp,
|
||||
msg_source_addr.u.prefix4,
|
||||
msg_group_addr.u.prefix4,
|
||||
sg.grp,
|
||||
msg_metric);
|
||||
}
|
||||
|
||||
@ -399,7 +383,7 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
|
||||
remain,
|
||||
group_addr);
|
||||
if (!pim_msg_curr) {
|
||||
char group_str[100];
|
||||
char group_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
|
||||
zlog_warn("%s: failure encoding group address %s: space left=%d",
|
||||
__PRETTY_FUNCTION__, group_str, remain);
|
||||
@ -412,7 +396,7 @@ int pim_assert_build_msg(uint8_t *pim_msg, int buf_size,
|
||||
remain,
|
||||
source_addr);
|
||||
if (!pim_msg_curr) {
|
||||
char source_str[100];
|
||||
char source_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
|
||||
zlog_warn("%s: failure encoding source address %s: space left=%d",
|
||||
__PRETTY_FUNCTION__, source_str, remain);
|
||||
@ -448,17 +432,23 @@ static int pim_assert_do(struct pim_ifchannel *ch,
|
||||
int pim_msg_size;
|
||||
|
||||
ifp = ch->interface;
|
||||
zassert(ifp);
|
||||
|
||||
if (!ifp)
|
||||
{
|
||||
if (PIM_DEBUG_PIM_TRACE)
|
||||
zlog_debug("%s: channel%s has no associated interface!",
|
||||
__PRETTY_FUNCTION__, ch->sg_str);
|
||||
return -1;
|
||||
}
|
||||
pim_ifp = ifp->info;
|
||||
if (!pim_ifp) {
|
||||
zlog_warn("%s: pim not enabled on interface: %s",
|
||||
__PRETTY_FUNCTION__, ifp->name);
|
||||
if (PIM_DEBUG_PIM_TRACE)
|
||||
zlog_debug("%s: channel %s pim not enabled on interface: %s",
|
||||
__PRETTY_FUNCTION__, ch->sg_str, ifp->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp,
|
||||
ch->group_addr, ch->source_addr,
|
||||
ch->sg.grp, ch->sg.src,
|
||||
metric.metric_preference,
|
||||
metric.route_metric,
|
||||
metric.rpt_bit_flag);
|
||||
@ -480,19 +470,16 @@ static int pim_assert_do(struct pim_ifchannel *ch,
|
||||
pim_hello_require(ifp);
|
||||
|
||||
if (PIM_DEBUG_PIM_TRACE) {
|
||||
char source_str[100];
|
||||
char group_str[100];
|
||||
pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
|
||||
pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
|
||||
zlog_debug("%s: to %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u",
|
||||
zlog_debug("%s: to %s: (S,G)=%s pref=%u metric=%u rpt_bit=%u",
|
||||
__PRETTY_FUNCTION__,
|
||||
ifp->name, source_str, group_str,
|
||||
ifp->name, ch->sg_str,
|
||||
metric.metric_preference,
|
||||
metric.route_metric,
|
||||
PIM_FORCE_BOOLEAN(metric.rpt_bit_flag));
|
||||
}
|
||||
|
||||
if (pim_msg_send(pim_ifp->pim_sock_fd,
|
||||
pim_ifp->primary_address,
|
||||
qpim_all_pim_routers_addr,
|
||||
pim_msg,
|
||||
pim_msg_size,
|
||||
@ -523,7 +510,7 @@ static int pim_assert_cancel(struct pim_ifchannel *ch)
|
||||
metric.rpt_bit_flag = 0;
|
||||
metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX;
|
||||
metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX;
|
||||
metric.ip_address = ch->source_addr;
|
||||
metric.ip_address = ch->sg.src;
|
||||
|
||||
return pim_assert_do(ch, metric);
|
||||
}
|
||||
@ -533,28 +520,20 @@ static int on_assert_timer(struct thread *t)
|
||||
struct pim_ifchannel *ch;
|
||||
struct interface *ifp;
|
||||
|
||||
zassert(t);
|
||||
ch = THREAD_ARG(t);
|
||||
zassert(ch);
|
||||
|
||||
ifp = ch->interface;
|
||||
zassert(ifp);
|
||||
|
||||
if (PIM_DEBUG_PIM_TRACE) {
|
||||
char src_str[100];
|
||||
char grp_str[100];
|
||||
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
|
||||
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
|
||||
zlog_debug("%s: (S,G)=(%s,%s) timer expired on interface %s",
|
||||
zlog_debug("%s: (S,G)=%s timer expired on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
src_str, grp_str, ifp->name);
|
||||
ch->sg_str, ifp->name);
|
||||
}
|
||||
|
||||
ch->t_ifassert_timer = 0;
|
||||
ch->t_ifassert_timer = NULL;
|
||||
|
||||
switch (ch->ifassert_state) {
|
||||
case PIM_IFASSERT_I_AM_WINNER:
|
||||
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
|
||||
assert_action_a3(ch);
|
||||
break;
|
||||
case PIM_IFASSERT_I_AM_LOSER:
|
||||
@ -562,13 +541,10 @@ static int on_assert_timer(struct thread *t)
|
||||
break;
|
||||
default:
|
||||
{
|
||||
char source_str[100];
|
||||
char group_str[100];
|
||||
pim_inet4_dump("<src?>", ch->source_addr, source_str, sizeof(source_str));
|
||||
pim_inet4_dump("<grp?>", ch->group_addr, group_str, sizeof(group_str));
|
||||
zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
source_str, group_str, ch->ifassert_state, ifp->name);
|
||||
if (PIM_DEBUG_PIM_EVENTS)
|
||||
zlog_warn("%s: (S,G)=%s invalid assert state %d on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
ch->sg_str, ch->ifassert_state, ifp->name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -577,46 +553,25 @@ static int on_assert_timer(struct thread *t)
|
||||
|
||||
static void assert_timer_off(struct pim_ifchannel *ch)
|
||||
{
|
||||
struct interface *ifp;
|
||||
|
||||
zassert(ch);
|
||||
ifp = ch->interface;
|
||||
zassert(ifp);
|
||||
|
||||
if (PIM_DEBUG_PIM_TRACE) {
|
||||
if (ch->t_ifassert_timer) {
|
||||
char src_str[100];
|
||||
char grp_str[100];
|
||||
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
|
||||
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
|
||||
zlog_debug("%s: (S,G)=(%s,%s) cancelling timer on interface %s",
|
||||
zlog_debug("%s: (S,G)=%s cancelling timer on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
src_str, grp_str, ifp->name);
|
||||
ch->sg_str, ch->interface->name);
|
||||
}
|
||||
}
|
||||
THREAD_OFF(ch->t_ifassert_timer);
|
||||
zassert(!ch->t_ifassert_timer);
|
||||
}
|
||||
|
||||
static void pim_assert_timer_set(struct pim_ifchannel *ch,
|
||||
int interval)
|
||||
{
|
||||
struct interface *ifp;
|
||||
|
||||
zassert(ch);
|
||||
ifp = ch->interface;
|
||||
zassert(ifp);
|
||||
|
||||
assert_timer_off(ch);
|
||||
|
||||
if (PIM_DEBUG_PIM_TRACE) {
|
||||
char src_str[100];
|
||||
char grp_str[100];
|
||||
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
|
||||
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
|
||||
zlog_debug("%s: (S,G)=(%s,%s) starting %u sec timer on interface %s",
|
||||
zlog_debug("%s: (S,G)=%s starting %u sec timer on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
src_str, grp_str, interval, ifp->name);
|
||||
ch->sg_str, interval, ch->interface->name);
|
||||
}
|
||||
|
||||
THREAD_TIMER_ON(master, ch->t_ifassert_timer,
|
||||
@ -644,17 +599,11 @@ int assert_action_a1(struct pim_ifchannel *ch)
|
||||
struct interface *ifp = ch->interface;
|
||||
struct pim_interface *pim_ifp;
|
||||
|
||||
zassert(ifp);
|
||||
|
||||
pim_ifp = ifp->info;
|
||||
if (!pim_ifp) {
|
||||
char src_str[100];
|
||||
char grp_str[100];
|
||||
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
|
||||
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
|
||||
zlog_warn("%s: (S,G)=(%s,%s) multicast not enabled on interface %s",
|
||||
zlog_warn("%s: (S,G)=%s multicast not enabled on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
src_str, grp_str, ifp->name);
|
||||
ch->sg_str, ifp->name);
|
||||
return -1; /* must return since pim_ifp is used below */
|
||||
}
|
||||
|
||||
@ -664,19 +613,19 @@ int assert_action_a1(struct pim_ifchannel *ch)
|
||||
pim_macro_spt_assert_metric(&ch->upstream->rpf,
|
||||
pim_ifp->primary_address));
|
||||
|
||||
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */
|
||||
if (assert_action_a3(ch)) {
|
||||
char src_str[100];
|
||||
char grp_str[100];
|
||||
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
|
||||
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
|
||||
zlog_warn("%s: (S,G)=(%s,%s) assert_action_a3 failure on interface %s",
|
||||
zlog_warn("%s: (S,G)=%s assert_action_a3 failure on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
src_str, grp_str, ifp->name);
|
||||
ch->sg_str, ifp->name);
|
||||
/* warning only */
|
||||
}
|
||||
|
||||
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
|
||||
if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER)
|
||||
{
|
||||
if (PIM_DEBUG_PIM_EVENTS)
|
||||
zlog_warn("%s: channel%s not in expected PIM_IFASSERT_I_AM_WINNER state",
|
||||
__PRETTY_FUNCTION__, ch->sg_str);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -699,7 +648,12 @@ static void assert_action_a2(struct pim_ifchannel *ch,
|
||||
|
||||
pim_assert_timer_set(ch, PIM_ASSERT_TIME);
|
||||
|
||||
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
|
||||
if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
|
||||
{
|
||||
if (PIM_DEBUG_PIM_EVENTS)
|
||||
zlog_warn("%s: channel%s not in expected PIM_IFASSERT_I_AM_LOSER state",
|
||||
__PRETTY_FUNCTION__, ch->sg_str);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -712,24 +666,23 @@ static void assert_action_a2(struct pim_ifchannel *ch,
|
||||
*/
|
||||
static int assert_action_a3(struct pim_ifchannel *ch)
|
||||
{
|
||||
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
|
||||
if (ch->ifassert_state != PIM_IFASSERT_I_AM_WINNER)
|
||||
{
|
||||
if (PIM_DEBUG_PIM_EVENTS)
|
||||
zlog_warn("%s: channel%s expected to be in PIM_IFASSERT_I_AM_WINNER state",
|
||||
__PRETTY_FUNCTION__, ch->sg_str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pim_assert_timer_reset(ch);
|
||||
|
||||
if (pim_assert_send(ch)) {
|
||||
char src_str[100];
|
||||
char grp_str[100];
|
||||
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
|
||||
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
|
||||
|
||||
zlog_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s",
|
||||
zlog_warn("%s: (S,G)=%s failure sending assert on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
src_str, grp_str, ch->interface->name);
|
||||
ch->sg_str, ch->interface->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -746,19 +699,20 @@ static int assert_action_a3(struct pim_ifchannel *ch)
|
||||
void assert_action_a4(struct pim_ifchannel *ch)
|
||||
{
|
||||
if (pim_assert_cancel(ch)) {
|
||||
char src_str[100];
|
||||
char grp_str[100];
|
||||
pim_inet4_dump("<src?>", ch->source_addr, src_str, sizeof(src_str));
|
||||
pim_inet4_dump("<grp?>", ch->group_addr, grp_str, sizeof(grp_str));
|
||||
zlog_warn("%s: failure sending AssertCancel(%s,%s) on interface %s",
|
||||
zlog_warn("%s: failure sending AssertCancel%s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
src_str, grp_str, ch->interface->name);
|
||||
ch->sg_str, ch->interface->name);
|
||||
/* log warning only */
|
||||
}
|
||||
|
||||
assert_action_a5(ch);
|
||||
|
||||
zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
|
||||
if (ch->ifassert_state != PIM_IFASSERT_NOINFO)
|
||||
{
|
||||
if (PIM_DEBUG_PIM_EVENTS)
|
||||
zlog_warn("%s: channel%s not in PIM_IFASSERT_NOINFO state as expected",
|
||||
__PRETTY_FUNCTION__, ch->sg_str);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -772,7 +726,12 @@ void assert_action_a4(struct pim_ifchannel *ch)
|
||||
void assert_action_a5(struct pim_ifchannel *ch)
|
||||
{
|
||||
reset_ifassert_state(ch);
|
||||
zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO);
|
||||
if (ch->ifassert_state != PIM_IFASSERT_NOINFO)
|
||||
{
|
||||
if (PIM_DEBUG_PIM_EVENTS)
|
||||
zlog_warn("%s: channel%s not in PIM_IFSSERT_NOINFO state as expected",
|
||||
__PRETTY_FUNCTION__, ch->sg_str);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -799,6 +758,11 @@ static void assert_action_a6(struct pim_ifchannel *ch,
|
||||
if (ch->upstream->join_state == PIM_UPSTREAM_JOINED)
|
||||
ch->upstream->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
|
||||
|
||||
zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER);
|
||||
if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
|
||||
{
|
||||
if(PIM_DEBUG_PIM_EVENTS)
|
||||
zlog_warn("%s: channel%s not in PIM_IFASSERT_I_AM_LOSER state as expected",
|
||||
__PRETTY_FUNCTION__, ch->sg_str);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,8 +30,7 @@
|
||||
#include "linklist.h"
|
||||
|
||||
struct pim_br {
|
||||
struct in_addr source;
|
||||
struct in_addr group;
|
||||
struct prefix_sg sg;
|
||||
struct in_addr pmbr;
|
||||
};
|
||||
|
||||
@ -40,14 +39,14 @@ struct in_addr pim_br_unknown = { .s_addr = 0 };
|
||||
static struct list *pim_br_list = NULL;
|
||||
|
||||
struct in_addr
|
||||
pim_br_get_pmbr (struct in_addr source, struct in_addr group)
|
||||
pim_br_get_pmbr (struct prefix_sg *sg)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct pim_br *pim_br;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (pim_br_list, node, pim_br)) {
|
||||
if (source.s_addr == pim_br->source.s_addr &&
|
||||
group.s_addr == pim_br->group.s_addr)
|
||||
if (sg->src.s_addr == pim_br->sg.src.s_addr &&
|
||||
sg->grp.s_addr == pim_br->sg.grp.s_addr)
|
||||
return pim_br->pmbr;
|
||||
}
|
||||
|
||||
@ -55,14 +54,14 @@ pim_br_get_pmbr (struct in_addr source, struct in_addr group)
|
||||
}
|
||||
|
||||
void
|
||||
pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr br)
|
||||
pim_br_set_pmbr (struct prefix_sg *sg, struct in_addr br)
|
||||
{
|
||||
struct listnode *node, *next;
|
||||
struct pim_br *pim_br;
|
||||
|
||||
for (ALL_LIST_ELEMENTS (pim_br_list, node, next, pim_br)) {
|
||||
if (source.s_addr == pim_br->source.s_addr &&
|
||||
group.s_addr == pim_br->group.s_addr)
|
||||
if (sg->src.s_addr == pim_br->sg.src.s_addr &&
|
||||
sg->grp.s_addr == pim_br->sg.grp.s_addr)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -73,8 +72,7 @@ pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr br)
|
||||
return;
|
||||
}
|
||||
|
||||
pim_br->source = source;
|
||||
pim_br->group = group;
|
||||
pim_br->sg = *sg;
|
||||
|
||||
listnode_add(pim_br_list, pim_br);
|
||||
}
|
||||
@ -86,14 +84,14 @@ pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr br)
|
||||
* Remove the (S,G) from the stored values
|
||||
*/
|
||||
void
|
||||
pim_br_clear_pmbr (struct in_addr source, struct in_addr group)
|
||||
pim_br_clear_pmbr (struct prefix_sg *sg)
|
||||
{
|
||||
struct listnode *node, *next;
|
||||
struct pim_br *pim_br;
|
||||
|
||||
for (ALL_LIST_ELEMENTS (pim_br_list, node, next, pim_br)) {
|
||||
if (source.s_addr == pim_br->source.s_addr &&
|
||||
group.s_addr == pim_br->group.s_addr)
|
||||
if (sg->src.s_addr == pim_br->sg.src.s_addr &&
|
||||
sg->grp.s_addr == pim_br->sg.grp.s_addr)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -21,10 +21,10 @@
|
||||
#ifndef PIM_BR_H
|
||||
#define PIM_BR_H
|
||||
|
||||
struct in_addr pim_br_get_pmbr (struct in_addr source, struct in_addr group);
|
||||
struct in_addr pim_br_get_pmbr (struct prefix_sg *sg);
|
||||
|
||||
void pim_br_set_pmbr (struct in_addr source, struct in_addr group, struct in_addr value);
|
||||
void pim_br_clear_pmbr (struct in_addr source, struct in_addr group);
|
||||
void pim_br_set_pmbr (struct prefix_sg *sg, struct in_addr value);
|
||||
void pim_br_clear_pmbr (struct prefix_sg *sg);
|
||||
|
||||
void pim_br_init (void);
|
||||
|
||||
|
4991
pimd/pim_cmd.c
4991
pimd/pim_cmd.c
File diff suppressed because it is too large
Load Diff
@ -47,6 +47,7 @@
|
||||
#define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n"
|
||||
#define DEBUG_PIM_HELLO_PACKETS_STR "PIM Hello protocol packets\n"
|
||||
#define DEBUG_PIM_J_P_PACKETS_STR "PIM Join/Prune protocol packets\n"
|
||||
#define DEBUG_PIM_PIM_REG_PACKETS_STR "PIM Register/Reg-Stop protocol packets\n"
|
||||
#define DEBUG_PIM_PACKETDUMP_STR "PIM packet dump\n"
|
||||
#define DEBUG_PIM_PACKETDUMP_SEND_STR "Dump sent packets\n"
|
||||
#define DEBUG_PIM_PACKETDUMP_RECV_STR "Dump received packets\n"
|
||||
@ -57,6 +58,12 @@
|
||||
#define CLEAR_IP_PIM_STR "PIM clear commands\n"
|
||||
#define MROUTE_STR "IP multicast routing table\n"
|
||||
#define RIB_STR "IP unicast routing table\n"
|
||||
#define CFG_MSDP_STR "Configure multicast source discovery protocol\n"
|
||||
#define MSDP_STR "MSDP information\n"
|
||||
#define DEBUG_MSDP_STR "MSDP protocol activity\n"
|
||||
#define DEBUG_MSDP_EVENTS_STR "MSDP protocol events\n"
|
||||
#define DEBUG_MSDP_INTERNAL_STR "MSDP protocol internal\n"
|
||||
#define DEBUG_MSDP_PACKETS_STR "MSDP protocol packets\n"
|
||||
|
||||
void pim_cmd_init(void);
|
||||
|
||||
|
@ -37,7 +37,7 @@ static void on_trace(const char *label,
|
||||
struct interface *ifp, struct in_addr src)
|
||||
{
|
||||
if (PIM_DEBUG_PIM_TRACE) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: from %s on %s",
|
||||
label, src_str, ifp->name);
|
||||
@ -49,7 +49,7 @@ static void tlv_trace_bool(const char *label, const char *tlv_name,
|
||||
int isset, int value)
|
||||
{
|
||||
if (isset) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: PIM hello option from %s on interface %s: %s=%d",
|
||||
label,
|
||||
@ -63,7 +63,7 @@ static void tlv_trace_uint16(const char *label, const char *tlv_name,
|
||||
int isset, uint16_t value)
|
||||
{
|
||||
if (isset) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
|
||||
label,
|
||||
@ -77,7 +77,7 @@ static void tlv_trace_uint32(const char *label, const char *tlv_name,
|
||||
int isset, uint32_t value)
|
||||
{
|
||||
if (isset) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u",
|
||||
label,
|
||||
@ -91,7 +91,7 @@ static void tlv_trace_uint32_hex(const char *label, const char *tlv_name,
|
||||
int isset, uint32_t value)
|
||||
{
|
||||
if (isset) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: PIM hello option from %s on interface %s: %s=%08x",
|
||||
label,
|
||||
@ -106,7 +106,7 @@ static void tlv_trace(const char *label, const char *tlv_name,
|
||||
int isset)
|
||||
{
|
||||
if (isset) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: PIM hello option from %s on interface %s: %s",
|
||||
label,
|
||||
@ -121,7 +121,7 @@ static void tlv_trace_list(const char *label, const char *tlv_name,
|
||||
int isset, struct list *addr_list)
|
||||
{
|
||||
if (isset) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%p",
|
||||
label,
|
||||
@ -181,7 +181,7 @@ int pim_hello_recv(struct interface *ifp,
|
||||
|
||||
if (remain < PIM_TLV_MIN_SIZE) {
|
||||
if (PIM_DEBUG_PIM_HELLO) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
@ -198,7 +198,7 @@ int pim_hello_recv(struct interface *ifp,
|
||||
|
||||
if ((tlv_curr + option_len) > tlv_pastend) {
|
||||
if (PIM_DEBUG_PIM_HELLO) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
@ -209,7 +209,7 @@ int pim_hello_recv(struct interface *ifp,
|
||||
}
|
||||
|
||||
if (PIM_DEBUG_PIM_HELLO) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
@ -267,7 +267,7 @@ int pim_hello_recv(struct interface *ifp,
|
||||
break;
|
||||
case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH:
|
||||
if (PIM_DEBUG_PIM_HELLO) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
@ -277,7 +277,7 @@ int pim_hello_recv(struct interface *ifp,
|
||||
break;
|
||||
default:
|
||||
if (PIM_DEBUG_PIM_HELLO) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
@ -326,7 +326,7 @@ int pim_hello_recv(struct interface *ifp,
|
||||
|
||||
if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
|
||||
if (PIM_DEBUG_PIM_HELLO) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: PIM hello missing holdtime from %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
@ -349,10 +349,11 @@ int pim_hello_recv(struct interface *ifp,
|
||||
hello_option_override_interval,
|
||||
hello_option_dr_priority,
|
||||
hello_option_generation_id,
|
||||
hello_option_addr_list);
|
||||
hello_option_addr_list,
|
||||
PIM_NEIGHBOR_SEND_DELAY);
|
||||
if (!neigh) {
|
||||
if (PIM_DEBUG_PIM_HELLO) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_warn("%s: failure creating PIM neighbor %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
@ -373,15 +374,10 @@ int pim_hello_recv(struct interface *ifp,
|
||||
/* GenID mismatch ? */
|
||||
if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) ||
|
||||
(hello_option_generation_id != neigh->generation_id)) {
|
||||
|
||||
/* GenID changed */
|
||||
|
||||
pim_upstream_rpf_genid_changed(neigh->source_addr);
|
||||
|
||||
/* GenID mismatch, then replace neighbor */
|
||||
|
||||
if (PIM_DEBUG_PIM_HELLO) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
@ -400,10 +396,11 @@ int pim_hello_recv(struct interface *ifp,
|
||||
hello_option_override_interval,
|
||||
hello_option_dr_priority,
|
||||
hello_option_generation_id,
|
||||
hello_option_addr_list);
|
||||
hello_option_addr_list,
|
||||
PIM_NEIGHBOR_SEND_NOW);
|
||||
if (!neigh) {
|
||||
if (PIM_DEBUG_PIM_HELLO) {
|
||||
char src_str[100];
|
||||
char src_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
|
||||
zlog_debug("%s: failure re-creating PIM neighbor %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
|
457
pimd/pim_iface.c
457
pimd/pim_iface.c
@ -25,6 +25,8 @@
|
||||
#include "memory.h"
|
||||
#include "prefix.h"
|
||||
#include "vrf.h"
|
||||
#include "linklist.h"
|
||||
#include "plist.h"
|
||||
|
||||
#include "pimd.h"
|
||||
#include "pim_iface.h"
|
||||
@ -38,14 +40,26 @@
|
||||
#include "pim_sock.h"
|
||||
#include "pim_time.h"
|
||||
#include "pim_ssmpingd.h"
|
||||
#include "pim_rp.h"
|
||||
|
||||
struct interface *pim_regiface = NULL;
|
||||
struct list *pim_ifchannel_list = NULL;
|
||||
|
||||
static void pim_if_igmp_join_del_all(struct interface *ifp);
|
||||
|
||||
void pim_if_init()
|
||||
void
|
||||
pim_if_init (void)
|
||||
{
|
||||
vrf_iflist_create(VRF_DEFAULT);
|
||||
pim_ifchannel_list = list_new();
|
||||
pim_ifchannel_list->cmp = (int (*)(void *, void *))pim_ifchannel_compare;
|
||||
}
|
||||
|
||||
void
|
||||
pim_if_terminate (void)
|
||||
{
|
||||
if (pim_ifchannel_list)
|
||||
list_free (pim_ifchannel_list);
|
||||
}
|
||||
|
||||
static void *if_list_clean(struct pim_interface *pim_ifp)
|
||||
@ -78,15 +92,16 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
|
||||
zassert(ifp);
|
||||
zassert(!ifp->info);
|
||||
|
||||
pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
|
||||
pim_ifp = XCALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
|
||||
if (!pim_ifp) {
|
||||
zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp));
|
||||
zlog_err("PIM XCALLOC(%zu) failure", sizeof(*pim_ifp));
|
||||
return 0;
|
||||
}
|
||||
|
||||
pim_ifp->options = 0;
|
||||
pim_ifp->mroute_vif_index = -1;
|
||||
|
||||
pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
|
||||
pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
|
||||
pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
|
||||
pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
|
||||
@ -104,15 +119,12 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
|
||||
if (igmp)
|
||||
PIM_IF_DO_IGMP(pim_ifp->options);
|
||||
|
||||
#if 0
|
||||
/* FIXME: Should join? */
|
||||
PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
|
||||
#endif
|
||||
|
||||
pim_ifp->igmp_join_list = 0;
|
||||
pim_ifp->igmp_socket_list = 0;
|
||||
pim_ifp->pim_neighbor_list = 0;
|
||||
pim_ifp->pim_ifchannel_list = 0;
|
||||
pim_ifp->igmp_join_list = NULL;
|
||||
pim_ifp->igmp_socket_list = NULL;
|
||||
pim_ifp->pim_neighbor_list = NULL;
|
||||
pim_ifp->pim_ifchannel_list = NULL;
|
||||
pim_ifp->pim_generation_id = 0;
|
||||
|
||||
/* list of struct igmp_sock */
|
||||
@ -141,6 +153,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
|
||||
return if_list_clean(pim_ifp);
|
||||
}
|
||||
pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
|
||||
pim_ifp->pim_ifchannel_list->cmp = (int (*)(void *, void *)) pim_ifchannel_compare;
|
||||
|
||||
ifp->info = pim_ifp;
|
||||
|
||||
@ -164,16 +177,11 @@ void pim_if_delete(struct interface *ifp)
|
||||
if (pim_ifp->igmp_join_list) {
|
||||
pim_if_igmp_join_del_all(ifp);
|
||||
}
|
||||
zassert(!pim_ifp->igmp_join_list);
|
||||
|
||||
zassert(pim_ifp->igmp_socket_list);
|
||||
zassert(!listcount(pim_ifp->igmp_socket_list));
|
||||
pim_ifchannel_delete_all (ifp);
|
||||
igmp_sock_delete_all (ifp);
|
||||
|
||||
zassert(pim_ifp->pim_neighbor_list);
|
||||
zassert(!listcount(pim_ifp->pim_neighbor_list));
|
||||
|
||||
zassert(pim_ifp->pim_ifchannel_list);
|
||||
zassert(!listcount(pim_ifp->pim_ifchannel_list));
|
||||
pim_neighbor_delete_all (ifp, "Interface removed from configuration");
|
||||
|
||||
if (PIM_MROUTE_IS_ENABLED) {
|
||||
pim_if_del_vif(ifp);
|
||||
@ -185,7 +193,7 @@ void pim_if_delete(struct interface *ifp)
|
||||
|
||||
XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
|
||||
|
||||
ifp->info = 0;
|
||||
ifp->info = NULL;
|
||||
}
|
||||
|
||||
void pim_if_update_could_assert(struct interface *ifp)
|
||||
@ -258,14 +266,10 @@ static int detect_primary_address_change(struct interface *ifp,
|
||||
int force_prim_as_any,
|
||||
const char *caller)
|
||||
{
|
||||
struct pim_interface *pim_ifp;
|
||||
struct pim_interface *pim_ifp = ifp->info;
|
||||
struct in_addr new_prim_addr;
|
||||
int changed;
|
||||
|
||||
pim_ifp = ifp->info;
|
||||
if (!pim_ifp)
|
||||
return 0;
|
||||
|
||||
if (force_prim_as_any)
|
||||
new_prim_addr = qpim_inaddr_any;
|
||||
else
|
||||
@ -274,8 +278,8 @@ static int detect_primary_address_change(struct interface *ifp,
|
||||
changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
|
||||
|
||||
if (PIM_DEBUG_ZEBRA) {
|
||||
char new_prim_str[100];
|
||||
char old_prim_str[100];
|
||||
char new_prim_str[INET_ADDRSTRLEN];
|
||||
char old_prim_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
|
||||
pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
|
||||
zlog_debug("%s: old=%s new=%s on interface %s: %s",
|
||||
@ -286,57 +290,230 @@ static int detect_primary_address_change(struct interface *ifp,
|
||||
|
||||
if (changed) {
|
||||
pim_ifp->primary_address = new_prim_addr;
|
||||
|
||||
if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
|
||||
return changed;
|
||||
}
|
||||
|
||||
pim_addr_change(ifp);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void detect_secondary_address_change(struct interface *ifp,
|
||||
static int pim_sec_addr_comp(const void *p1, const void *p2)
|
||||
{
|
||||
const struct pim_secondary_addr *sec1 = p1;
|
||||
const struct pim_secondary_addr *sec2 = p2;
|
||||
|
||||
if (ntohl(sec1->addr.s_addr) < ntohl(sec2->addr.s_addr))
|
||||
return -1;
|
||||
|
||||
if (ntohl(sec1->addr.s_addr) > ntohl(sec2->addr.s_addr))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
|
||||
{
|
||||
XFREE(MTYPE_PIM_SEC_ADDR, sec_addr);
|
||||
}
|
||||
|
||||
static struct pim_secondary_addr *
|
||||
pim_sec_addr_find(struct pim_interface *pim_ifp, struct in_addr addr)
|
||||
{
|
||||
struct pim_secondary_addr *sec_addr;
|
||||
struct listnode *node;
|
||||
|
||||
if (!pim_ifp->sec_addr_list) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
|
||||
if (sec_addr->addr.s_addr == addr.s_addr) {
|
||||
return sec_addr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void pim_sec_addr_del(struct pim_interface *pim_ifp,
|
||||
struct pim_secondary_addr *sec_addr)
|
||||
{
|
||||
listnode_delete(pim_ifp->sec_addr_list, sec_addr);
|
||||
pim_sec_addr_free(sec_addr);
|
||||
}
|
||||
|
||||
static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct in_addr addr)
|
||||
{
|
||||
int changed = 0;
|
||||
struct pim_secondary_addr *sec_addr;
|
||||
|
||||
sec_addr = pim_sec_addr_find(pim_ifp, addr);
|
||||
if (sec_addr) {
|
||||
sec_addr->flags &= ~PIM_SEC_ADDRF_STALE;
|
||||
return changed;
|
||||
}
|
||||
|
||||
if (!pim_ifp->sec_addr_list) {
|
||||
pim_ifp->sec_addr_list = list_new();
|
||||
pim_ifp->sec_addr_list->del = (void (*)(void *))pim_sec_addr_free;
|
||||
pim_ifp->sec_addr_list->cmp = (int (*)(void *, void *))pim_sec_addr_comp;
|
||||
}
|
||||
|
||||
sec_addr = XCALLOC(MTYPE_PIM_SEC_ADDR, sizeof(*sec_addr));
|
||||
if (!sec_addr) {
|
||||
if (list_isempty(pim_ifp->sec_addr_list)) {
|
||||
list_free(pim_ifp->sec_addr_list);
|
||||
pim_ifp->sec_addr_list = NULL;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
changed = 1;
|
||||
sec_addr->addr = addr;
|
||||
listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int pim_sec_addr_del_all(struct pim_interface *pim_ifp)
|
||||
{
|
||||
int changed = 0;
|
||||
|
||||
if (!pim_ifp->sec_addr_list) {
|
||||
return changed;
|
||||
}
|
||||
if (!list_isempty(pim_ifp->sec_addr_list)) {
|
||||
changed = 1;
|
||||
/* remove all nodes and free up the list itself */
|
||||
list_delete_all_node(pim_ifp->sec_addr_list);
|
||||
list_free(pim_ifp->sec_addr_list);
|
||||
pim_ifp->sec_addr_list = NULL;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int pim_sec_addr_update(struct interface *ifp)
|
||||
{
|
||||
struct pim_interface *pim_ifp = ifp->info;
|
||||
struct connected *ifc;
|
||||
struct listnode *node;
|
||||
struct listnode *nextnode;
|
||||
struct pim_secondary_addr *sec_addr;
|
||||
int changed = 0;
|
||||
|
||||
if (pim_ifp->sec_addr_list) {
|
||||
for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
|
||||
sec_addr->flags |= PIM_SEC_ADDRF_STALE;
|
||||
}
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
|
||||
struct prefix *p = ifc->address;
|
||||
|
||||
if (p->family != AF_INET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pim_ifp->primary_address.s_addr == p->u.prefix4.s_addr) {
|
||||
/* don't add the primary address into the secondary address list */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pim_sec_addr_add(pim_ifp, p->u.prefix4)) {
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (pim_ifp->sec_addr_list) {
|
||||
/* Drop stale entries */
|
||||
for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode, sec_addr)) {
|
||||
if (sec_addr->flags & PIM_SEC_ADDRF_STALE) {
|
||||
pim_sec_addr_del(pim_ifp, sec_addr);
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the list went empty free it up */
|
||||
if (list_isempty(pim_ifp->sec_addr_list)) {
|
||||
list_free(pim_ifp->sec_addr_list);
|
||||
pim_ifp->sec_addr_list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int detect_secondary_address_change(struct interface *ifp,
|
||||
int force_prim_as_any,
|
||||
const char *caller)
|
||||
{
|
||||
struct pim_interface *pim_ifp;
|
||||
int changed;
|
||||
struct pim_interface *pim_ifp = ifp->info;
|
||||
int changed = 0;
|
||||
|
||||
pim_ifp = ifp->info;
|
||||
if (!pim_ifp)
|
||||
return;
|
||||
|
||||
changed = 1; /* true */
|
||||
if (PIM_DEBUG_ZEBRA)
|
||||
zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
|
||||
__PRETTY_FUNCTION__, ifp->name);
|
||||
|
||||
if (!changed) {
|
||||
return;
|
||||
if (force_prim_as_any) {
|
||||
/* if primary address is being forced to zero just flush the
|
||||
* secondary address list */
|
||||
changed = pim_sec_addr_del_all(pim_ifp);
|
||||
} else {
|
||||
/* re-evaluate the secondary address list */
|
||||
changed = pim_sec_addr_update(ifp);
|
||||
}
|
||||
|
||||
if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
|
||||
return;
|
||||
}
|
||||
|
||||
pim_addr_change(ifp);
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void detect_address_change(struct interface *ifp,
|
||||
int force_prim_as_any,
|
||||
const char *caller)
|
||||
{
|
||||
int prim_changed;
|
||||
int changed = 0;
|
||||
struct pim_interface *pim_ifp;
|
||||
|
||||
prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller);
|
||||
if (prim_changed) {
|
||||
/* no need to detect secondary change because
|
||||
the reaction would be the same */
|
||||
pim_ifp = ifp->info;
|
||||
if (!pim_ifp)
|
||||
return;
|
||||
|
||||
if (detect_primary_address_change(ifp, force_prim_as_any, caller)) {
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
detect_secondary_address_change(ifp, caller);
|
||||
if (detect_secondary_address_change(ifp, force_prim_as_any, caller)) {
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
|
||||
if (changed) {
|
||||
if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
|
||||
return;
|
||||
}
|
||||
|
||||
pim_addr_change(ifp);
|
||||
}
|
||||
|
||||
/* XXX: if we have unnumbered interfaces we need to run detect address
|
||||
* address change on all of them when the lo address changes */
|
||||
}
|
||||
|
||||
int pim_update_source_set(struct interface *ifp, struct in_addr source)
|
||||
{
|
||||
struct pim_interface *pim_ifp = ifp->info;
|
||||
|
||||
if (!pim_ifp) {
|
||||
return PIM_IFACE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (pim_ifp->update_source.s_addr == source.s_addr) {
|
||||
return PIM_UPDATE_SOURCE_DUP;
|
||||
}
|
||||
|
||||
pim_ifp->update_source = source;
|
||||
detect_address_change(ifp, 0 /* force_prim_as_any */,
|
||||
__PRETTY_FUNCTION__);
|
||||
|
||||
return PIM_SUCCESS;
|
||||
}
|
||||
|
||||
void pim_if_addr_add(struct connected *ifc)
|
||||
@ -406,6 +583,7 @@ void pim_if_addr_add(struct connected *ifc)
|
||||
if (pim_ifp->mroute_vif_index < 0) {
|
||||
pim_if_add_vif(ifp);
|
||||
}
|
||||
pim_ifchannel_scan_forward_start (ifp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -496,19 +674,59 @@ void pim_if_addr_add_all(struct interface *ifp)
|
||||
struct connected *ifc;
|
||||
struct listnode *node;
|
||||
struct listnode *nextnode;
|
||||
int v4_addrs = 0;
|
||||
int v6_addrs = 0;
|
||||
struct pim_interface *pim_ifp = ifp->info;
|
||||
|
||||
|
||||
/* PIM/IGMP enabled ? */
|
||||
if (!ifp->info)
|
||||
if (!pim_ifp)
|
||||
return;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
|
||||
struct prefix *p = ifc->address;
|
||||
|
||||
if (p->family != AF_INET)
|
||||
continue;
|
||||
{
|
||||
v6_addrs++;
|
||||
continue;
|
||||
}
|
||||
|
||||
v4_addrs++;
|
||||
pim_if_addr_add(ifc);
|
||||
}
|
||||
|
||||
if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
|
||||
{
|
||||
if (PIM_IF_TEST_PIM(pim_ifp->options)) {
|
||||
|
||||
/* Interface has a valid primary address ? */
|
||||
if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
|
||||
|
||||
/* Interface has a valid socket ? */
|
||||
if (pim_ifp->pim_sock_fd < 0) {
|
||||
if (pim_sock_add(ifp)) {
|
||||
zlog_warn("Failure creating PIM socket for interface %s",
|
||||
ifp->name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} /* pim */
|
||||
}
|
||||
if (PIM_MROUTE_IS_ENABLED) {
|
||||
/*
|
||||
* PIM or IGMP is enabled on interface, and there is at least one
|
||||
* address assigned, then try to create a vif_index.
|
||||
*/
|
||||
if (pim_ifp->mroute_vif_index < 0) {
|
||||
pim_if_add_vif(ifp);
|
||||
}
|
||||
pim_ifchannel_scan_forward_start (ifp);
|
||||
}
|
||||
|
||||
pim_rp_setup();
|
||||
pim_rp_check_on_if_add(pim_ifp);
|
||||
}
|
||||
|
||||
void pim_if_addr_del_all(struct interface *ifp)
|
||||
@ -529,6 +747,9 @@ void pim_if_addr_del_all(struct interface *ifp)
|
||||
|
||||
pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
|
||||
}
|
||||
|
||||
pim_rp_setup();
|
||||
pim_i_am_rp_re_evaluate();
|
||||
}
|
||||
|
||||
void pim_if_addr_del_all_igmp(struct interface *ifp)
|
||||
@ -571,17 +792,28 @@ void pim_if_addr_del_all_pim(struct interface *ifp)
|
||||
}
|
||||
}
|
||||
|
||||
static struct in_addr find_first_nonsec_addr(struct interface *ifp)
|
||||
struct in_addr
|
||||
pim_find_primary_addr (struct interface *ifp)
|
||||
{
|
||||
struct connected *ifc;
|
||||
struct listnode *node;
|
||||
struct in_addr addr;
|
||||
int v4_addrs = 0;
|
||||
int v6_addrs = 0;
|
||||
struct pim_interface *pim_ifp = ifp->info;
|
||||
|
||||
if (pim_ifp && PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) {
|
||||
return pim_ifp->update_source;
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
|
||||
struct prefix *p = ifc->address;
|
||||
|
||||
|
||||
if (p->family != AF_INET)
|
||||
continue;
|
||||
{
|
||||
v6_addrs++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
|
||||
zlog_warn("%s: null IPv4 address connected to interface %s",
|
||||
@ -589,22 +821,33 @@ static struct in_addr find_first_nonsec_addr(struct interface *ifp)
|
||||
continue;
|
||||
}
|
||||
|
||||
v4_addrs++;
|
||||
|
||||
if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
|
||||
continue;
|
||||
|
||||
return p->u.prefix4;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have no v4_addrs and v6 is configured
|
||||
* We probably are using unnumbered
|
||||
* So let's grab the loopbacks v4 address
|
||||
* and use that as the primary address
|
||||
*/
|
||||
if (!v4_addrs && v6_addrs && !if_is_loopback (ifp))
|
||||
{
|
||||
struct interface *lo_ifp;
|
||||
lo_ifp = if_lookup_by_name_vrf ("lo", VRF_DEFAULT);
|
||||
if (lo_ifp)
|
||||
return pim_find_primary_addr (lo_ifp);
|
||||
}
|
||||
|
||||
addr.s_addr = PIM_NET_INADDR_ANY;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
struct in_addr pim_find_primary_addr(struct interface *ifp)
|
||||
{
|
||||
return find_first_nonsec_addr(ifp);
|
||||
}
|
||||
|
||||
static int pim_iface_vif_index = 0;
|
||||
|
||||
static int
|
||||
@ -800,9 +1043,9 @@ int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)
|
||||
struct interface *ifp;
|
||||
|
||||
ifp = if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
|
||||
pim_ifp = ifp->info;
|
||||
if (!pim_ifp)
|
||||
if (!ifp || !ifp->info)
|
||||
return -1;
|
||||
pim_ifp = ifp->info;
|
||||
|
||||
return pim_ifp->mroute_vif_index;
|
||||
}
|
||||
@ -899,14 +1142,14 @@ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
|
||||
}
|
||||
|
||||
if (PIM_DEBUG_PIM_TRACE) {
|
||||
char addr_str[100];
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
|
||||
zlog_debug("%s: neighbor not found for address %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
addr_str, ifp->name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
long pim_if_t_suppressed_msec(struct interface *ifp)
|
||||
@ -985,8 +1228,8 @@ static struct igmp_join *igmp_join_new(struct interface *ifp,
|
||||
|
||||
join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
|
||||
if (join_fd < 0) {
|
||||
char group_str[100];
|
||||
char source_str[100];
|
||||
char group_str[INET_ADDRSTRLEN];
|
||||
char source_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
|
||||
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
|
||||
zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
|
||||
@ -995,13 +1238,13 @@ static struct igmp_join *igmp_join_new(struct interface *ifp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
|
||||
ij = XCALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
|
||||
if (!ij) {
|
||||
char group_str[100];
|
||||
char source_str[100];
|
||||
char group_str[INET_ADDRSTRLEN];
|
||||
char source_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
|
||||
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
|
||||
zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
|
||||
zlog_err("%s: XCALLOC(%zu) failure for IGMP group %s source %s on interface %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
sizeof(*ij), group_str, source_str, ifp->name);
|
||||
close(join_fd);
|
||||
@ -1045,8 +1288,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
|
||||
|
||||
ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
|
||||
if (ij) {
|
||||
char group_str[100];
|
||||
char source_str[100];
|
||||
char group_str[INET_ADDRSTRLEN];
|
||||
char source_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
|
||||
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
|
||||
zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
|
||||
@ -1057,8 +1300,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
|
||||
|
||||
ij = igmp_join_new(ifp, group_addr, source_addr);
|
||||
if (!ij) {
|
||||
char group_str[100];
|
||||
char source_str[100];
|
||||
char group_str[INET_ADDRSTRLEN];
|
||||
char source_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
|
||||
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
|
||||
zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
|
||||
@ -1068,8 +1311,8 @@ int pim_if_igmp_join_add(struct interface *ifp,
|
||||
}
|
||||
|
||||
if (PIM_DEBUG_IGMP_EVENTS) {
|
||||
char group_str[100];
|
||||
char source_str[100];
|
||||
char group_str[INET_ADDRSTRLEN];
|
||||
char source_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
|
||||
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
|
||||
zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
|
||||
@ -1106,8 +1349,8 @@ int pim_if_igmp_join_del(struct interface *ifp,
|
||||
|
||||
ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
|
||||
if (!ij) {
|
||||
char group_str[100];
|
||||
char source_str[100];
|
||||
char group_str[INET_ADDRSTRLEN];
|
||||
char source_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
|
||||
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
|
||||
zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
|
||||
@ -1117,14 +1360,13 @@ int pim_if_igmp_join_del(struct interface *ifp,
|
||||
}
|
||||
|
||||
if (close(ij->sock_fd)) {
|
||||
int e = errno;
|
||||
char group_str[100];
|
||||
char source_str[100];
|
||||
char group_str[INET_ADDRSTRLEN];
|
||||
char source_str[INET_ADDRSTRLEN];
|
||||
pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
|
||||
pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
|
||||
zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e));
|
||||
ij->sock_fd, group_str, source_str, ifp->name, errno, safe_strerror(errno));
|
||||
/* warning only */
|
||||
}
|
||||
listnode_delete(pim_ifp->igmp_join_list, ij);
|
||||
@ -1249,3 +1491,40 @@ void pim_if_create_pimreg (void)
|
||||
pim_if_new(pim_regiface, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pim_if_connected_to_source (struct interface *ifp, struct in_addr src)
|
||||
{
|
||||
struct listnode *cnode;
|
||||
struct connected *c;
|
||||
struct prefix p;
|
||||
|
||||
p.family = AF_INET;
|
||||
p.u.prefix4 = src;
|
||||
p.prefixlen = IPV4_MAX_BITLEN;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, c))
|
||||
{
|
||||
if ((c->address->family == AF_INET) &&
|
||||
prefix_match (CONNECTED_PREFIX (c), &p))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct interface *
|
||||
pim_if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id)
|
||||
{
|
||||
struct listnode *ifnode;
|
||||
struct interface *ifp;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
|
||||
{
|
||||
if (pim_if_connected_to_source (ifp, src) && ifp->info)
|
||||
return ifp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
along with this program; see the file COPYING; if not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
|
||||
MA 02110-1301 USA
|
||||
*/
|
||||
*/
|
||||
|
||||
#ifndef PIM_IFACE_H
|
||||
#define PIM_IFACE_H
|
||||
@ -58,12 +58,26 @@ enum pim_interface_type {
|
||||
PIM_INTERFACE_SM
|
||||
};
|
||||
|
||||
enum pim_secondary_addr_flags {
|
||||
PIM_SEC_ADDRF_NONE = 0,
|
||||
PIM_SEC_ADDRF_STALE = (1 << 0)
|
||||
};
|
||||
|
||||
struct pim_secondary_addr {
|
||||
struct in_addr addr;
|
||||
enum pim_secondary_addr_flags flags;
|
||||
};
|
||||
|
||||
struct pim_interface {
|
||||
enum pim_interface_type itype;
|
||||
uint32_t options; /* bit vector */
|
||||
ifindex_t mroute_vif_index;
|
||||
struct in_addr primary_address; /* remember addr to detect change */
|
||||
struct list *sec_addr_list; /* list of struct pim_secondary_addr */
|
||||
struct in_addr update_source; /* user can statically set the primary
|
||||
* address of the interface */
|
||||
|
||||
int igmp_version; /* IGMP version */
|
||||
int igmp_default_robustness_variable; /* IGMPv3 QRV */
|
||||
int igmp_default_query_interval; /* IGMPv3 secs between general queries */
|
||||
int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in dsecs for general queries */
|
||||
@ -106,6 +120,7 @@ struct pim_interface {
|
||||
};
|
||||
|
||||
extern struct interface *pim_regiface;
|
||||
extern struct list *pim_ifchannel_list;
|
||||
/*
|
||||
if default_holdtime is set (>= 0), use it;
|
||||
otherwise default_holdtime is 3.5 * hello_period
|
||||
@ -116,6 +131,7 @@ extern struct interface *pim_regiface;
|
||||
((pim_ifp)->pim_default_holdtime))
|
||||
|
||||
void pim_if_init(void);
|
||||
void pim_if_terminate (void);
|
||||
|
||||
struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim);
|
||||
void pim_if_delete(struct interface *ifp);
|
||||
@ -126,6 +142,8 @@ void pim_if_addr_del_all(struct interface *ifp);
|
||||
void pim_if_addr_del_all_igmp(struct interface *ifp);
|
||||
void pim_if_addr_del_all_pim(struct interface *ifp);
|
||||
|
||||
struct interface *pim_if_lookup_address_vrf (struct in_addr src, vrf_id_t vrf_id);
|
||||
|
||||
int pim_if_add_vif(struct interface *ifp);
|
||||
int pim_if_del_vif(struct interface *ifp);
|
||||
void pim_if_add_vif_all(void);
|
||||
@ -166,4 +184,8 @@ void pim_if_update_join_desired(struct pim_interface *pim_ifp);
|
||||
void pim_if_update_assert_tracking_desired(struct interface *ifp);
|
||||
|
||||
void pim_if_create_pimreg(void);
|
||||
|
||||
int pim_if_connected_to_source (struct interface *ifp, struct in_addr src);
|
||||
int pim_update_source_set(struct interface *ifp, struct in_addr source);
|
||||
|
||||
#endif /* PIM_IFACE_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,6 +24,7 @@
|
||||
#include <zebra.h>
|
||||
|
||||
#include "if.h"
|
||||
#include "prefix.h"
|
||||
|
||||
#include "pim_upstream.h"
|
||||
|
||||
@ -35,7 +36,10 @@ enum pim_ifmembership {
|
||||
enum pim_ifjoin_state {
|
||||
PIM_IFJOIN_NOINFO,
|
||||
PIM_IFJOIN_JOIN,
|
||||
PIM_IFJOIN_PRUNE_PENDING
|
||||
PIM_IFJOIN_PRUNE,
|
||||
PIM_IFJOIN_PRUNE_PENDING,
|
||||
PIM_IFJOIN_PRUNE_TMP,
|
||||
PIM_IFJOIN_PRUNE_PENDING_TMP,
|
||||
};
|
||||
|
||||
enum pim_ifassert_state {
|
||||
@ -66,12 +70,22 @@ struct pim_assert_metric {
|
||||
#define PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(flags) ((flags) |= PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED)
|
||||
#define PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(flags) ((flags) &= ~PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED)
|
||||
|
||||
/*
|
||||
* Flat to tell us if the ifchannel is (S,G,rpt)
|
||||
*/
|
||||
#define PIM_IF_FLAG_MASK_S_G_RPT (1 << 2)
|
||||
#define PIM_IF_FLAG_TEST_S_G_RPT(flags) ((flags) & PIM_IF_FLAG_MASK_S_G_RPT)
|
||||
#define PIM_IF_FLAG_SET_S_G_RPT(flags) ((flags) |= PIM_IF_FLAG_MASK_S_G_RPT)
|
||||
#define PIM_IF_FLAG_UNSET_S_G_RPT(flags) ((flags) &= ~PIM_IF_FLAG_MASK_S_G_RPT)
|
||||
|
||||
/*
|
||||
Per-interface (S,G) state
|
||||
*/
|
||||
struct pim_ifchannel {
|
||||
struct in_addr source_addr; /* (S,G) source key */
|
||||
struct in_addr group_addr; /* (S,G) group key */
|
||||
struct pim_ifchannel *parent;
|
||||
struct list *sources;
|
||||
struct prefix_sg sg;
|
||||
char sg_str[PIM_SG_LEN];
|
||||
struct interface *interface; /* backpointer to interface */
|
||||
uint32_t flags;
|
||||
|
||||
@ -98,33 +112,28 @@ struct pim_ifchannel {
|
||||
|
||||
void pim_ifchannel_free(struct pim_ifchannel *ch);
|
||||
void pim_ifchannel_delete(struct pim_ifchannel *ch);
|
||||
void pim_ifchannel_delete_all (struct interface *ifp);
|
||||
void pim_ifchannel_membership_clear(struct interface *ifp);
|
||||
void pim_ifchannel_delete_on_noinfo(struct interface *ifp);
|
||||
struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp,
|
||||
struct in_addr source_addr,
|
||||
struct in_addr group_addr);
|
||||
struct prefix_sg *sg);
|
||||
struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
|
||||
struct in_addr source_addr,
|
||||
struct in_addr group_addr);
|
||||
struct prefix_sg *sg, int flags);
|
||||
void pim_ifchannel_join_add(struct interface *ifp,
|
||||
struct in_addr neigh_addr,
|
||||
struct in_addr upstream,
|
||||
struct in_addr source_addr,
|
||||
struct in_addr group_addr,
|
||||
struct prefix_sg *sg,
|
||||
uint8_t source_flags,
|
||||
uint16_t holdtime);
|
||||
void pim_ifchannel_prune(struct interface *ifp,
|
||||
struct in_addr upstream,
|
||||
struct in_addr source_addr,
|
||||
struct in_addr group_addr,
|
||||
struct prefix_sg *sg,
|
||||
uint8_t source_flags,
|
||||
uint16_t holdtime);
|
||||
void pim_ifchannel_local_membership_add(struct interface *ifp,
|
||||
struct in_addr source_addr,
|
||||
struct in_addr group_addr);
|
||||
struct prefix_sg *sg);
|
||||
void pim_ifchannel_local_membership_del(struct interface *ifp,
|
||||
struct in_addr source_addr,
|
||||
struct in_addr group_addr);
|
||||
struct prefix_sg *sg);
|
||||
|
||||
void pim_ifchannel_ifjoin_switch(const char *caller,
|
||||
struct pim_ifchannel *ch,
|
||||
@ -140,4 +149,8 @@ void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch);
|
||||
void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch);
|
||||
void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch);
|
||||
|
||||
void pim_ifchannel_scan_forward_start (struct interface *new_ifp);
|
||||
void pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom);
|
||||
|
||||
int pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2);
|
||||
#endif /* PIM_IFCHANNEL_H */
|
||||
|
765
pimd/pim_igmp.c
765
pimd/pim_igmp.c
File diff suppressed because it is too large
Load Diff
@ -51,6 +51,7 @@
|
||||
#define IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET (2)
|
||||
#define IGMP_V3_GROUP_RECORD_GROUP_OFFSET (4)
|
||||
#define IGMP_V3_GROUP_RECORD_SOURCE_OFFSET (8)
|
||||
#define IGMP_CHECKSUM_OFFSET (2)
|
||||
|
||||
/* RFC 3376: 8.1. Robustness Variable - Default: 2 */
|
||||
#define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2)
|
||||
@ -64,6 +65,8 @@
|
||||
/* RFC 3376: 8.8. Last Member Query Interval - Default: 10 deciseconds */
|
||||
#define IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC (10)
|
||||
|
||||
#define IGMP_DEFAULT_VERSION (3)
|
||||
|
||||
struct igmp_join {
|
||||
struct in_addr group_addr;
|
||||
struct in_addr source_addr;
|
||||
@ -97,7 +100,7 @@ struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list,
|
||||
struct interface *ifp);
|
||||
void igmp_sock_delete(struct igmp_sock *igmp);
|
||||
void igmp_sock_free(struct igmp_sock *igmp);
|
||||
|
||||
void igmp_sock_delete_all (struct interface *ifp);
|
||||
int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len);
|
||||
|
||||
void pim_igmp_general_query_on(struct igmp_sock *igmp);
|
||||
@ -151,6 +154,9 @@ struct igmp_group {
|
||||
since sources have their counters) */
|
||||
int group_specific_query_retransmit_count;
|
||||
|
||||
/* compatibility mode - igmp v1, v2 or v3 */
|
||||
int igmp_version;
|
||||
|
||||
struct in_addr group_addr;
|
||||
int group_filtermode_isexcl; /* 0=INCLUDE, 1=EXCLUDE */
|
||||
struct list *group_source_list; /* list of struct igmp_source */
|
||||
@ -175,4 +181,18 @@ void igmp_group_timer_on(struct igmp_group *group,
|
||||
struct igmp_source *
|
||||
source_new (struct igmp_group *group,
|
||||
struct in_addr src_addr);
|
||||
|
||||
void igmp_send_query(int igmp_version,
|
||||
struct igmp_group *group,
|
||||
int fd,
|
||||
const char *ifname,
|
||||
char *query_buf,
|
||||
int query_buf_size,
|
||||
int num_sources,
|
||||
struct in_addr dst_addr,
|
||||
struct in_addr group_addr,
|
||||
int query_max_response_time_dsec,
|
||||
uint8_t s_flag,
|
||||
uint8_t querier_robustness_variable,
|
||||
uint16_t querier_query_interval);
|
||||
#endif /* PIM_IGMP_H */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user