Merge remote-tracking branch 'origin/master' into pr/111

This commit is contained in:
Donald Sharp 2017-01-27 11:44:42 -05:00
commit c016b6c796
170 changed files with 17866 additions and 6920 deletions

View File

@ -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)

View File

@ -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)
@ -1027,6 +1039,10 @@ bgp_attr_unintern_sub (struct attr *attr)
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 ||

View File

@ -93,6 +93,9 @@ struct attr_extra
/* Extended Communities attribute. */
struct ecommunity *ecommunity;
/* Large Communities attribute. */
struct lcommunity *lcommunity;
/* Route-Reflector Cluster attribute */
struct cluster_list *cluster;

View File

@ -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);

View File

@ -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 */

View File

@ -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. */

View File

@ -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"

View File

@ -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
View 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
View 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 */

View File

@ -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")

View File

@ -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 */

View File

@ -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;

View File

@ -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,

View File

@ -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 */

View File

@ -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);
}

View File

@ -188,6 +188,8 @@ 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;

View File

@ -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;
};

View File

@ -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:

File diff suppressed because it is too large Load Diff

View File

@ -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,

View File

@ -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);

View File

@ -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);
}

View File

@ -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 */

View File

@ -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) &&

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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,

View File

@ -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;
}
/*

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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
@ -3274,49 +3322,35 @@ clear_vnc_responses (struct rfapi_local_reg_delete_arg *cda)
* 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);

View File

@ -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"

View File

@ -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;

View File

@ -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 = \

View File

@ -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);

View File

@ -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;
}

View File

@ -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. */

View File

@ -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;}

View File

@ -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++;
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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 */

View 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);
}

View File

@ -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);

View File

@ -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
View 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 */

View File

@ -63,7 +63,12 @@ writen(int fd, const u_char *ptr, int nbytes)
{
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;

View File

@ -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];

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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",

View File

@ -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))

View File

@ -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");

View File

@ -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)

View File

@ -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));

View File

@ -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));

View File

@ -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];

View File

@ -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));

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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 { \

View File

@ -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+

View File

@ -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))

View File

@ -22,6 +22,7 @@
#include <zebra.h>
#include "monotime.h"
#include "linklist.h"
#include "thread.h"
#include "prefix.h"
@ -318,7 +319,7 @@ ospf_timer_dump (struct thread *t, char *buf, size_t size)
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);
}

View File

@ -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 (&current->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);

View File

@ -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))
{

View File

@ -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 *);

View File

@ -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];
}

View File

@ -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 (&current->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. */

View File

@ -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");
@ -1441,10 +1429,8 @@ ospf_spf_calculate_schedule (struct ospf *ospf, ospf_spf_reason_t reason)
return;
}
/* XXX Monotic timers: we only care about relative time here. */
result = tv_sub (recent_relative_time (), ospf->ts_spf);
elapsed = monotime_since (&ospf->ts_spf, NULL) / 1000;
elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000);
ht = ospf->spf_holdtime * ospf->spf_hold_multiplier;
if (ht > ospf->spf_max_holdtime)

View File

@ -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

View File

@ -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)
{

View File

@ -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)

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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__,

View File

@ -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;
}

View File

@ -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

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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