Merge branch 'master' into dev-master

This commit is contained in:
Mitesh Kanjariya 2017-08-28 18:19:03 -07:00 committed by GitHub
commit 09fdc88c8c
176 changed files with 5999 additions and 5677 deletions

View File

@ -5,7 +5,7 @@ include common.am
AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir) -I$(top_builddir)/lib
AM_CFLAGS = $(WERROR)
DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE)
LIBCAP = @LIBCAP@
EXTRA_DIST =
@ -25,6 +25,14 @@ pkginclude_HEADERS =
nodist_pkginclude_HEADERS =
dist_examples_DATA =
## libtool, the self-made GNU scourge
## ... this should fix relinking
## ... and AUTOMAKE_DUMMY is needed to prevent automake from treating this
## as overriding the normal targets...
$(AUTOMAKE_DUMMY)install-moduleLTLIBRARIES: install-libLTLIBRARIES
$(AUTOMAKE_DUMMY)install-binPROGRAMS: install-libLTLIBRARIES
$(AUTOMAKE_DUMMY)install-sbinPROGRAMS: install-libLTLIBRARIES
include lib/subdir.am
include zebra/subdir.am
include qpb/subdir.am

View File

@ -1256,8 +1256,8 @@ void
babel_if_init ()
{
/* initialize interface list */
if_add_hook (IF_NEW_HOOK, babel_if_new_hook);
if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
hook_register_prio(if_add, 0, babel_if_new_hook);
hook_register_prio(if_del, 0, babel_if_delete_hook);
babel_enable_if = vector_init (1);

View File

@ -37,7 +37,6 @@ void babelz_zebra_init(void);
/* we must use a pointer because of zclient.c's functions (new, free). */
struct zclient *zclient;
static int zebra_config_write (struct vty *vty);
/* Debug types */
static struct {
@ -55,118 +54,24 @@ static struct {
{0, 0, NULL}
};
/* Zebra node structure. */
struct cmd_node zebra_node =
{
ZEBRA_NODE,
"%s(config-router)# ",
1 /* vtysh? yes */
};
/* Zebra route add and delete treatment (ipv6). */
/* Zebra route add and delete treatment. */
static int
babel_zebra_read_ipv6 (int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf)
babel_zebra_read_route (int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf)
{
struct stream *s;
struct zapi_ipv6 api;
unsigned long ifindex = -1;
struct in6_addr nexthop;
struct prefix_ipv6 prefix;
struct zapi_route api;
s = zclient->ibuf;
ifindex = 0;
memset (&nexthop, 0, sizeof (struct in6_addr));
memset (&api, 0, sizeof(struct zapi_ipv6));
memset (&prefix, 0, sizeof (struct prefix_ipv6));
if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1;
/* Type, flags, message. */
api.type = stream_getc (s);
api.instance = stream_getw (s);
api.flags = stream_getl (s);
api.message = stream_getc (s);
/* we completely ignore srcdest routes for now. */
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
return 0;
/* IPv6 prefix. */
prefix.family = AF_INET6;
prefix.prefixlen = stream_getc (s);
stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen));
/* Nexthop, ifindex, distance, metric. */
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) {
api.nexthop_num = stream_getc (s);
stream_get (&nexthop, s, sizeof(nexthop));
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) {
api.ifindex_num = stream_getc (s);
ifindex = stream_getl (s);
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
else
api.distance = 0;
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl (s);
else
api.metric = 0;
if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
babel_ipv6_route_add(&api, &prefix, ifindex, &nexthop);
else
babel_ipv6_route_delete(&api, &prefix, ifindex);
return 0;
}
static int
babel_zebra_read_ipv4 (int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf)
{
struct stream *s;
struct zapi_ipv4 api;
unsigned long ifindex = -1;
struct in_addr nexthop;
struct prefix_ipv4 prefix;
s = zclient->ibuf;
ifindex = 0;
memset (&nexthop, 0, sizeof (struct in_addr));
memset (&api, 0, sizeof(struct zapi_ipv4));
memset (&prefix, 0, sizeof (struct prefix_ipv4));
/* Type, flags, message. */
api.type = stream_getc (s);
api.instance = stream_getw (s);
api.flags = stream_getl (s);
api.message = stream_getc (s);
/* IPv6 prefix. */
prefix.family = AF_INET;
prefix.prefixlen = stream_getc (s);
stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen));
/* Nexthop, ifindex, distance, metric. */
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) {
api.nexthop_num = stream_getc (s);
stream_get (&nexthop, s, sizeof(nexthop));
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) {
api.ifindex_num = stream_getc (s);
ifindex = stream_getl (s);
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
else
api.distance = 0;
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl (s);
else
api.metric = 0;
if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD) {
babel_ipv4_route_add(&api, &prefix, ifindex, &nexthop);
if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) {
babel_route_add(&api);
} else {
babel_ipv4_route_delete(&api, &prefix, ifindex);
babel_route_delete(&api);
}
return 0;
@ -310,6 +215,20 @@ debug_babel_config_write (struct vty * vty)
#endif /* NO_DEBUG */
}
DEFUN_NOSH (show_debugging_babel,
show_debugging_babel_cmd,
"show debugging [babel]",
SHOW_STR
DEBUG_STR
"Babel")
{
vty_out(vty, "BABEL debugging status\n");
debug_babel_config_write(vty);
return CMD_SUCCESS;
}
static void
babel_zebra_connected (struct zclient *zclient)
{
@ -328,34 +247,16 @@ void babelz_zebra_init(void)
zclient->interface_down = babel_interface_down;
zclient->interface_address_add = babel_interface_address_add;
zclient->interface_address_delete = babel_interface_address_delete;
zclient->redistribute_route_ipv4_add = babel_zebra_read_ipv4;
zclient->redistribute_route_ipv4_del = babel_zebra_read_ipv4;
zclient->redistribute_route_ipv6_add = babel_zebra_read_ipv6;
zclient->redistribute_route_ipv6_del = babel_zebra_read_ipv6;
zclient->redistribute_route_add = babel_zebra_read_route;
zclient->redistribute_route_del = babel_zebra_read_route;
install_node (&zebra_node, zebra_config_write);
install_element(BABEL_NODE, &babel_redistribute_type_cmd);
install_element(ENABLE_NODE, &debug_babel_cmd);
install_element(ENABLE_NODE, &no_debug_babel_cmd);
install_element(CONFIG_NODE, &debug_babel_cmd);
install_element(CONFIG_NODE, &no_debug_babel_cmd);
}
static int
zebra_config_write (struct vty *vty)
{
if (! zclient->enable)
{
vty_out (vty, "no router zebra\n");
return 1;
}
else if (! vrf_bitmap_check (zclient->redist[AFI_IP][ZEBRA_ROUTE_BABEL], VRF_DEFAULT))
{
vty_out (vty, "router zebra\n");
vty_out (vty, " no redistribute babel\n");
return 1;
}
return 0;
install_element(VIEW_NODE, &show_debugging_babel_cmd);
}
void

View File

@ -331,8 +331,8 @@ babel_main_loop(struct thread *thread)
/* if there is no timeout, we must wait. */
if(timeval_compare(&tv, &babel_now) > 0) {
timeval_minus(&tv, &tv, &babel_now);
debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %ld msecs",
tv.tv_sec * 1000 + tv.tv_usec / 1000);
debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %lld msecs",
(long long)tv.tv_sec * 1000 + tv.tv_usec / 1000);
/* it happens often to have less than 1 ms, it's bad. */
timeval_add_msec(&tv, &tv, 300);
babel_set_timer(&tv);

View File

@ -51,13 +51,8 @@ THE SOFTWARE.
static int
kernel_route_v4(int add, const unsigned char *pref, unsigned short plen,
const unsigned char *gate, int ifindex,
unsigned int metric);
static int
kernel_route_v6(int add, const unsigned char *pref, unsigned short plen,
const unsigned char *gate, int ifindex,
unsigned int metric);
zebra_route(int add, int familt, const unsigned char *pref, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric);
int
kernel_interface_operational(struct interface *interface)
@ -84,7 +79,7 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen,
unsigned int newmetric)
{
int rc;
int ipv4;
int family;
/* Check that the protocol family is consistent. */
if(plen >= 96 && v4mapped(pref)) {
@ -92,46 +87,37 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen,
errno = EINVAL;
return -1;
}
ipv4 = 1;
family = AF_INET;
} else {
if(v4mapped(gate)) {
errno = EINVAL;
return -1;
}
ipv4 = 0;
family = AF_INET6;
}
switch (operation) {
case ROUTE_ADD:
return ipv4 ?
kernel_route_v4(1, pref, plen, gate, ifindex, metric):
kernel_route_v6(1, pref, plen, gate, ifindex, metric);
return zebra_route(1, family, pref, plen, gate, ifindex, metric);
break;
case ROUTE_FLUSH:
return ipv4 ?
kernel_route_v4(0, pref, plen, gate, ifindex, metric):
kernel_route_v6(0, pref, plen, gate, ifindex, metric);
return zebra_route(0, family, pref, plen, gate, ifindex, metric);
break;
case ROUTE_MODIFY:
if(newmetric == metric && memcmp(newgate, gate, 16) == 0 &&
newifindex == ifindex)
return 0;
debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new.");
rc = ipv4 ?
kernel_route_v4(0, pref, plen, gate, ifindex, metric):
kernel_route_v6(0, pref, plen, gate, ifindex, metric);
rc = zebra_route(0, family, pref, plen, gate, ifindex, metric);
if (rc < 0)
return -1;
rc = ipv4 ?
kernel_route_v4(1, pref, plen, newgate, newifindex, newmetric):
kernel_route_v6(1, pref, plen, newgate, newifindex, newmetric);
rc = zebra_route(1, family, pref, plen, newgate, newifindex,
newmetric);
return rc;
break;
default:
zlog_err("this should never appens (false value - kernel_route)");
zlog_err("this should never happen (false value - kernel_route)");
assert(0);
exit(1);
break;
@ -139,110 +125,81 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen,
}
static int
kernel_route_v4(int add,
const unsigned char *pref, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric)
zebra_route(int add, int family, const unsigned char *pref, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric)
{
struct zapi_route api; /* quagga's communication system */
struct prefix quagga_prefix; /* quagga's prefix */
struct in_addr babel_prefix_addr; /* babeld's prefix addr */
struct nexthop nexthop; /* next router to go */
struct nexthop *nexthop_pointer = &nexthop; /* it's an array! */
union g_addr babel_prefix_addr; /* babeld's prefix addr */
struct zapi_nexthop *api_nh; /* next router to go - no ECMP */
api_nh = &api.nexthops[0];
/* convert to be understandable by quagga */
/* convert given addresses */
uchar_to_inaddr(&babel_prefix_addr, pref);
uchar_to_inaddr(&nexthop.gate.ipv4, gate);
switch (family) {
case AF_INET:
uchar_to_inaddr(&babel_prefix_addr.ipv4, pref);
break;
case AF_INET6:
uchar_to_in6addr(&babel_prefix_addr.ipv6, pref);
break;
}
/* make prefix structure */
memset (&quagga_prefix, 0, sizeof(quagga_prefix));
quagga_prefix.family = AF_INET;
IPV4_ADDR_COPY (&quagga_prefix.u.prefix4, &babel_prefix_addr);
quagga_prefix.prefixlen = plen - 96; /* our plen is for v4mapped's addr */
quagga_prefix.family = family;
switch (family) {
case AF_INET:
IPV4_ADDR_COPY (&quagga_prefix.u.prefix4, &babel_prefix_addr.ipv4);
/* our plen is for v4mapped's addr */
quagga_prefix.prefixlen = plen - 96;
break;
case AF_INET6:
IPV6_ADDR_COPY (&quagga_prefix.u.prefix6, &babel_prefix_addr.ipv6);
quagga_prefix.prefixlen = plen;
break;
}
apply_mask(&quagga_prefix);
memset(&api, 0, sizeof(api));
api.type = ZEBRA_ROUTE_BABEL;
api.flags = 0;
api.message = 0;
api.instance = 0;
api.safi = SAFI_UNICAST;
api.vrf_id = VRF_DEFAULT;
api.prefix = quagga_prefix;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
if(metric >= KERNEL_INFINITY) {
api.flags = ZEBRA_FLAG_REJECT;
api.nexthop_num = 0;
} else {
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
api.nexthop = &nexthop_pointer;
nexthop.ifindex = ifindex;
if (IPV4_ADDR_SAME (&nexthop.gate.ipv4, &quagga_prefix.u.prefix4) &&
quagga_prefix.prefixlen == 32) {
nexthop.type = NEXTHOP_TYPE_IFINDEX;
} else {
nexthop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
api_nh->ifindex = ifindex;
switch (family) {
case AF_INET:
uchar_to_inaddr(&api_nh->gate.ipv4, gate);
if (IPV4_ADDR_SAME (&api_nh->gate.ipv4, &quagga_prefix.u.prefix4) &&
quagga_prefix.prefixlen == 32) {
api_nh->type = NEXTHOP_TYPE_IFINDEX;
} else {
api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
}
break;
case AF_INET6:
uchar_to_in6addr(&api_nh->gate.ipv6, gate);
/* difference to IPv4: always leave the linklocal as nexthop */
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
break;
}
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = metric;
}
debugf(BABEL_DEBUG_ROUTE, "%s route (ipv4) to zebra",
add ? "adding" : "removing" );
return zapi_route (add ? ZEBRA_IPV4_ROUTE_ADD :
ZEBRA_IPV4_ROUTE_DELETE,
zclient, &quagga_prefix, NULL, &api);
}
static int
kernel_route_v6(int add, const unsigned char *pref, unsigned short plen,
const unsigned char *gate, int ifindex, unsigned int metric)
{
struct zapi_route api; /* quagga's communication system */
struct prefix quagga_prefix; /* quagga's prefix */
struct in6_addr babel_prefix_addr; /* babeld's prefix addr */
struct nexthop nexthop; /* next router to go */
struct nexthop *nexthop_pointer = &nexthop;
/* convert to be understandable by quagga */
/* convert given addresses */
uchar_to_in6addr(&babel_prefix_addr, pref);
uchar_to_in6addr(&nexthop.gate.ipv6, gate);
/* make prefix structure */
memset (&quagga_prefix, 0, sizeof(quagga_prefix));
quagga_prefix.family = AF_INET6;
IPV6_ADDR_COPY (&quagga_prefix.u.prefix6, &babel_prefix_addr);
quagga_prefix.prefixlen = plen;
apply_mask(&quagga_prefix);
memset(&api, 0, sizeof(api));
api.type = ZEBRA_ROUTE_BABEL;
api.flags = 0;
api.message = 0;
api.instance = 0;
api.safi = SAFI_UNICAST;
api.vrf_id = VRF_DEFAULT;
if(metric >= KERNEL_INFINITY) {
api.flags = ZEBRA_FLAG_REJECT;
api.nexthop_num = 0;
} else {
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
api.nexthop = &nexthop_pointer;
nexthop.ifindex = ifindex;
/* difference to IPv4: always leave the linklocal as nexthop */
nexthop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = metric;
}
debugf(BABEL_DEBUG_ROUTE, "%s route (ipv6) to zebra",
add ? "adding" : "removing" );
return zapi_route (add ? ZEBRA_IPV6_ROUTE_ADD :
ZEBRA_IPV6_ROUTE_DELETE,
zclient, &quagga_prefix, NULL, &api);
debugf(BABEL_DEBUG_ROUTE, "%s route (%s) to zebra",
add ? "adding" : "removing",
(family == AF_INET) ? "ipv4" : "ipv6");
return zclient_route_send (add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
zclient, &api);
}
int

View File

@ -391,7 +391,7 @@ parse_packet(const unsigned char *from, struct interface *ifp,
} else if(type == MESSAGE_HELLO) {
unsigned short seqno, interval;
int changed;
unsigned int timestamp;
unsigned int timestamp = 0;
DO_NTOHS(seqno, message + 4);
DO_NTOHS(interval, message + 6);
debugf(BABEL_DEBUG_COMMON,"Received hello %d (%d) from %s on %s.",

View File

@ -43,63 +43,54 @@ static int numxroutes = 0, maxxroutes = 0;
/* Add redistributed route to Babel table. */
int
babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
unsigned int ifindex, struct in_addr *nexthop)
babel_route_add (struct zapi_route *api)
{
unsigned char uchar_prefix[16];
inaddr_to_uchar(uchar_prefix, &prefix->prefix);
debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route coming from Zebra.");
xroute_add_new_route(uchar_prefix, prefix->prefixlen + 96,
api->metric, ifindex, 0, 1);
switch (api->prefix.family) {
case AF_INET:
inaddr_to_uchar(uchar_prefix, &api->prefix.u.prefix4);
debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route coming from Zebra.");
xroute_add_new_route(uchar_prefix, api->prefix.prefixlen + 96,
api->metric, api->nexthops[0].ifindex, 0, 1);
break;
case AF_INET6:
in6addr_to_uchar(uchar_prefix, &api->prefix.u.prefix6);
debugf(BABEL_DEBUG_ROUTE, "Adding new ipv6 route coming from Zebra.");
xroute_add_new_route(uchar_prefix, api->prefix.prefixlen,
api->metric, api->nexthops[0].ifindex, 0, 1);
break;
}
return 0;
}
/* Remove redistributed route from Babel table. */
int
babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
unsigned int ifindex)
babel_route_delete (struct zapi_route *api)
{
unsigned char uchar_prefix[16];
struct xroute *xroute = NULL;
inaddr_to_uchar(uchar_prefix, &prefix->prefix);
xroute = find_xroute(uchar_prefix, prefix->prefixlen + 96);
if (xroute != NULL) {
debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra).");
flush_xroute(xroute);
switch (api->prefix.family) {
case AF_INET:
inaddr_to_uchar(uchar_prefix, &api->prefix.u.prefix4);
xroute = find_xroute(uchar_prefix, api->prefix.prefixlen + 96);
if (xroute != NULL) {
debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra).");
flush_xroute(xroute);
}
break;
case AF_INET6:
in6addr_to_uchar(uchar_prefix, &api->prefix.u.prefix6);
xroute = find_xroute(uchar_prefix, api->prefix.prefixlen);
if (xroute != NULL) {
debugf(BABEL_DEBUG_ROUTE, "Removing ipv6 route (from zebra).");
flush_xroute(xroute);
}
break;
}
return 0;
}
/* Add redistributed route to Babel table. */
int
babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
unsigned int ifindex, struct in6_addr *nexthop)
{
unsigned char uchar_prefix[16];
in6addr_to_uchar(uchar_prefix, &prefix->prefix);
debugf(BABEL_DEBUG_ROUTE, "Adding new route coming from Zebra.");
xroute_add_new_route(uchar_prefix, prefix->prefixlen, api->metric, ifindex,
0, 1);
return 0;
}
/* Remove redistributed route from Babel table. */
int
babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
unsigned int ifindex)
{
unsigned char uchar_prefix[16];
struct xroute *xroute = NULL;
in6addr_to_uchar(uchar_prefix, &prefix->prefix);
xroute = find_xroute(uchar_prefix, prefix->prefixlen);
if (xroute != NULL) {
debugf(BABEL_DEBUG_ROUTE, "Removing route (from zebra).");
flush_xroute(xroute);
}
return 0;
}

View File

@ -36,14 +36,8 @@ struct xroute_stream;
struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen);
void flush_xroute(struct xroute *xroute);
int babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
unsigned int ifindex, struct in_addr *nexthop);
int babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
unsigned int ifindex);
int babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
unsigned int ifindex, struct in6_addr *nexthop);
int babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
unsigned int ifindex);
int babel_route_add (struct zapi_route *api);
int babel_route_delete (struct zapi_route *api);
int xroutes_estimate(void);
struct xroute_stream *xroute_stream(void);
struct xroute *xroute_stream_next(struct xroute_stream *stream);

View File

@ -72,7 +72,7 @@ struct bgp_attr_encap_subtlv {
unsigned long refcnt;
uint16_t type;
uint16_t length;
uint8_t value[1]; /* will be extended */
uint8_t value[0]; /* will be extended */
};
#if ENABLE_BGP_VNC

View File

@ -1615,12 +1615,12 @@ DEFUN (no_debug_bgp,
return CMD_SUCCESS;
}
DEFUN (show_debugging_bgp,
show_debugging_bgp_cmd,
"show debugging bgp",
SHOW_STR
DEBUG_STR
BGP_STR)
DEFUN_NOSH (show_debugging_bgp,
show_debugging_bgp_cmd,
"show debugging [bgp]",
SHOW_STR
DEBUG_STR
BGP_STR)
{
vty_out(vty, "BGP debugging status:\n");

View File

@ -140,11 +140,8 @@ __attribute__((__noreturn__)) void sigint(void)
{
zlog_notice("Terminating on signal");
if (!retain_mode) {
if (!retain_mode)
bgp_terminate();
if (bgpd_privs.user) /* NULL if skip_runas flag set */
zprivs_terminate(&bgpd_privs);
}
bgp_exit(0);
@ -172,13 +169,12 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
/* it only makes sense for this to be called on a clean exit */
assert(status == 0);
frr_early_fini();
bfd_gbl_exit();
bgp_close();
if (retain_mode)
if_add_hook(IF_DELETE_HOOK, NULL);
/* reverse bgp_master_init */
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
bgp_delete(bgp);
@ -214,24 +210,15 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
community_list_terminate(bgp_clist);
bgp_vrf_terminate();
cmd_terminate();
vty_terminate();
#if ENABLE_BGP_VNC
vnc_zebra_destroy();
#endif
bgp_zebra_destroy();
/* reverse bgp_master_init */
if (bm->master)
thread_master_free(bm->master);
closezlog();
list_delete(bm->bgp);
memset(bm, 0, sizeof(*bm));
if (bgp_debug_count())
log_memstats_stderr("bgpd");
frr_fini();
exit(status);
}

View File

@ -20,6 +20,7 @@
*/
#include <zebra.h>
#include <math.h>
#include "prefix.h"
#include "linklist.h"
@ -2001,18 +2002,15 @@ int bgp_zebra_has_route_changed(struct bgp_node *rn, struct bgp_info *selected)
struct bgp_process_queue {
struct bgp *bgp;
struct bgp_node *rn;
afi_t afi;
safi_t safi;
STAILQ_HEAD(, bgp_node)pqueue;
#define BGP_PROCESS_QUEUE_EOIU_MARKER (1 << 0)
unsigned int flags;
unsigned int queued;
};
static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
afi_t afi, safi_t safi)
{
struct bgp_process_queue *pq = data;
struct bgp *bgp = pq->bgp;
struct bgp_node *rn = pq->rn;
afi_t afi = pq->afi;
safi_t safi = pq->safi;
struct prefix *p = &rn->p;
struct bgp_info *new_select;
struct bgp_info *old_select;
@ -2033,7 +2031,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
bgp->main_peers_update_hold = 0;
bgp_start_routeadv(bgp);
return WQ_SUCCESS;
return;
}
/* Best path selection. */
@ -2045,11 +2043,9 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
/* Do we need to allocate or free labels?
* Right now, since we only deal with per-prefix labels, it is not
* necessary to do this upon changes to best path except if the label
* index changes.
* NOTE: This is only relevant for the default instance.
* index changes
*/
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
&& safi == SAFI_UNICAST) {
if (bgp->allocate_mpls_labels[afi][safi]) {
if (new_select) {
if (!old_select
|| bgp_label_index_differs(new_select, old_select)
@ -2070,8 +2066,11 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
} else
bgp_register_for_label(rn, new_select);
}
} else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
} else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
bgp_unregister_for_label(rn);
}
} else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
bgp_unregister_for_label(rn);
}
/* If best route remains the same and this is not due to user-initiated
@ -2115,7 +2114,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
}
UNSET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
return WQ_SUCCESS;
return;
}
/* If the user did "clear ip bgp prefix x.x.x.x" this flag will be set
@ -2193,21 +2192,42 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
bgp_info_reap(rn, old_select);
UNSET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
return;
}
static wq_item_status bgp_process_wq(struct work_queue *wq, void *data)
{
struct bgp_process_queue *pqnode = data;
struct bgp *bgp = pqnode->bgp;
struct bgp_table *table;
struct bgp_node *rn, *nrn;
/* eoiu marker */
if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER)) {
bgp_process_main_one(bgp, NULL, 0, 0);
return WQ_SUCCESS;
}
STAILQ_FOREACH_SAFE(rn, &pqnode->pqueue, pq, nrn) {
table = bgp_node_table(rn);
bgp_process_main_one(bgp, rn, table->afi, table->safi);
bgp_unlock_node(rn);
bgp_table_unlock(table);
}
return WQ_SUCCESS;
}
static void bgp_processq_del(struct work_queue *wq, void *data)
{
struct bgp_process_queue *pq = data;
struct bgp_table *table;
struct bgp_process_queue *pqnode = data;
bgp_unlock(pq->bgp);
if (pq->rn) {
table = bgp_node_table(pq->rn);
bgp_unlock_node(pq->rn);
bgp_table_unlock(table);
}
XFREE(MTYPE_BGP_PROCESS_QUEUE, pq);
bgp_unlock(pqnode->bgp);
XFREE(MTYPE_BGP_PROCESS_QUEUE, pqnode);
}
void bgp_process_queue_init(void)
@ -2222,7 +2242,7 @@ void bgp_process_queue_init(void)
}
}
bm->process_main_queue->spec.workfunc = &bgp_process_main;
bm->process_main_queue->spec.workfunc = &bgp_process_wq;
bm->process_main_queue->spec.del_item_data = &bgp_processq_del;
bm->process_main_queue->spec.max_retries = 0;
bm->process_main_queue->spec.hold = 50;
@ -2230,31 +2250,56 @@ void bgp_process_queue_init(void)
bm->process_main_queue->spec.yield = 50 * 1000L;
}
static struct bgp_process_queue *bgp_process_queue_work(struct work_queue *wq,
struct bgp *bgp)
{
struct bgp_process_queue *pqnode;
pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE, sizeof(struct bgp_process_queue));
/* unlocked in bgp_processq_del */
pqnode->bgp = bgp_lock(bgp);
STAILQ_INIT(&pqnode->pqueue);
work_queue_add(wq, pqnode);
return pqnode;
}
void bgp_process(struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
{
#define ARBITRARY_PROCESS_QLEN 10000
struct work_queue *wq = bm->process_main_queue;
struct bgp_process_queue *pqnode;
/* already scheduled for processing? */
if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED))
return;
if (bm->process_main_queue == NULL)
if (wq == NULL)
return;
pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE,
sizeof(struct bgp_process_queue));
if (!pqnode)
return;
/* Add route nodes to an existing work queue item until reaching the
limit only if is from the same BGP view and it's not an EOIU marker */
if (work_queue_item_count(wq)) {
struct work_queue_item *item = work_queue_last_item(wq);
pqnode = item->data;
/* all unlocked in bgp_processq_del */
if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) ||
pqnode->bgp != bgp || pqnode->queued >= ARBITRARY_PROCESS_QLEN)
pqnode = bgp_process_queue_work(wq, bgp);
} else
pqnode = bgp_process_queue_work(wq, bgp);
/* all unlocked in bgp_process_wq */
bgp_table_lock(bgp_node_table(rn));
pqnode->rn = bgp_lock_node(rn);
pqnode->bgp = bgp;
bgp_lock(bgp);
pqnode->afi = afi;
pqnode->safi = safi;
work_queue_add(bm->process_main_queue, pqnode);
SET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
bgp_lock_node(rn);
STAILQ_INSERT_TAIL(&pqnode->pqueue, rn, pq);
pqnode->queued++;
return;
}
@ -2265,15 +2310,9 @@ void bgp_add_eoiu_mark(struct bgp *bgp)
if (bm->process_main_queue == NULL)
return;
pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE,
sizeof(struct bgp_process_queue));
if (!pqnode)
return;
pqnode = bgp_process_queue_work(bm->process_main_queue, bgp);
pqnode->rn = NULL;
pqnode->bgp = bgp;
bgp_lock(bgp);
work_queue_add(bm->process_main_queue, pqnode);
SET_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER);
}
static int bgp_maximum_prefix_restart_timer(struct thread *thread)
@ -6050,8 +6089,7 @@ DEFUN (no_ipv6_aggregate_address,
/* Redistribute route treatment. */
void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
const struct in_addr *nexthop,
const struct in6_addr *nexthop6, unsigned int ifindex,
const union g_addr *nexthop, unsigned int ifindex,
u_int32_t metric, u_char type, u_short instance,
route_tag_t tag)
{
@ -6067,14 +6105,17 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
/* Make default attribute. */
bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE);
if (nexthop)
attr.nexthop = *nexthop;
attr.nh_ifindex = ifindex;
if (nexthop6) {
attr.mp_nexthop_global = *nexthop6;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
if (nexthop) {
switch (p->family) {
case AF_INET:
attr.nexthop = nexthop->ipv4;
break;
case AF_INET6:
attr.mp_nexthop_global = nexthop->ipv6;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
}
}
attr.nh_ifindex = ifindex;
attr.med = metric;
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
@ -8002,7 +8043,8 @@ static int bgp_show_community_list(struct vty *vty, struct bgp *bgp,
static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
const char *prefix, afi_t afi, safi_t safi,
enum bgp_show_type type);
static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi,
static int bgp_show_regexp(struct vty *vty, struct bgp *bgp,
const char *regstr, afi_t afi,
safi_t safi, enum bgp_show_type type);
static int bgp_show_community(struct vty *vty, struct bgp *bgp, int argc,
struct cmd_token **argv, int exact, afi_t afi,
@ -8820,32 +8862,28 @@ DEFUN (show_ip_bgp_large_community,
static int bgp_table_stats(struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi);
/* BGP route print out function. */
/* BGP route print out function without JSON */
DEFUN (show_ip_bgp,
show_ip_bgp_cmd,
"show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]\
[<\
cidr-only\
|dampening <flap-statistics|dampened-paths|parameters>\
|route-map WORD\
|prefix-list WORD\
|filter-list WORD\
|statistics\
|community [<AA:NN|local-AS|no-advertise|no-export> [exact-match]]\
|community-list <(1-500)|WORD> [exact-match]\
|A.B.C.D/M longer-prefixes\
|X:X::X:X/M longer-prefixes>\
] [json]",
<dampening <parameters>\
|route-map WORD\
|prefix-list WORD\
|filter-list WORD\
|statistics\
|community <AA:NN|local-AS|no-advertise|no-export> [exact-match]\
|community-list <(1-500)|WORD> [exact-match]\
|A.B.C.D/M longer-prefixes\
|X:X::X:X/M longer-prefixes\
>",
SHOW_STR
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
"Display only routes with non-natural netmasks\n"
"Display detailed information about dampening\n"
"Display flap statistics of routes\n"
"Display paths suppressed due to dampening\n"
"Display detail of configured dampening parameters\n"
"Display routes matching the route-map\n"
"A route-map to match on\n"
@ -8867,13 +8905,11 @@ DEFUN (show_ip_bgp,
"IPv4 prefix\n"
"Display route and more specific routes\n"
"IPv6 prefix\n"
"Display route and more specific routes\n"
JSON_STR)
"Display route and more specific routes\n")
{
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
int exact_match = 0;
enum bgp_show_type sh_type = bgp_show_type_normal;
struct bgp *bgp = NULL;
int idx = 0;
@ -8882,23 +8918,8 @@ DEFUN (show_ip_bgp,
if (!idx)
return CMD_WARNING;
int uj = use_json(argc, argv);
if (uj)
argc--;
if (argv_find(argv, argc, "cidr-only", &idx))
return bgp_show(vty, bgp, afi, safi, bgp_show_type_cidr_only,
NULL, uj);
if (argv_find(argv, argc, "dampening", &idx)) {
if (argv_find(argv, argc, "dampened-paths", &idx))
return bgp_show(vty, bgp, afi, safi,
bgp_show_type_dampend_paths, NULL, uj);
else if (argv_find(argv, argc, "flap-statistics", &idx))
return bgp_show(vty, bgp, afi, safi,
bgp_show_type_flap_statistics, NULL,
uj);
else if (argv_find(argv, argc, "parameters", &idx))
if (argv_find(argv, argc, "parameters", &idx))
return bgp_show_dampening_parameters(vty, afi, safi);
}
@ -8927,10 +8948,6 @@ DEFUN (show_ip_bgp,
return bgp_show_community(vty, bgp, argc, argv,
exact_match, afi, safi);
}
/* show all communities */
else
return bgp_show(vty, bgp, afi, safi,
bgp_show_type_community_all, NULL, uj);
}
if (argv_find(argv, argc, "community-list", &idx)) {
@ -8947,6 +8964,66 @@ DEFUN (show_ip_bgp,
safi,
bgp_show_type_prefix_longer);
return CMD_WARNING;
}
/* BGP route print out function with JSON */
DEFUN (show_ip_bgp_json,
show_ip_bgp_json_cmd,
"show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]\
[<\
cidr-only\
|dampening <flap-statistics|dampened-paths>\
|community \
>] [json]",
SHOW_STR
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
"Display only routes with non-natural netmasks\n"
"Display detailed information about dampening\n"
"Display flap statistics of routes\n"
"Display paths suppressed due to dampening\n"
"Display routes matching the communities\n"
JSON_STR)
{
afi_t afi = AFI_IP6;
safi_t safi = SAFI_UNICAST;
enum bgp_show_type sh_type = bgp_show_type_normal;
struct bgp *bgp = NULL;
int idx = 0;
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp);
if (!idx)
return CMD_WARNING;
int uj = use_json(argc, argv);
if (uj)
argc--;
if (argv_find(argv, argc, "cidr-only", &idx))
return bgp_show(vty, bgp, afi, safi, bgp_show_type_cidr_only,
NULL, uj);
if (argv_find(argv, argc, "dampening", &idx)) {
if (argv_find(argv, argc, "dampened-paths", &idx))
return bgp_show(vty, bgp, afi, safi,
bgp_show_type_dampend_paths, NULL, uj);
else if (argv_find(argv, argc, "flap-statistics", &idx))
return bgp_show(vty, bgp, afi, safi,
bgp_show_type_flap_statistics, NULL,
uj);
}
if (argv_find(argv, argc, "community", &idx)) {
/* show all communities */
return bgp_show(vty, bgp, afi, safi,
bgp_show_type_community_all, NULL, uj);
}
if (safi == SAFI_MPLS_VPN)
return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_normal,
NULL, 0, uj);
@ -9056,7 +9133,7 @@ DEFUN (show_ip_bgp_regexp,
idx++;
char *regstr = argv_concat(argv, argc, idx);
int rc = bgp_show_regexp(vty, (const char *)regstr, afi, safi,
int rc = bgp_show_regexp(vty, bgp, (const char *)regstr, afi, safi,
bgp_show_type_regexp);
XFREE(MTYPE_TMP, regstr);
return rc;
@ -9091,7 +9168,8 @@ DEFUN (show_ip_bgp_instance_all,
return CMD_SUCCESS;
}
static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi,
static int bgp_show_regexp(struct vty *vty, struct bgp *bgp,
const char *regstr, afi_t afi,
safi_t safi, enum bgp_show_type type)
{
regex_t *regex;
@ -9103,7 +9181,7 @@ static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi,
return CMD_WARNING;
}
rc = bgp_show(vty, NULL, afi, safi, type, regex, 0);
rc = bgp_show(vty, bgp, afi, safi, type, regex, 0);
bgp_regex_free(regex);
return rc;
}
@ -9332,6 +9410,7 @@ static const char *table_stats_strs[] = {
struct bgp_table_stats {
struct bgp_table *table;
unsigned long long counts[BGP_STATS_MAX];
double total_space;
};
#if 0
@ -9400,8 +9479,8 @@ static int bgp_table_stats_walker(struct thread *t)
ts->counts[BGP_STATS_UNAGGREGATEABLE]++;
/* announced address space */
if (space)
ts->counts[BGP_STATS_SPACE] +=
1 << (space - rn->p.prefixlen);
ts->total_space += pow(2.0,
space - rn->p.prefixlen);
} else if (prn->info)
ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++;
@ -9511,31 +9590,26 @@ static int bgp_table_stats(struct vty *vty, struct bgp *bgp, afi_t afi,
break;
case BGP_STATS_SPACE:
vty_out(vty, "%-30s: ", table_stats_strs[i]);
vty_out(vty, "%12llu\n", ts.counts[i]);
if (ts.counts[BGP_STATS_MAXBITLEN] < 9)
break;
vty_out(vty, "%30s: ", "%% announced ");
vty_out(vty, "%12.2f\n",
100 * (float)ts.counts[BGP_STATS_SPACE]
/ (float)((uint64_t)1UL
<< ts.counts
[BGP_STATS_MAXBITLEN]));
vty_out(vty, "%30s: ", "/8 equivalent ");
vty_out(vty, "%12.2f\n",
(float)ts.counts[BGP_STATS_SPACE]
/ (float)(1UL
<< (ts.counts
[BGP_STATS_MAXBITLEN]
- 8)));
if (ts.counts[BGP_STATS_MAXBITLEN] < 25)
break;
vty_out(vty, "%30s: ", "/24 equivalent ");
vty_out(vty, "%12.2f",
(float)ts.counts[BGP_STATS_SPACE]
/ (float)(1UL
<< (ts.counts
[BGP_STATS_MAXBITLEN]
- 24)));
vty_out(vty, "%12g\n", ts.total_space);
if (afi == AFI_IP6) {
vty_out(vty, "%30s: ", "/32 equivalent ");
vty_out(vty, "%12g\n",
ts.total_space * pow(2.0, -128+32));
vty_out(vty, "%30s: ", "/48 equivalent ");
vty_out(vty, "%12g\n",
ts.total_space * pow(2.0, -128+48));
} else {
vty_out(vty, "%30s: ", "% announced ");
vty_out(vty, "%12.2f\n",
ts.total_space * 100. * pow(2.0, -32));
vty_out(vty, "%30s: ", "/8 equivalent ");
vty_out(vty, "%12.2f\n",
ts.total_space * pow(2.0, -32+8));
vty_out(vty, "%30s: ", "/24 equivalent ");
vty_out(vty, "%12.2f\n",
ts.total_space * pow(2.0, -32+24));
}
break;
default:
vty_out(vty, "%-30s: ", table_stats_strs[i]);
@ -11265,6 +11339,7 @@ void bgp_route_init(void)
/* IPv4 labeled-unicast configuration. */
install_element(VIEW_NODE, &show_ip_bgp_instance_all_cmd);
install_element(VIEW_NODE, &show_ip_bgp_cmd);
install_element(VIEW_NODE, &show_ip_bgp_json_cmd);
install_element(VIEW_NODE, &show_ip_bgp_route_cmd);
install_element(VIEW_NODE, &show_ip_bgp_regexp_cmd);

View File

@ -22,6 +22,7 @@
#define _QUAGGA_BGP_ROUTE_H
#include "queue.h"
#include "nexthop.h"
#include "bgp_table.h"
struct bgp_nexthop_cache;
@ -328,8 +329,7 @@ extern int bgp_nlri_parse_ip(struct peer *, struct attr *, struct bgp_nlri *);
extern int bgp_maximum_prefix_overflow(struct peer *, afi_t, safi_t, int);
extern void bgp_redistribute_add(struct bgp *, struct prefix *,
const struct in_addr *,
const struct in6_addr *, unsigned int ifindex,
const union g_addr *, unsigned int ifindex,
u_int32_t, u_char, u_short, route_tag_t);
extern void bgp_redistribute_delete(struct bgp *, struct prefix *, u_char,
u_short);

View File

@ -23,6 +23,7 @@
#include "mpls.h"
#include "table.h"
#include "queue.h"
struct bgp_table {
/* afi/safi of this table */
@ -52,6 +53,8 @@ struct bgp_node {
struct bgp_node *prn;
STAILQ_ENTRY(bgp_node) pq;
mpls_label_t local_label;
uint64_t version;

View File

@ -6145,6 +6145,8 @@ DEFUN (clear_ip_bgp_all,
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
"Clear all peers\n"
"BGP neighbor address to clear\n"
"BGP IPv6 neighbor to clear\n"
@ -6153,8 +6155,6 @@ DEFUN (clear_ip_bgp_all,
"Clear all external peers\n"
"Clear all members of peer-group\n"
"BGP peer-group name\n"
BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
BGP_SOFT_STR
BGP_SOFT_IN_STR
BGP_SOFT_OUT_STR
@ -7071,26 +7071,6 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
return CMD_SUCCESS;
}
/*
* Return if we have a peer configured to use this afi/safi
*/
static int bgp_show_summary_afi_safi_peer_exists(struct bgp *bgp, int afi,
int safi)
{
struct listnode *node;
struct peer *peer;
for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
continue;
if (peer->afc[afi][safi])
return 1;
}
return 0;
}
static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
int safi, u_char use_json,
json_object *json)
@ -7109,8 +7089,7 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
if (safi_wildcard)
safi = 1; /* SAFI_UNICAST */
while (safi < SAFI_MAX) {
if (bgp_show_summary_afi_safi_peer_exists(bgp, afi,
safi)) {
if (bgp_afi_safi_peer_exists(bgp, afi, safi)) {
json_output = true;
if (is_wildcard) {
/*

View File

@ -58,11 +58,6 @@
/* All information about zebra. */
struct zclient *zclient = NULL;
/* Growable buffer for nexthops sent to zebra */
struct stream *bgp_nexthop_buf = NULL;
struct stream *bgp_ifindices_buf = NULL;
struct stream *bgp_label_buf = NULL;
/* These array buffers are used in making a copy of the attributes for
route-map apply. Arrays are being used here to minimize mallocs and
frees for the temporary copy of the attributes.
@ -559,75 +554,36 @@ static int bgp_interface_vrf_update(int command, struct zclient *zclient,
}
/* Zebra route add and delete treatment. */
static int zebra_read_ipv4(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
static int zebra_read_route(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct stream *s;
struct zapi_ipv4 api;
struct in_addr nexthop;
struct prefix_ipv4 p;
struct zapi_route api;
union g_addr nexthop;
unsigned int ifindex;
int i;
int add, i;
struct bgp *bgp;
bgp = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp)
return 0;
s = zclient->ibuf;
nexthop.s_addr = 0;
if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1;
/* Type, flags, message. */
api.type = stream_getc(s);
api.instance = stream_getw(s);
api.flags = stream_getl(s);
api.message = stream_getc(s);
/* we completely ignore srcdest routes for now. */
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
return 0;
/* IPv4 prefix. */
memset(&p, 0, sizeof(struct prefix_ipv4));
p.family = AF_INET;
p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc(s));
stream_get(&p.prefix, s, PSIZE(p.prefixlen));
/* ignore link-local address. */
if (api.prefix.family == AF_INET6
&& IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
return 0;
/* Nexthop, ifindex, distance, metric. */
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
api.nexthop_num = stream_getc(s);
nexthop.s_addr = stream_get_ipv4(s);
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
api.ifindex_num = stream_getc(s);
ifindex = stream_getl(s); /* ifindex, unused */
} else {
ifindex = 0;
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc(s);
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl(s);
else
api.metric = 0;
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG))
api.tag = stream_getl(s);
else
api.tag = 0;
if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD) {
if (bgp_debug_zebra((struct prefix *)&p)) {
char buf[2][INET_ADDRSTRLEN];
zlog_debug(
"Rx IPv4 route add VRF %u %s[%d] %s/%d nexthop %s metric %u tag %" ROUTE_TAG_PRI,
vrf_id, zebra_route_string(api.type),
api.instance, inet_ntop(AF_INET, &p.prefix,
buf[0], sizeof(buf[0])),
p.prefixlen, inet_ntop(AF_INET, &nexthop,
buf[1], sizeof(buf[1])),
api.metric, api.tag);
}
nexthop = api.nexthops[0].gate;
ifindex = api.nexthops[0].ifindex;
add = (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD);
if (add) {
/*
* The ADD message is actually an UPDATE and there is no
* explicit DEL
@ -639,156 +595,30 @@ static int zebra_read_ipv4(int command, struct zclient *zclient,
*/
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
if (i != api.type)
bgp_redistribute_delete(bgp,
(struct prefix *)&p, i,
bgp_redistribute_delete(bgp, &api.prefix, i,
api.instance);
}
/* Now perform the add/update. */
bgp_redistribute_add(bgp, (struct prefix *)&p, &nexthop, NULL,
ifindex, api.metric, api.type,
api.instance, api.tag);
} else if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL) {
if (bgp_debug_zebra((struct prefix *)&p)) {
char buf[2][INET_ADDRSTRLEN];
zlog_debug(
"Rx IPv4 route delete VRF %u %s[%d] %s/%d "
"nexthop %s metric %u tag %" ROUTE_TAG_PRI,
vrf_id, zebra_route_string(api.type),
api.instance, inet_ntop(AF_INET, &p.prefix,
buf[0], sizeof(buf[0])),
p.prefixlen, inet_ntop(AF_INET, &nexthop,
buf[1], sizeof(buf[1])),
api.metric, api.tag);
}
bgp_redistribute_delete(bgp, (struct prefix *)&p, api.type,
api.instance);
}
return 0;
}
/* Zebra route add and delete treatment. */
static int zebra_read_ipv6(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct stream *s;
struct zapi_ipv6 api;
struct in6_addr nexthop;
struct prefix_ipv6 p, src_p;
unsigned int ifindex;
int i;
struct bgp *bgp;
bgp = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp)
return 0;
s = zclient->ibuf;
memset(&nexthop, 0, sizeof(struct in6_addr));
/* Type, flags, message. */
api.type = stream_getc(s);
api.instance = stream_getw(s);
api.flags = stream_getl(s);
api.message = stream_getc(s);
/* IPv6 prefix. */
memset(&p, 0, sizeof(struct prefix_ipv6));
p.family = AF_INET6;
p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc(s));
stream_get(&p.prefix, s, PSIZE(p.prefixlen));
memset(&src_p, 0, sizeof(struct prefix_ipv6));
src_p.family = AF_INET6;
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) {
src_p.prefixlen = stream_getc(s);
stream_get(&src_p.prefix, s, PSIZE(src_p.prefixlen));
}
if (src_p.prefixlen)
/* we completely ignore srcdest routes for now. */
return 0;
/* Nexthop, ifindex, distance, metric. */
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
api.nexthop_num = stream_getc(s);
stream_get(&nexthop, s, 16);
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
api.ifindex_num = stream_getc(s);
ifindex = stream_getl(s); /* ifindex, unused */
bgp_redistribute_add(bgp, &api.prefix, &nexthop, ifindex,
api.metric, api.type, api.instance,
api.tag);
} else {
ifindex = 0;
bgp_redistribute_delete(bgp, &api.prefix, api.type,
api.instance);
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc(s);
else
api.distance = 0;
if (bgp_debug_zebra(&api.prefix)) {
char buf[2][PREFIX_STRLEN];
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl(s);
else
api.metric = 0;
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG))
api.tag = stream_getl(s);
else
api.tag = 0;
/* Simply ignore link-local address. */
if (IN6_IS_ADDR_LINKLOCAL(&p.prefix))
return 0;
if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD) {
if (bgp_debug_zebra((struct prefix *)&p)) {
char buf[2][INET6_ADDRSTRLEN];
zlog_debug(
"Rx IPv6 route add VRF %u %s[%d] %s/%d nexthop %s metric %u tag %" ROUTE_TAG_PRI,
vrf_id, zebra_route_string(api.type),
api.instance, inet_ntop(AF_INET6, &p.prefix,
buf[0], sizeof(buf[0])),
p.prefixlen, inet_ntop(AF_INET, &nexthop,
buf[1], sizeof(buf[1])),
api.metric, api.tag);
}
/*
* The ADD message is actually an UPDATE and there is no
* explicit DEL
* for a prior redistributed route, if any. So, perform an
* implicit
* DEL processing for the same redistributed route from any
* other
* source type.
*/
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
if (i != api.type)
bgp_redistribute_delete(bgp,
(struct prefix *)&p, i,
api.instance);
}
bgp_redistribute_add(bgp, (struct prefix *)&p, NULL, &nexthop,
ifindex, api.metric, api.type,
api.instance, api.tag);
} else if (command == ZEBRA_REDISTRIBUTE_IPV6_DEL) {
if (bgp_debug_zebra((struct prefix *)&p)) {
char buf[2][INET6_ADDRSTRLEN];
zlog_debug(
"Rx IPv6 route delete VRF %u %s[%d] %s/%d "
"nexthop %s metric %u tag %" ROUTE_TAG_PRI,
vrf_id, zebra_route_string(api.type),
api.instance, inet_ntop(AF_INET6, &p.prefix,
buf[0], sizeof(buf[0])),
p.prefixlen, inet_ntop(AF_INET6, &nexthop,
buf[1], sizeof(buf[1])),
api.metric, api.tag);
}
bgp_redistribute_delete(bgp, (struct prefix *)&p, api.type,
api.instance);
prefix2str(&api.prefix, buf[0], sizeof(buf[0]));
inet_ntop(api.prefix.family, &nexthop, buf[1], sizeof(buf[1]));
zlog_debug(
"Rx route %s VRF %u %s[%d] %s "
"nexthop %s metric %u tag %" ROUTE_TAG_PRI,
(add) ? "add" : "delete", vrf_id,
zebra_route_string(api.type), api.instance, buf[0],
buf[1], api.metric, api.tag);
}
return 0;
@ -1153,7 +983,11 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
struct bgp_info *info, struct bgp *bgp, afi_t afi,
safi_t safi)
{
u_int32_t flags;
struct zapi_route api;
struct zapi_nexthop *api_nh;
int nh_family;
int valid_nh_count = 0;
int has_valid_label = 0;
u_char distance;
struct peer *peer;
struct bgp_info *mpinfo;
@ -1169,18 +1003,17 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (!bgp_install_info_to_zebra(bgp))
return;
if ((p->family == AF_INET
&& !vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_BGP],
bgp->vrf_id))
|| (p->family == AF_INET6
&& !vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_BGP],
bgp->vrf_id)))
return;
if (bgp->main_zebra_update_hold)
return;
flags = 0;
/* Make Zebra API structure. */
memset(&api, 0, sizeof(api));
api.vrf_id = bgp->vrf_id;
api.type = ZEBRA_ROUTE_BGP;
api.safi = safi;
api.prefix = *p;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
peer = info->peer;
tag = info->attr->tag;
@ -1189,40 +1022,39 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
* in
* the RIB */
if (info->sub_type == BGP_ROUTE_AGGREGATE)
SET_FLAG(flags, ZEBRA_FLAG_BLACKHOLE);
SET_FLAG(api.flags, ZEBRA_FLAG_BLACKHOLE);
if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED
|| info->sub_type == BGP_ROUTE_AGGREGATE) {
SET_FLAG(flags, ZEBRA_FLAG_IBGP);
SET_FLAG(flags, ZEBRA_FLAG_INTERNAL);
SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
}
if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|| CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
|| bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
SET_FLAG(flags, ZEBRA_FLAG_INTERNAL);
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(info->attr)) {
struct zapi_ipv4 api;
struct in_addr *nexthop;
char buf[2][INET_ADDRSTRLEN];
int valid_nh_count = 0;
int has_valid_label = 0;
/* Get nexthop address-family */
if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(info->attr))
nh_family = AF_INET;
else if (p->family == AF_INET6
|| (p->family == AF_INET
&& BGP_ATTR_NEXTHOP_AFI_IP6(info->attr)))
nh_family = AF_INET6;
else
return;
/* resize nexthop buffer size if necessary */
stream_reset(bgp_nexthop_buf);
nexthop = NULL;
if (bgp->table_map[afi][safi].name)
BGP_INFO_ATTR_BUF_INIT();
stream_reset(bgp_label_buf);
/* Metric is currently based on the best-path only */
metric = info->attr->med;
for (mpinfo = info; mpinfo; mpinfo = bgp_info_mpath_next(mpinfo)) {
if (nh_family == AF_INET) {
struct in_addr *nexthop;
if (bgp->table_map[afi][safi].name)
BGP_INFO_ATTR_BUF_INIT();
/* Metric is currently based on the best-path only */
metric = info->attr->med;
for (mpinfo = info; mpinfo;
mpinfo = bgp_info_mpath_next(mpinfo)) {
nexthop = NULL;
if (bgp->table_map[afi][safi].name) {
@ -1234,8 +1066,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
bgp->table_map[afi][safi].map, p,
info_cp)) {
if (mpinfo == info) {
/* Metric is currently based on
* the best-path only */
metric = info_cp->attr->med;
tag = info_cp->attr->tag;
}
@ -1248,118 +1078,13 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (nexthop == NULL)
continue;
stream_put(bgp_nexthop_buf, &nexthop,
sizeof(struct in_addr *));
if (mpinfo->extra
&& bgp_is_valid_label(&mpinfo->extra->label)) {
has_valid_label = 1;
label = label_pton(&mpinfo->extra->label);
stream_put(bgp_label_buf, &label,
sizeof(mpls_label_t));
}
valid_nh_count++;
}
api.vrf_id = bgp->vrf_id;
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.instance = 0;
api.message = 0;
api.safi = safi;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
if (has_valid_label)
SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
/* Note that this currently only applies to Null0 routes for
* aggregates.
* ZEBRA_FLAG_BLACKHOLE signals zapi_ipv4_route to encode a
* special
* BLACKHOLE nexthop. We want to set api.nexthop_num to zero
* since we
* do not want to also encode the 0.0.0.0 nexthop for the
* aggregate route.
*/
if (CHECK_FLAG(flags, ZEBRA_FLAG_BLACKHOLE))
api.nexthop_num = 0;
else
api.nexthop_num = valid_nh_count;
api.nexthop = (struct in_addr **)STREAM_DATA(bgp_nexthop_buf);
if (has_valid_label) {
api.label_num = valid_nh_count;
api.label = (unsigned int *)STREAM_DATA(bgp_label_buf);
api_nh = &api.nexthops[valid_nh_count];
api_nh->gate.ipv4 = *nexthop;
api_nh->type = NEXTHOP_TYPE_IPV4;
} else {
api.label_num = 0;
api.label = NULL;
}
api.ifindex_num = 0;
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = metric;
api.tag = 0;
ifindex_t ifindex;
struct in6_addr *nexthop;
if (tag) {
SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
api.tag = tag;
}
distance = bgp_distance_apply(p, info, afi, safi, bgp);
if (distance) {
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
api.distance = distance;
}
if (bgp_debug_zebra(p)) {
int i;
char label_buf[20];
zlog_debug(
"Tx IPv4 route %s VRF %u %s/%d metric %u tag %" ROUTE_TAG_PRI
" count %d",
(valid_nh_count ? "add" : "delete"),
bgp->vrf_id, inet_ntop(AF_INET, &p->u.prefix4,
buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.tag,
api.nexthop_num);
for (i = 0; i < api.nexthop_num; i++) {
label_buf[0] = '\0';
if (has_valid_label)
sprintf(label_buf, "label %u",
api.label[i]);
zlog_debug(" nhop [%d]: %s %s", i + 1,
inet_ntop(AF_INET, api.nexthop[i],
buf[1], sizeof(buf[1])),
label_buf);
}
}
zapi_ipv4_route(valid_nh_count ? ZEBRA_IPV4_ROUTE_ADD
: ZEBRA_IPV4_ROUTE_DELETE,
zclient, (struct prefix_ipv4 *)p, &api);
}
/* We have to think about a IPv6 link-local address curse. */
if (p->family == AF_INET6
|| (p->family == AF_INET && BGP_ATTR_NEXTHOP_AFI_IP6(info->attr))) {
ifindex_t ifindex;
struct in6_addr *nexthop;
struct zapi_ipv6 api;
int valid_nh_count = 0;
char buf[2][INET6_ADDRSTRLEN];
int has_valid_label = 0;
stream_reset(bgp_nexthop_buf);
stream_reset(bgp_ifindices_buf);
stream_reset(bgp_label_buf);
ifindex = 0;
nexthop = NULL;
if (bgp->table_map[afi][safi].name)
BGP_INFO_ATTR_BUF_INIT();
metric = info->attr->med;
for (mpinfo = info; mpinfo;
mpinfo = bgp_info_mpath_next(mpinfo)) {
ifindex = 0;
nexthop = NULL;
@ -1407,147 +1132,72 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (ifindex == 0)
continue;
stream_put(bgp_nexthop_buf, &nexthop,
sizeof(struct in6_addr *));
stream_put(bgp_ifindices_buf, &ifindex,
sizeof(unsigned int));
if (mpinfo->extra
&& bgp_is_valid_label(&mpinfo->extra->label)) {
has_valid_label = 1;
label = label_pton(&mpinfo->extra->label);
stream_put(bgp_label_buf, &label,
sizeof(mpls_label_t));
}
valid_nh_count++;
api_nh = &api.nexthops[valid_nh_count];
api_nh->gate.ipv6 = *nexthop;
api_nh->ifindex = ifindex;
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
}
/* Make Zebra API structure. */
api.vrf_id = bgp->vrf_id;
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.instance = 0;
api.message = 0;
api.safi = safi;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
if (mpinfo->extra
&& bgp_is_valid_label(&mpinfo->extra->label)) {
has_valid_label = 1;
label = label_pton(&mpinfo->extra->label);
if (has_valid_label)
SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
/* Note that this currently only applies to Null0 routes for
* aggregates.
* ZEBRA_FLAG_BLACKHOLE signals zapi_ipv6_route to encode a
* special
* BLACKHOLE nexthop. We want to set api.nexthop_num to zero
* since we
* do not want to also encode the :: nexthop for the aggregate
* route.
*/
if (CHECK_FLAG(flags, ZEBRA_FLAG_BLACKHOLE))
api.nexthop_num = 0;
else
api.nexthop_num = valid_nh_count;
api.nexthop = (struct in6_addr **)STREAM_DATA(bgp_nexthop_buf);
SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX);
api.ifindex_num = valid_nh_count;
api.ifindex = (ifindex_t *)STREAM_DATA(bgp_ifindices_buf);
if (has_valid_label) {
api.label_num = valid_nh_count;
api.label = (unsigned int *)STREAM_DATA(bgp_label_buf);
} else {
api.label_num = 0;
api.label = NULL;
api_nh->label_num = 1;
api_nh->labels[0] = label;
}
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = metric;
api.tag = 0;
valid_nh_count++;
}
if (tag) {
SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
api.tag = tag;
}
if (has_valid_label)
SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
distance = bgp_distance_apply(p, info, afi, safi, bgp);
if (distance) {
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
api.distance = distance;
}
if (!CHECK_FLAG(api.flags, ZEBRA_FLAG_BLACKHOLE))
api.nexthop_num = valid_nh_count;
if (p->family == AF_INET) {
if (bgp_debug_zebra(p)) {
int i;
char label_buf[20];
zlog_debug(
"Tx IPv4 route %s VRF %u %s/%d metric %u tag %" ROUTE_TAG_PRI,
valid_nh_count ? "add" : "delete",
bgp->vrf_id,
inet_ntop(AF_INET, &p->u.prefix4,
buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.tag);
for (i = 0; i < api.nexthop_num; i++) {
label_buf[0] = '\0';
if (has_valid_label)
sprintf(label_buf, "label %u",
api.label[i]);
zlog_debug(
" nhop [%d]: %s if %s %s",
i + 1,
inet_ntop(AF_INET6,
api.nexthop[i],
buf[1],
sizeof(buf[1])),
ifindex2ifname(api.ifindex[i],
bgp->vrf_id),
label_buf);
}
}
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = metric;
if (valid_nh_count)
zapi_ipv4_route_ipv6_nexthop(
ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD,
zclient, (struct prefix_ipv4 *)p,
(struct zapi_ipv6 *)&api);
else
zapi_ipv4_route(ZEBRA_IPV4_ROUTE_DELETE,
zclient,
(struct prefix_ipv4 *)p,
(struct zapi_ipv4 *)&api);
} else {
if (bgp_debug_zebra(p)) {
int i;
char label_buf[20];
zlog_debug(
"Tx IPv6 route %s VRF %u %s/%d metric %u tag %" ROUTE_TAG_PRI,
valid_nh_count ? "add" : "delete",
bgp->vrf_id,
inet_ntop(AF_INET6, &p->u.prefix6,
buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.tag);
for (i = 0; i < api.nexthop_num; i++) {
label_buf[0] = '\0';
if (has_valid_label)
sprintf(label_buf, "label %u",
api.label[i]);
zlog_debug(
" nhop [%d]: %s if %s %s",
i + 1,
inet_ntop(AF_INET6,
api.nexthop[i],
buf[1],
sizeof(buf[1])),
ifindex2ifname(api.ifindex[i],
bgp->vrf_id),
label_buf);
}
}
if (tag) {
SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
api.tag = tag;
}
zapi_ipv6_route(
valid_nh_count ? ZEBRA_IPV6_ROUTE_ADD
: ZEBRA_IPV6_ROUTE_DELETE,
zclient, (struct prefix_ipv6 *)p, NULL, &api);
distance = bgp_distance_apply(p, info, afi, safi, bgp);
if (distance) {
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
api.distance = distance;
}
if (bgp_debug_zebra(p)) {
char prefix_buf[PREFIX_STRLEN];
char nh_buf[INET6_ADDRSTRLEN];
char label_buf[20];
int i;
prefix2str(&api.prefix, prefix_buf, sizeof(prefix_buf));
zlog_debug("Tx route %s VRF %u %s metric %u tag %" ROUTE_TAG_PRI
" count %d",
valid_nh_count ? "add" : "delete", bgp->vrf_id,
prefix_buf, api.metric, api.tag, api.nexthop_num);
for (i = 0; i < api.nexthop_num; i++) {
api_nh = &api.nexthops[i];
inet_ntop(nh_family, &api_nh->gate, nh_buf,
sizeof(nh_buf));
label_buf[0] = '\0';
if (has_valid_label)
sprintf(label_buf, "label %u",
api_nh->labels[0]);
zlog_debug(" nhop [%d]: %s %s", i + 1, nh_buf,
label_buf);
}
}
zclient_route_send(valid_nh_count ? ZEBRA_ROUTE_ADD
: ZEBRA_ROUTE_DELETE,
zclient, &api);
}
/* Announce all routes of a table to zebra */
@ -1578,7 +1228,7 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi)
void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
{
u_int32_t flags;
struct zapi_route api;
struct peer *peer;
peer = info->peer;
@ -1590,101 +1240,30 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
if (!bgp_install_info_to_zebra(peer->bgp))
return;
if ((p->family == AF_INET
&& !vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_BGP],
peer->bgp->vrf_id))
|| (p->family == AF_INET6
&& !vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_BGP],
peer->bgp->vrf_id)))
return;
flags = 0;
memset(&api, 0, sizeof(api));
api.vrf_id = peer->bgp->vrf_id;
api.type = ZEBRA_ROUTE_BGP;
api.safi = safi;
api.prefix = *p;
if (peer->sort == BGP_PEER_IBGP) {
SET_FLAG(flags, ZEBRA_FLAG_INTERNAL);
SET_FLAG(flags, ZEBRA_FLAG_IBGP);
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
}
if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|| CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
|| bgp_flag_check(peer->bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
SET_FLAG(flags, ZEBRA_FLAG_INTERNAL);
SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
if (p->family == AF_INET) {
struct zapi_ipv4 api;
if (bgp_debug_zebra(p)) {
char buf[PREFIX_STRLEN];
api.vrf_id = peer->bgp->vrf_id;
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.instance = 0;
api.message = 0;
api.safi = safi;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 0;
api.nexthop = NULL;
api.label_num = 0;
api.label = NULL;
api.ifindex_num = 0;
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
api.tag = 0;
if (info->attr->tag != 0) {
SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
api.tag = info->attr->tag;
}
if (bgp_debug_zebra(p)) {
char buf[2][INET_ADDRSTRLEN];
zlog_debug(
"Tx IPv4 route delete VRF %u %s/%d metric %u tag %" ROUTE_TAG_PRI,
peer->bgp->vrf_id,
inet_ntop(AF_INET, &p->u.prefix4, buf[0],
sizeof(buf[0])),
p->prefixlen, api.metric, api.tag);
}
zapi_ipv4_route(ZEBRA_IPV4_ROUTE_DELETE, zclient,
(struct prefix_ipv4 *)p, &api);
prefix2str(&api.prefix, buf, sizeof(buf));
zlog_debug("Tx route delete VRF %u %s", peer->bgp->vrf_id, buf);
}
/* We have to think about a IPv6 link-local address curse. */
if (p->family == AF_INET6) {
struct zapi_ipv6 api;
api.vrf_id = peer->bgp->vrf_id;
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.instance = 0;
api.message = 0;
api.safi = safi;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 0;
api.nexthop = NULL;
api.ifindex_num = 0;
api.label_num = 0;
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
api.tag = 0;
if (info->attr->tag != 0) {
SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
api.tag = info->attr->tag;
}
if (bgp_debug_zebra(p)) {
char buf[2][INET6_ADDRSTRLEN];
zlog_debug(
"Tx IPv6 route delete VRF %u %s/%d metric %u tag %" ROUTE_TAG_PRI,
peer->bgp->vrf_id,
inet_ntop(AF_INET6, &p->u.prefix6, buf[0],
sizeof(buf[0])),
p->prefixlen, api.metric, api.tag);
}
zapi_ipv6_route(ZEBRA_IPV6_ROUTE_DELETE, zclient,
(struct prefix_ipv6 *)p, NULL, &api);
}
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
}
struct bgp_redist *bgp_redist_lookup(struct bgp *bgp, afi_t afi, u_char type,
@ -2198,12 +1777,10 @@ void bgp_zebra_init(struct thread_master *master)
zclient->interface_nbr_address_delete =
bgp_interface_nbr_address_delete;
zclient->interface_vrf_update = bgp_interface_vrf_update;
zclient->redistribute_route_ipv4_add = zebra_read_ipv4;
zclient->redistribute_route_ipv4_del = zebra_read_ipv4;
zclient->redistribute_route_add = zebra_read_route;
zclient->redistribute_route_del = zebra_read_route;
zclient->interface_up = bgp_interface_up;
zclient->interface_down = bgp_interface_down;
zclient->redistribute_route_ipv6_add = zebra_read_ipv6;
zclient->redistribute_route_ipv6_del = zebra_read_ipv6;
zclient->nexthop_update = bgp_read_nexthop_update;
zclient->import_check_update = bgp_read_import_check_update;
zclient->fec_update = bgp_read_fec_update;
@ -2211,22 +1788,10 @@ void bgp_zebra_init(struct thread_master *master)
zclient->local_vni_del = bgp_zebra_process_local_vni;
zclient->local_macip_add = bgp_zebra_process_local_macip;
zclient->local_macip_del = bgp_zebra_process_local_macip;
bgp_nexthop_buf = stream_new(multipath_num * sizeof(struct in6_addr));
bgp_ifindices_buf = stream_new(multipath_num * sizeof(unsigned int));
bgp_label_buf = stream_new(multipath_num * sizeof(unsigned int));
}
void bgp_zebra_destroy(void)
{
if (bgp_nexthop_buf)
stream_free(bgp_nexthop_buf);
if (bgp_ifindices_buf)
stream_free(bgp_ifindices_buf);
if (bgp_label_buf)
stream_free(bgp_label_buf);
if (zclient == NULL)
return;
zclient_stop(zclient);

View File

@ -1116,9 +1116,8 @@ struct peer *peer_new(struct bgp *bgp)
peer->status = Idle;
peer->ostatus = Idle;
peer->cur_event = peer->last_event = peer->last_major_event = 0;
peer->bgp = bgp;
peer->bgp = bgp_lock(bgp);
peer = peer_lock(peer); /* initial reference */
bgp_lock(bgp);
peer->password = NULL;
/* Set default flags. */
@ -1392,6 +1391,32 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer)
hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
}
static void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi,
safi_t safi)
{
struct bgp_node *rn, *nrn;
for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
rn = bgp_route_next(rn)) {
if (rn->info != NULL) {
/* Special handling for 2-level routing
* tables. */
if (safi == SAFI_MPLS_VPN
|| safi == SAFI_ENCAP
|| safi == SAFI_EVPN) {
for (nrn = bgp_table_top((
struct bgp_table
*)(rn->info));
nrn;
nrn = bgp_route_next(nrn))
bgp_process(bgp, nrn,
afi, safi);
} else
bgp_process(bgp, rn, afi, safi);
}
}
}
/* Force a bestpath recalculation for all prefixes. This is used
* when 'bgp bestpath' commands are entered.
*/
@ -1399,29 +1424,10 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp)
{
afi_t afi;
safi_t safi;
struct bgp_node *rn, *nrn;
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
rn = bgp_route_next(rn)) {
if (rn->info != NULL) {
/* Special handling for 2-level routing
* tables. */
if (safi == SAFI_MPLS_VPN
|| safi == SAFI_ENCAP
|| safi == SAFI_EVPN) {
for (nrn = bgp_table_top((
struct bgp_table
*)(rn->info));
nrn;
nrn = bgp_route_next(nrn))
bgp_process(bgp, nrn,
afi, safi);
} else
bgp_process(bgp, rn, afi, safi);
}
}
bgp_recalculate_afi_safi_bestpaths(bgp, afi, safi);
}
}
}
@ -1501,6 +1507,25 @@ struct peer *peer_create_accept(struct bgp *bgp)
return peer;
}
/*
* Return true if we have a peer configured to use this afi/safi
*/
int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi)
{
struct listnode *node;
struct peer *peer;
for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
continue;
if (peer->afc[afi][safi])
return 1;
}
return 0;
}
/* Change peer's AS number. */
void peer_as_change(struct peer *peer, as_t as, int as_specified)
{
@ -1715,11 +1740,14 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi)
struct peer_group *group;
struct listnode *node, *nnode;
struct peer *tmp_peer;
struct bgp *bgp;
/* Nothing to do if we've already activated this peer */
if (peer->afc[afi][safi])
return ret;
bgp = peer->bgp;
/* This is a peer-group so activate all of the members of the
* peer-group as well */
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
@ -1742,6 +1770,17 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi)
ret |= non_peergroup_activate_af(peer, afi, safi);
}
/* If this is the first peer to be activated for this afi/labeled-unicast
* recalc bestpaths to trigger label allocation */
if (safi == SAFI_LABELED_UNICAST && !bgp->allocate_mpls_labels[afi][SAFI_UNICAST]) {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_info("peer(s) are now active for labeled-unicast, allocate MPLS labels");
bgp->allocate_mpls_labels[afi][SAFI_UNICAST] = 1;
bgp_recalculate_afi_safi_bestpaths(bgp, afi, SAFI_UNICAST);
}
return ret;
}
@ -1799,6 +1838,7 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi)
struct peer_group *group;
struct peer *tmp_peer;
struct listnode *node, *nnode;
struct bgp *bgp;
/* Nothing to do if we've already de-activated this peer */
if (!peer->afc[afi][safi])
@ -1822,6 +1862,20 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi)
ret |= non_peergroup_deactivate_af(peer, afi, safi);
}
bgp = peer->bgp;
/* If this is the last peer to be deactivated for this afi/labeled-unicast
* recalc bestpaths to trigger label deallocation */
if (safi == SAFI_LABELED_UNICAST &&
bgp->allocate_mpls_labels[afi][SAFI_UNICAST] &&
!bgp_afi_safi_peer_exists(bgp, afi, safi)) {
if (BGP_DEBUG(zebra, ZEBRA))
zlog_info("peer(s) are no longer active for labeled-unicast, deallocate MPLS labels");
bgp->allocate_mpls_labels[afi][SAFI_UNICAST] = 0;
bgp_recalculate_afi_safi_bestpaths(bgp, afi, SAFI_UNICAST);
}
return ret;
}
@ -3107,6 +3161,8 @@ int bgp_delete(struct bgp *bgp)
* routes to be processed still referencing the struct bgp.
*/
listnode_delete(bm->bgp, bgp);
if (list_isempty(bm->bgp))
bgp_close();
/* Deregister from Zebra, if needed */
if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
@ -3125,21 +3181,7 @@ int bgp_delete(struct bgp *bgp)
return 0;
}
static void bgp_free(struct bgp *);
void bgp_lock(struct bgp *bgp)
{
++bgp->lock;
}
void bgp_unlock(struct bgp *bgp)
{
assert(bgp->lock > 0);
if (--bgp->lock == 0)
bgp_free(bgp);
}
static void bgp_free(struct bgp *bgp)
void bgp_free(struct bgp *bgp)
{
afi_t afi;
safi_t safi;

View File

@ -337,6 +337,9 @@ struct bgp {
/* BGP redistribute configuration. */
struct list *redist[AFI_MAX][ZEBRA_ROUTE_MAX];
/* Allocate MPLS labels */
u_char allocate_mpls_labels[AFI_MAX][SAFI_MAX];
/* timer to re-evaluate neighbor default-originate route-maps */
struct thread *t_rmap_def_originate_eval;
#define RMAP_DEFAULT_ORIGINATE_EVAL_TIMER 5
@ -1256,9 +1259,6 @@ extern int bgp_flag_set(struct bgp *, int);
extern int bgp_flag_unset(struct bgp *, int);
extern int bgp_flag_check(struct bgp *, int);
extern void bgp_lock(struct bgp *);
extern void bgp_unlock(struct bgp *);
extern void bgp_router_id_zebra_bump(vrf_id_t, const struct prefix *);
extern int bgp_router_id_static_set(struct bgp *, struct in_addr);
@ -1287,6 +1287,7 @@ extern int bgp_listen_limit_unset(struct bgp *);
extern int bgp_update_delay_active(struct bgp *);
extern int bgp_update_delay_configured(struct bgp *);
extern int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi);
extern void peer_as_change(struct peer *, as_t, int);
extern int peer_remote_as(struct bgp *, union sockunion *, const char *, as_t *,
int, afi_t, safi_t);
@ -1399,6 +1400,20 @@ extern struct peer_af *peer_af_find(struct peer *, afi_t, safi_t);
extern int peer_af_delete(struct peer *, afi_t, safi_t);
extern void bgp_close(void);
extern void bgp_free(struct bgp *);
static inline struct bgp *bgp_lock(struct bgp *bgp)
{
bgp->lock++;
return bgp;
}
static inline void bgp_unlock(struct bgp *bgp)
{
assert(bgp->lock > 0);
if (--bgp->lock == 0)
bgp_free(bgp);
}
static inline int afindex(afi_t afi, safi_t safi)
{
@ -1544,10 +1559,8 @@ static inline struct vrf *bgp_vrf_lookup_by_instance_type(struct bgp *bgp)
static inline void bgp_vrf_link(struct bgp *bgp, struct vrf *vrf)
{
bgp->vrf_id = vrf->vrf_id;
if (vrf->info != (void *)bgp) {
bgp_lock(bgp);
vrf->info = (void *)bgp;
}
if (vrf->info != (void *)bgp)
vrf->info = (void *)bgp_lock(bgp);
}
/* Unlink BGP instance from VRF. */

View File

@ -1224,8 +1224,8 @@ static int rfapiVpnBiSamePtUn(struct bgp_info *bi1, struct bgp_info *bi2)
switch (pfx_un1.family) {
case AF_INET:
if (!IPV4_ADDR_SAME(&pfx_un1.u.prefix4.s_addr,
&pfx_un2.u.prefix4.s_addr))
if (!IPV4_ADDR_SAME(&pfx_un1.u.prefix4,
&pfx_un2.u.prefix4))
return 0;
break;
case AF_INET6:

View File

@ -142,13 +142,13 @@ DEFUN (no_debug_bgp_vnc_all,
* show/save
***********************************************************************/
DEFUN (show_debugging_bgp_vnc,
show_debugging_bgp_vnc_cmd,
"show debugging bgp vnc",
SHOW_STR
DEBUG_STR
BGP_STR
VNC_STR)
DEFUN_NOSH (show_debugging_bgp_vnc,
show_debugging_bgp_vnc_cmd,
"show debugging bgp vnc",
SHOW_STR
DEBUG_STR
BGP_STR
VNC_STR)
{
size_t i;

View File

@ -57,8 +57,8 @@ static struct zclient *zclient_vnc = NULL;
/*
* Routes coming from zebra get added to VNC here
*/
static void vnc_redistribute_add(struct prefix *p, struct in_addr *nexthop,
u_int32_t metric, uint8_t type)
static void vnc_redistribute_add(struct prefix *p, u_int32_t metric,
uint8_t type)
{
struct bgp *bgp = bgp_get_default();
struct prefix_rd prd;
@ -329,156 +329,33 @@ static void vnc_redistribute_withdraw(struct bgp *bgp, afi_t afi, uint8_t type)
*
* Assumes 1 nexthop
*/
static int vnc_zebra_read_ipv4(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
static int vnc_zebra_read_route(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct stream *s;
struct zapi_ipv4 api;
struct in_addr nexthop;
struct prefix_ipv4 p;
struct zapi_route api;
int add;
s = zclient->ibuf;
nexthop.s_addr = 0;
if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1;
/* Type, flags, message. */
api.type = stream_getc(s);
api.flags = stream_getc(s);
api.message = stream_getc(s);
/* IPv4 prefix. */
memset(&p, 0, sizeof(struct prefix_ipv4));
p.family = AF_INET;
p.prefixlen = stream_getc(s);
stream_get(&p.prefix, s, PSIZE(p.prefixlen));
/* Nexthop, ifindex, distance, metric. */
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
api.nexthop_num = stream_getc(s);
nexthop.s_addr = stream_get_ipv4(s);
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
api.ifindex_num = stream_getc(s);
stream_getl(s);
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc(s);
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl(s);
else
api.metric = 0;
if (command == ZEBRA_IPV4_ROUTE_ADD) {
if (BGP_DEBUG(zebra, ZEBRA)) {
char buf[2][INET_ADDRSTRLEN];
vnc_zlog_debug_verbose(
"%s: Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u",
__func__, zebra_route_string(api.type),
inet_ntop(AF_INET, &p.prefix, buf[0],
sizeof(buf[0])),
p.prefixlen, inet_ntop(AF_INET, &nexthop,
buf[1], sizeof(buf[1])),
api.metric);
}
vnc_redistribute_add((struct prefix *)&p, &nexthop, api.metric,
api.type);
} else {
if (BGP_DEBUG(zebra, ZEBRA)) {
char buf[2][INET_ADDRSTRLEN];
vnc_zlog_debug_verbose(
"%s: Zebra rcvd: IPv4 route delete %s %s/%d "
"nexthop %s metric %u",
__func__, zebra_route_string(api.type),
inet_ntop(AF_INET, &p.prefix, buf[0],
sizeof(buf[0])),
p.prefixlen, inet_ntop(AF_INET, &nexthop,
buf[1], sizeof(buf[1])),
api.metric);
}
vnc_redistribute_delete((struct prefix *)&p, api.type);
}
return 0;
}
/* Zebra route add and delete treatment. */
static int vnc_zebra_read_ipv6(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct stream *s;
struct zapi_ipv6 api;
struct in6_addr nexthop;
struct prefix_ipv6 p, src_p;
s = zclient->ibuf;
memset(&nexthop, 0, sizeof(struct in6_addr));
/* Type, flags, message. */
api.type = stream_getc(s);
api.flags = stream_getc(s);
api.message = stream_getc(s);
/* IPv6 prefix. */
memset(&p, 0, sizeof(struct prefix_ipv6));
p.family = AF_INET6;
p.prefixlen = stream_getc(s);
stream_get(&p.prefix, s, PSIZE(p.prefixlen));
memset(&src_p, 0, sizeof(struct prefix_ipv6));
src_p.family = AF_INET6;
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) {
src_p.prefixlen = stream_getc(s);
stream_get(&src_p.prefix, s, PSIZE(src_p.prefixlen));
}
if (src_p.prefixlen)
/* we completely ignore srcdest routes for now. */
/* we completely ignore srcdest routes for now. */
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
return 0;
/* Nexthop, ifindex, distance, metric. */
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
api.nexthop_num = stream_getc(s);
stream_get(&nexthop, s, 16);
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
api.ifindex_num = stream_getc(s);
stream_getl(s);
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc(s);
add = (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD);
if (add)
vnc_redistribute_add(&api.prefix, api.metric, api.type);
else
api.distance = 0;
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl(s);
else
api.metric = 0;
vnc_redistribute_delete(&api.prefix, api.type);
/* Simply ignore link-local address. */
if (IN6_IS_ADDR_LINKLOCAL(&p.prefix))
return 0;
if (BGP_DEBUG(zebra, ZEBRA)) {
char buf[PREFIX_STRLEN];
if (command == ZEBRA_IPV6_ROUTE_ADD) {
if (BGP_DEBUG(zebra, ZEBRA)) {
char buf[INET6_ADDRSTRLEN];
vnc_zlog_debug_verbose(
"Zebra rcvd: IPv6 route add %s %s/%d metric %u",
zebra_route_string(api.type),
inet_ntop(AF_INET6, &p.prefix, buf,
sizeof(buf)),
p.prefixlen, api.metric);
}
vnc_redistribute_add((struct prefix *)&p, NULL, api.metric,
api.type);
} else {
if (BGP_DEBUG(zebra, ZEBRA)) {
char buf[INET6_ADDRSTRLEN];
vnc_zlog_debug_verbose(
"Zebra rcvd: IPv6 route delete %s %s/%d metric %u",
zebra_route_string(api.type),
inet_ntop(AF_INET6, &p.prefix, buf,
sizeof(buf)),
p.prefixlen, api.metric);
}
vnc_redistribute_delete((struct prefix *)&p, api.type);
prefix2str(&api.prefix, buf, sizeof(buf));
vnc_zlog_debug_verbose(
"%s: Zebra rcvd: route delete %s %s metric %u",
__func__, zebra_route_string(api.type), buf,
api.metric);
}
return 0;
@ -494,83 +371,57 @@ static int vnc_zebra_read_ipv6(int command, struct zclient *zclient,
static void vnc_zebra_route_msg(struct prefix *p, int nhp_count, void *nhp_ary,
int add) /* 1 = add, 0 = del */
{
struct zapi_route api;
struct zapi_nexthop *api_nh;
int i;
if (!nhp_count) {
vnc_zlog_debug_verbose("%s: empty nexthop list, skipping",
__func__);
return;
}
if (p->family == AF_INET) {
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_VNC;
api.safi = SAFI_UNICAST;
api.prefix = *p;
struct zapi_ipv4 api;
/* Nexthops */
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = nhp_count;
for (i = 0; i < nhp_count; i++) {
struct in_addr *nhp_ary4;
struct in6_addr *nhp_ary6;
api.flags = 0;
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_VNC;
api.message = 0;
SET_FLAG(api.message,
ZAPI_MESSAGE_NEXTHOP); /* TBD what's it mean? */
api.nexthop_num = nhp_count;
api.nexthop = nhp_ary;
api.ifindex_num = 0;
api.instance = 0;
api.safi = SAFI_UNICAST;
if (BGP_DEBUG(zebra, ZEBRA)) {
char buf[INET_ADDRSTRLEN];
vnc_zlog_debug_verbose(
"%s: Zebra send: IPv4 route %s %s/%d, nhp_count=%d",
__func__, (add ? "add" : "del"),
inet_ntop(AF_INET, &p->u.prefix4, buf,
sizeof(buf)),
p->prefixlen, nhp_count);
api_nh = &api.nexthops[i];
switch (p->family) {
case AF_INET:
nhp_ary4 = nhp_ary;
memcpy(&api_nh->gate.ipv4, &nhp_ary4[i],
sizeof(api_nh->gate.ipv4));
api_nh->type = NEXTHOP_TYPE_IPV4;
break;
case AF_INET6:
nhp_ary6 = nhp_ary;
memcpy(&api_nh->gate.ipv6, &nhp_ary6[i],
sizeof(api_nh->gate.ipv6));
api_nh->type = NEXTHOP_TYPE_IPV6;
break;
}
zapi_ipv4_route((add ? ZEBRA_IPV4_NEXTHOP_ADD
: ZEBRA_IPV4_NEXTHOP_DELETE),
zclient_vnc, (struct prefix_ipv4 *)p, &api);
} else if (p->family == AF_INET6) {
struct zapi_ipv6 api;
ifindex_t ifindex = 0;
/* Make Zebra API structure. */
api.flags = 0;
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_VNC;
api.message = 0;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); /* TBD means? */
api.nexthop_num = nhp_count;
api.nexthop = nhp_ary;
SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX);
api.ifindex_num = 1;
api.ifindex = &ifindex;
api.instance = 0;
api.safi = SAFI_UNICAST;
if (BGP_DEBUG(zebra, ZEBRA)) {
char buf[INET6_ADDRSTRLEN];
vnc_zlog_debug_verbose(
"%s: Zebra send: IPv6 route %s %s/%d nhp_count=%d",
__func__, (add ? "add" : "del"),
inet_ntop(AF_INET6, &p->u.prefix6, buf,
sizeof(buf)),
p->prefixlen, nhp_count);
}
zapi_ipv6_route((add ? ZEBRA_IPV6_NEXTHOP_ADD
: ZEBRA_IPV6_NEXTHOP_DELETE),
zclient_vnc, (struct prefix_ipv6 *)p, NULL,
&api);
} else {
vnc_zlog_debug_verbose(
"%s: unknown prefix address family, skipping",
__func__);
return;
}
if (BGP_DEBUG(zebra, ZEBRA)) {
char buf[PREFIX_STRLEN];
prefix2str(&api.prefix, buf, sizeof(buf));
vnc_zlog_debug_verbose(
"%s: Zebra send: route %s %s, nhp_count=%d", __func__,
(add ? "add" : "del"), buf, nhp_count);
}
zclient_route_send((add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE),
zclient_vnc, &api);
}
@ -1042,10 +893,8 @@ void vnc_zebra_init(struct thread_master *master)
zclient_vnc = zclient_new(master);
zclient_init(zclient_vnc, ZEBRA_ROUTE_VNC, 0);
zclient_vnc->redistribute_route_ipv4_add = vnc_zebra_read_ipv4;
zclient_vnc->redistribute_route_ipv4_del = vnc_zebra_read_ipv4;
zclient_vnc->redistribute_route_ipv6_add = vnc_zebra_read_ipv6;
zclient_vnc->redistribute_route_ipv6_del = vnc_zebra_read_ipv6;
zclient_vnc->redistribute_route_add = vnc_zebra_read_route;
zclient_vnc->redistribute_route_del = vnc_zebra_read_route;
}
void vnc_zebra_destroy(void)

View File

@ -13,8 +13,7 @@ CLIPPY_DEPS = $(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py
SUFFIXES = _clippy.c .proto .pb-c.c .pb-c.h .pb.h
.c_clippy.c:
@{ test -x $(top_builddir)/$(HOSTTOOLS)lib/clippy || $(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/clippy; }
$(AM_V_CLIPPY)$(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py $< > $@.tmp
@{ test -f $@ && diff $@.tmp $@ >/dev/null 2>/dev/null; } && rm $@.tmp || mv $@.tmp $@
$(AM_V_CLIPPY)$(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py -o $@ $<
## automake's "ylwrap" is a great piece of GNU software... not.
.l.c:

View File

@ -195,6 +195,7 @@ fi
dnl always want these CFLAGS
AC_C_FLAG([-fno-omit-frame-pointer])
AC_C_FLAG([-funwind-tables])
AC_C_FLAG([-Wall])
AC_C_FLAG([-Wextra])
AC_C_FLAG([-Wmissing-prototypes])
@ -320,6 +321,8 @@ AC_ARG_WITH(rfp-path,
AS_HELP_STRING([--with-rfp-path[=DIR]],[path to replaced stub RFP used with BGP VNC]))
AC_ARG_ENABLE(snmp,
AS_HELP_STRING([--enable-snmp=ARG], [enable SNMP support (smux or agentx)]))
AC_ARG_ENABLE(zeromq,
AS_HELP_STRING([--enable-zeromq], [enable ZeroMQ handler (libfrrzmq)]))
AC_ARG_WITH(libpam,
AS_HELP_STRING([--with-libpam], [use libpam for PAM support in vtysh]))
AC_ARG_ENABLE(ospfapi,
@ -344,7 +347,7 @@ AC_ARG_ENABLE(shell_access,
AC_ARG_ENABLE(rtadv,
AS_HELP_STRING([--disable-rtadv], [disable IPV6 router advertisement feature]))
AC_ARG_ENABLE(irdp,
AS_HELP_STRING([--enable-irdp], [enable IRDP server support in zebra]))
AS_HELP_STRING([--disable-irdp], [enable IRDP server support in zebra (default if supported)]))
AC_ARG_ENABLE(capabilities,
AS_HELP_STRING([--disable-capabilities], [disable using POSIX capabilities]))
AC_ARG_ENABLE(rusage,
@ -570,10 +573,6 @@ else
AC_MSG_RESULT(no)
fi
if test "${enable_irdp}" = "yes"; then
AC_DEFINE(HAVE_IRDP,, IRDP )
fi
if test x"${enable_user}" = x"no"; then
enable_user=""
else
@ -1370,7 +1369,7 @@ fi
dnl ------------------
dnl check Net-SNMP library
dnl ------------------
if test "${enable_snmp}" != ""; then
if test "${enable_snmp}" != "" -a "${enable_snmp}" != "no"; then
AC_PATH_TOOL([NETSNMP_CONFIG], [net-snmp-config], [no])
if test x"$NETSNMP_CONFIG" = x"no"; then
AC_MSG_ERROR([--enable-snmp given but unable to find net-snmp-config])
@ -1479,17 +1478,27 @@ AC_CHECK_MEMBERS([struct sockaddr.sa_len,
dnl ---------------------------
dnl IRDP/pktinfo/icmphdr checks
dnl ---------------------------
AC_CHECK_TYPES([struct in_pktinfo],
[AC_CHECK_TYPES([struct icmphdr],
[if test "${enable_irdp}" != "no"; then
AC_DEFINE(HAVE_IRDP,, IRDP)
fi],
[if test "${enable_irdp}" = "yes"; then
AC_MSG_ERROR(['IRDP requires in_pktinfo at the moment!'])
fi], [FRR_INCLUDES])],
[if test "${enable_irdp}" = "yes"; then
AC_MSG_ERROR(['IRDP requires in_pktinfo at the moment!'])
fi], [FRR_INCLUDES])
AC_CHECK_TYPES([struct in_pktinfo], [
AC_CHECK_TYPES([struct icmphdr], [
IRDP=true
], [
IRDP=false
], [FRR_INCLUDES])
], [
IRDP=false
], [FRR_INCLUDES])
case "${enable_irdp}" in
yes)
$IRDP || AC_MSG_ERROR(['IRDP requires in_pktinfo at the moment!'])
;;
no)
IRDP=false
;;
esac
AM_CONDITIONAL(IRDP, $IRDP)
dnl -----------------------
dnl checking for IP_PKTINFO
@ -1708,6 +1717,21 @@ AC_CHECK_HEADER([malloc.h],
)
], [], FRR_INCLUDES)
dnl ------
dnl ZeroMQ
dnl ------
if test "x$enable_zeromq" != "xno"; then
PKG_CHECK_MODULES(ZEROMQ, [libzmq >= 4.0.0], [
AC_DEFINE(HAVE_ZEROMQ, 1, [Enable ZeroMQ support])
ZEROMQ=true
], [
if test "x$enable_zeromq" = "xyes"; then
AC_MSG_ERROR([configuration specifies --enable-zeromq but libzmq was not found])
fi
])
fi
AM_CONDITIONAL([ZEROMQ], test "x$ZEROMQ" = "xtrue")
dnl ----------
dnl configure date
dnl ----------

3
doc/code/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/_templates
/_build
!/Makefile

216
doc/code/Makefile Normal file
View File

@ -0,0 +1,216 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*
.PHONY: html
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: dirhtml
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/FRR.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/FRR.qhc"
.PHONY: applehelp
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
.PHONY: devhelp
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/FRR"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/FRR"
@echo "# devhelp"
.PHONY: epub
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: latex
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: latexpdfja
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
.PHONY: info
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
.PHONY: gettext
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

293
doc/code/conf.py Normal file
View File

@ -0,0 +1,293 @@
# -*- coding: utf-8 -*-
#
# FRR documentation build configuration file, created by
# sphinx-quickstart on Tue Jan 31 16:00:52 2017.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
import re
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.todo']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'FRR'
copyright = u'2017, FRR'
author = u'FRR'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
# The short X.Y version.
version = u'?.?'
# The full version, including alpha/beta/rc tags.
release = u'?.?-?'
val = re.compile('^S\["([^"]+)"\]="(.*)"$')
with open('../../config.status', 'r') as cfgstatus:
for ln in cfgstatus.readlines():
m = val.match(ln)
if m is None: continue
if m.group(1) == 'PACKAGE_VERSION':
release = m.group(2)
version = release.split('-')[0]
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'FRRdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'FRR.tex', u'FRR Documentation',
u'FRR', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'frr', u'FRR Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'FRR', u'FRR Documentation',
author, 'FRR', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

171
doc/code/hooks.rst Normal file
View File

@ -0,0 +1,171 @@
.. highlight:: c
Hooks
=====
Libfrr provides type-safe subscribable hook points where other pieces of
code can add one or more callback functions. "type-safe" in this case
applies to the function pointers used for subscriptions. The
implementations checks (at compile-time) wheter a callback to be added has
the appropriate function signature (parameters) for the hook.
Example:
.. code-block:: c
:caption: mydaemon.h
#include "hook.h"
DECLARE_HOOK(some_update_event, (struct eventinfo *info), (info))
.. code-block:: c
:caption: mydaemon.c
#include "mydaemon.h"
DEFINE_HOOK(some_update_event, (struct eventinfo *info), (info))
...
hook_call(some_update_event, info);
.. code-block:: c
:caption: mymodule.c
#include "mydaemon.h"
static int event_handler(struct eventinfo *info);
...
hook_register(some_update_event, event_handler);
Do not use parameter names starting with "hook", these can collide with
names used by the hook code itself.
Return values
-------------
Callbacks to be placed on hooks always return "int" for now; hook_call will
sum up the return values from each called function. (The default is 0 if no
callbacks are registered.)
There are no pre-defined semantics for the value, in most cases it is
ignored. For success/failure indication, 0 should be success, and
handlers should make sure to only return 0 or 1 (not -1 or other values).
There is no built-in way to abort executing a chain after a failure of one
of the callbacks. If this is needed, the hook can use an extra
``bool *aborted`` argument.
Priorities
----------
Hooks support a "priority" value for ordering registered calls
relative to each other. The priority is a signed integer where lower
values are called earlier. There are also "Koohs", which is hooks with
reverse priority ordering (for cleanup/deinit hooks, so you can use the
same priority value).
Recommended priority value ranges are:
======================== ===================================================
Range Usage
------------------------ ---------------------------------------------------
-999 ... 0 ... 999 main executable / daemon, or library
-1999 ... -1000 modules registering calls that should run before
the daemon's bits
1000 ... 1999 modules' calls that should run after daemon's
(includes default value: 1000)
======================== ===================================================
Note: the default value is 1000, based on the following 2 expectations:
- most hook_register() usage will be in loadable modules
- usage of hook_register() in the daemon itself may need relative ordering
to itself, making an explicit value the expected case
The priority value is passed as extra argument on hook_register_prio() /
hook_register_arg_prio(). Whether a hook runs in reverse is determined
solely by the code defining / calling the hook. (DECLARE_KOOH is actually
the same thing as DECLARE_HOOK, it's just there to make it obvious.)
Definition
----------
.. c:macro:: DECLARE_HOOK(name, arglist, passlist)
.. c:macro:: DECLARE_KOOH(name, arglist, passlist)
:param name: Name of the hook to be defined
:param arglist: Function definition style parameter list in braces.
:param passlist: List of the same parameters without their types.
Note: the second and third macro args must be the hook function's
parameter list, with the same names for each parameter. The second
macro arg is with types (used for defining things), the third arg is
just the names (used for passing along parameters).
This macro must be placed in a header file; this header file must be
included to register a callback on the hook.
Examples:
.. code-block:: c
DECLARE_HOOK(foo, (), ())
DECLARE_HOOK(bar, (int arg), (arg))
DECLARE_HOOK(baz, (const void *x, in_addr_t y), (x, y))
.. c:macro:: DEFINE_HOOK(name, arglist, passlist)
Implements an hook. Each ``DECLARE_HOOK`` must have be accompanied by
exactly one ``DEFINE_HOOK``, which needs to be placed in a source file.
**The hook can only be called from this source file.** This is intentional
to avoid overloading and/or misusing hooks for distinct purposes.
The compiled source file will include a global symbol with the name of the
hook prefixed by `_hook_`. Trying to register a callback for a hook that
doesn't exist will therefore result in a linker error, or a module
load-time error for dynamic modules.
.. c:macro:: DEFINE_KOOH(name, arglist, passlist)
Same as ``DEFINE_HOOK``, but the sense of priorities / order of callbacks
is reversed. This should be used for cleanup hooks.
.. c:function:: int hook_call(name, ...)
Calls the specified named hook. Parameters to the hook are passed right
after the hook name, e.g.:
.. code-block:: c
hook_call(foo);
hook_call(bar, 0);
hook_call(baz, NULL, INADDR_ANY);
Returns the sum of return values from all callbacks. The ``DEFINE_HOOK``
statement for the hook must be placed in the file before any ``hook_call``
use of the hook.
Callback registration
---------------------
.. c:function:: void hook_register(name, int (*callback)(...))
.. c:function:: void hook_register_prio(name, int priority, int (*callback)(...))
.. c:function:: void hook_register_arg(name, int (*callback)(void *arg, ...), void *arg)
.. c:function:: void hook_register_arg_prio(name, int priority, int (*callback)(void *arg, ...), void *arg)
Register a callback with an hook. If the caller needs to pass an extra
argument to the callback, the _arg variant can be used and the extra
parameter will be passed as first argument to the callback. There is no
typechecking for this argument.
The priority value is used as described above. The variants without a
priority parameter use 1000 as priority value.
.. c:function:: void hook_unregister(name, int (*callback)(...))
.. c:function:: void hook_unregister_arg(name, int (*callback)(void *arg, ...), void *arg)
Removes a previously registered callback from a hook. Note that there
is no _prio variant of these calls. The priority value is only used during
registration.

18
doc/code/index.rst Normal file
View File

@ -0,0 +1,18 @@
Welcome to FRR's documentation!
===============================
Contents:
.. toctree::
:maxdepth: 2
library
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

10
doc/code/library.rst Normal file
View File

@ -0,0 +1,10 @@
libfrr library facilities
=========================
.. toctree::
:maxdepth: 2
memtypes
hooks

117
doc/code/memtypes.rst Normal file
View File

@ -0,0 +1,117 @@
.. highlight:: c
Memtypes
========
FRR includes wrappers arround ``malloc()`` and ``free()`` that count the number
of objects currently allocated, for each of a defined ``MTYPE``.
To this extent, there are `memory groups` and `memory types`. Each memory
type must belong to a memory group, this is used just to provide some basic
structure.
Example:
.. code-block:: c
:caption: mydaemon.h
DECLARE_MGROUP(MYDAEMON)
DECLARE_MTYPE(MYNEIGHBOR)
.. code-block:: c
:caption: mydaemon.c
DEFINE_MGROUP( MYDAEMON, "My daemon's memory")
DEFINE_MTYPE( MYDAEMON, MYNEIGHBOR, "Neighbor entry")
DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name")
struct neigh *neighbor_new(const char *name)
{
struct neigh *n = XMALLOC(MYNEIGHBOR, sizeof(*n));
n->name = XSTRDUP(MYNEIGHBORNAME, name);
return n;
}
void neighbor_free(struct neigh *n)
{
XFREE(MYNEIGHBORNAME, n->name);
XFREE(MYNEIGHBOR, n);
}
Definition
----------
.. c:macro:: DECLARE_MGROUP(name)
This macro forward-declares a memory group and should be placed in a
``.h`` file. It expands to an ``extern struct memgroup`` statement.
.. c:macro:: DEFINE_MGROUP(mname, description)
Defines/implements a memory group. Must be placed into exactly one ``.c``
file (multiple inclusion will result in a link-time symbol conflict).
Contains additional logic (constructor and destructor) to register the
memory group in a global list.
.. c:macro:: DECLARE_MTYPE(name)
Forward-declares a memory type and makes ``MTYPE_name`` available for use.
Note that the ``MTYPE_`` prefix must not be included in the name, it is
automatically prefixed.
``MTYPE_name`` is created as a `static const` symbol, i.e. a compile-time
constant. It refers to an ``extern struct memtype _mt_name``, where `name`
is replaced with the actual name.
.. c:macro:: DEFINE_MTYPE(group, name, description)
Define/implement a memory type, must be placed into exactly one ``.c``
file (multiple inclusion will result in a link-time symbol conflict).
Like ``DEFINE_MGROUP``, this contains actual code to register the MTYPE
under its group.
.. c:macro:: DEFINE_MTYPE_STATIC(group, name, description)
Same as ``DEFINE_MTYPE``, but the ``DEFINE_MTYPE_STATIC`` variant places
the C ``static`` keyword on the definition, restricting the MTYPE's
availability to the current source file. This should be appropriate in
>80% of cases.
.. todo::
Daemons currently have ``daemon_memory.[ch]`` files listing all of
their MTYPEs. This is not how it should be, most of these types
should be moved into the appropriate files where they are used.
Only a few MTYPEs should remain non-static after that.
Usage
-----
.. c:function:: void *XMALLOC(struct memtype *mtype, size_t size)
.. c:function:: void *XCALLOC(struct memtype *mtype, size_t size)
.. c:function:: void *XSTRDUP(struct memtype *mtype, size_t size)
Allocation wrappers for malloc/calloc/realloc/strdup, taking an extra
mtype parameter.
.. c:function:: void *XREALLOC(struct memtype *mtype, void *ptr, size_t size)
Wrapper around realloc() with MTYPE tracking. Note that ``ptr`` may
be NULL, in which case the function does the same as XMALLOC (regardless
of whether the system realloc() supports this.)
.. c:function:: void XFREE(struct memtype *mtype, void *ptr)
Wrapper around free(), again taking an extra mtype parameter. This is
actually a macro, with the following additional properties:
- the macro contains ``ptr = NULL``
- if ptr is NULL, no operation is performed (as is guaranteed by system
implementations.) Do not surround XFREE with ``if (ptr != NULL)``
checks.

View File

@ -158,7 +158,7 @@ const char *eigrp_topology_ip_string(struct eigrp_prefix_entry *tn)
static char buf[EIGRP_IF_STRING_MAXLEN] = "";
u_int32_t ifaddr;
ifaddr = ntohl(tn->destination_ipv4->prefix.s_addr);
ifaddr = ntohl(tn->destination->u.prefix4.s_addr);
snprintf(buf, EIGRP_IF_STRING_MAXLEN, "%u.%u.%u.%u",
(ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff,
(ifaddr >> 8) & 0xff, ifaddr & 0xff);
@ -289,11 +289,12 @@ void show_ip_eigrp_topology_header(struct vty *vty, struct eigrp *eigrp)
void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn)
{
struct list *successors = eigrp_topology_get_successor(tn);
char buffer[PREFIX_STRLEN];
vty_out(vty, "%-3c", (tn->state > 0) ? 'A' : 'P');
vty_out(vty, "%s/%u, ", inet_ntoa(tn->destination_ipv4->prefix),
tn->destination_ipv4->prefixlen);
vty_out(vty, "%s, ",
prefix2str(tn->destination, buffer, PREFIX_STRLEN));
vty_out(vty, "%u successors, ", successors->count);
vty_out(vty, "FD is %u, serno: %" PRIu64 " \n", tn->fdistance,
tn->serno);
@ -323,12 +324,12 @@ void show_ip_eigrp_neighbor_entry(struct vty *vty, struct eigrp *eigrp,
}
DEFUN (show_debugging_eigrp,
show_debugging_eigrp_cmd,
"show debugging eigrp",
SHOW_STR
DEBUG_STR
EIGRP_STR)
DEFUN_NOSH (show_debugging_eigrp,
show_debugging_eigrp_cmd,
"show debugging [eigrp]",
SHOW_STR
DEBUG_STR
EIGRP_STR)
{
int i;

View File

@ -178,7 +178,7 @@ struct {
* Return number of occurred event (arrow in diagram).
*
*/
int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
static int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
{
// Loading base information from message
// struct eigrp *eigrp = msg->eigrp;
@ -204,8 +204,7 @@ int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
switch (actual_state) {
case EIGRP_FSM_STATE_PASSIVE: {
struct eigrp_neighbor_entry *head =
(struct eigrp_neighbor_entry *)
entry->prefix->entries->head->data;
listnode_head(prefix->entries);
if (head->reported_distance < prefix->fdistance) {
return EIGRP_FSM_KEEP_STATE;
@ -226,8 +225,7 @@ int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
case EIGRP_FSM_STATE_ACTIVE_0: {
if (msg->packet_type == EIGRP_OPC_REPLY) {
struct eigrp_neighbor_entry *head =
(struct eigrp_neighbor_entry *)
entry->prefix->entries->head->data;
listnode_head(prefix->entries);
listnode_delete(prefix->rij, entry->adv_router);
if (prefix->rij->count)
@ -279,8 +277,7 @@ int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
case EIGRP_FSM_STATE_ACTIVE_2: {
if (msg->packet_type == EIGRP_OPC_REPLY) {
struct eigrp_neighbor_entry *head =
(struct eigrp_neighbor_entry *)
prefix->entries->head->data;
listnode_head(prefix->entries);
listnode_delete(prefix->rij, entry->adv_router);
if (prefix->rij->count) {
@ -331,9 +328,10 @@ int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
* Function made to execute in separate thread.
* Load argument from thread and execute proper NSM function
*/
int eigrp_fsm_event(struct eigrp_fsm_action_message *msg, int event)
int eigrp_fsm_event(struct eigrp_fsm_action_message *msg)
{
zlog_info("EIGRP AS: %d State: %d Event: %d Network: %s\n",
int event = eigrp_get_fsm_event(msg);
zlog_info("EIGRP AS: %d State: %d Event: %d Network: %s",
msg->eigrp->AS, msg->prefix->state, event,
eigrp_topology_ip_string(msg->prefix));
(*(NSM[msg->prefix->state][event].func))(msg);
@ -350,16 +348,15 @@ int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg)
struct eigrp *eigrp = msg->eigrp;
struct eigrp_prefix_entry *prefix = msg->prefix;
struct list *successors = eigrp_topology_get_successor(prefix);
struct eigrp_neighbor_entry *ne;
assert(successors); // If this is NULL we have shit the bed, fun huh?
ne = listnode_head(successors);
prefix->state = EIGRP_FSM_STATE_ACTIVE_1;
prefix->rdistance = prefix->distance = prefix->fdistance =
((struct eigrp_neighbor_entry *)successors->head->data)
->distance;
prefix->reported_metric =
((struct eigrp_neighbor_entry *)successors->head->data)
->total_metric;
ne->distance;
prefix->reported_metric = ne->total_metric;
if (eigrp_nbr_count_get()) {
prefix->req_action |= EIGRP_FSM_NEED_QUERY;
@ -379,16 +376,15 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
struct eigrp *eigrp = msg->eigrp;
struct eigrp_prefix_entry *prefix = msg->prefix;
struct list *successors = eigrp_topology_get_successor(prefix);
struct eigrp_neighbor_entry *ne;
assert(successors); // If this is NULL somebody poked us in the eye.
ne = listnode_head(successors);
prefix->state = EIGRP_FSM_STATE_ACTIVE_3;
prefix->rdistance = prefix->distance = prefix->fdistance =
((struct eigrp_neighbor_entry *)successors->head->data)
->distance;
prefix->reported_metric =
((struct eigrp_neighbor_entry *)successors->head->data)
->total_metric;
ne->distance;
prefix->reported_metric = ne->total_metric;
if (eigrp_nbr_count_get()) {
prefix->req_action |= EIGRP_FSM_NEED_QUERY;
listnode_add(eigrp->topology_changes_internalIPV4, prefix);
@ -405,21 +401,15 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
{
struct eigrp_prefix_entry *prefix = msg->prefix;
struct eigrp_neighbor_entry *ne = listnode_head(prefix->entries);
if (prefix->state == EIGRP_FSM_STATE_PASSIVE) {
if (!eigrp_metrics_is_same(prefix->reported_metric,
((struct eigrp_neighbor_entry *)
prefix->entries->head->data)
->total_metric)) {
ne->total_metric)) {
prefix->rdistance = prefix->fdistance =
prefix->distance =
((struct eigrp_neighbor_entry *)
prefix->entries->head->data)
->distance;
prefix->distance = ne->distance;
prefix->reported_metric =
((struct eigrp_neighbor_entry *)
prefix->entries->head->data)
->total_metric;
ne->total_metric;
if (msg->packet_type == EIGRP_OPC_QUERY)
eigrp_send_reply(msg->adv_router, prefix);
prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
@ -441,22 +431,20 @@ int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
{
struct eigrp *eigrp = msg->eigrp;
struct eigrp_prefix_entry *prefix = msg->prefix;
struct eigrp_neighbor_entry *ne = listnode_head(prefix->entries);
prefix->fdistance = prefix->distance = prefix->rdistance =
((struct eigrp_neighbor_entry *)(prefix->entries->head->data))
->distance;
prefix->reported_metric =
((struct eigrp_neighbor_entry *)(prefix->entries->head->data))
->total_metric;
ne->distance;
prefix->reported_metric = ne->total_metric;
if (prefix->state == EIGRP_FSM_STATE_ACTIVE_3) {
struct list *successors = eigrp_topology_get_successor(prefix);
assert(successors); // It's like Napolean and Waterloo
eigrp_send_reply(
((struct eigrp_neighbor_entry *)successors->head->data)
->adv_router,
prefix);
ne = listnode_head(successors);
eigrp_send_reply(ne->adv_router,
prefix);
list_delete(successors);
}
@ -473,15 +461,15 @@ int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg)
{
struct list *successors = eigrp_topology_get_successor(msg->prefix);
struct eigrp_neighbor_entry *ne;
assert(successors); // Trump and his big hands
ne = listnode_head(successors);
msg->prefix->state = msg->prefix->state == EIGRP_FSM_STATE_ACTIVE_1
? EIGRP_FSM_STATE_ACTIVE_0
: EIGRP_FSM_STATE_ACTIVE_2;
msg->prefix->distance =
((struct eigrp_neighbor_entry *)successors->head->data)
->distance;
msg->prefix->distance = ne->distance;
if (!msg->prefix->rij->count)
(*(NSM[msg->prefix->state][eigrp_get_fsm_event(msg)].func))(
msg);
@ -495,13 +483,11 @@ int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
{
struct eigrp *eigrp = msg->eigrp;
struct eigrp_prefix_entry *prefix = msg->prefix;
struct eigrp_neighbor_entry *ne = listnode_head(prefix->entries);
prefix->state = EIGRP_FSM_STATE_PASSIVE;
prefix->distance = prefix->rdistance =
((struct eigrp_neighbor_entry *)(prefix->entries->head->data))
->distance;
prefix->reported_metric =
((struct eigrp_neighbor_entry *)(prefix->entries->head->data))
->total_metric;
prefix->distance = prefix->rdistance = ne->distance;
prefix->reported_metric = ne->total_metric;
prefix->fdistance = prefix->fdistance > prefix->distance
? prefix->distance
: prefix->fdistance;
@ -510,11 +496,9 @@ int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
assert(successors); // Having a spoon and all you need is a
// knife
eigrp_send_reply(
((struct eigrp_neighbor_entry *)successors->head->data)
->adv_router,
prefix);
ne = listnode_head(successors);
eigrp_send_reply(ne->adv_router,
prefix);
list_delete(successors);
}
@ -531,6 +515,7 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
{
struct eigrp *eigrp = msg->eigrp;
struct eigrp_prefix_entry *prefix = msg->prefix;
struct eigrp_neighbor_entry *best_successor;
struct list *successors = eigrp_topology_get_successor(prefix);
assert(successors); // Routing without a stack
@ -538,8 +523,8 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
prefix->state = prefix->state == EIGRP_FSM_STATE_ACTIVE_0
? EIGRP_FSM_STATE_ACTIVE_1
: EIGRP_FSM_STATE_ACTIVE_3;
struct eigrp_neighbor_entry *best_successor =
((struct eigrp_neighbor_entry *)(successors->head->data));
best_successor = listnode_head(successors);
prefix->rdistance = prefix->distance = best_successor->distance;
prefix->reported_metric = best_successor->total_metric;
@ -559,13 +544,13 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg)
{
struct list *successors = eigrp_topology_get_successor(msg->prefix);
struct eigrp_neighbor_entry *ne;
assert(successors); // Cats and no Dogs
ne = listnode_head(successors);
msg->prefix->state = EIGRP_FSM_STATE_ACTIVE_2;
msg->prefix->distance =
((struct eigrp_neighbor_entry *)(successors->head->data))
->distance;
msg->prefix->distance = ne->distance;
list_delete(successors);
return 1;

View File

@ -28,8 +28,7 @@
#ifndef _ZEBRA_EIGRP_FSM_H
#define _ZEBRA_EIGRP_FSM_H
extern int eigrp_get_fsm_event(struct eigrp_fsm_action_message *);
extern int eigrp_fsm_event(struct eigrp_fsm_action_message *, int);
extern int eigrp_fsm_event(struct eigrp_fsm_action_message *msg);
#endif /* _ZEBRA_EIGRP_DUAL_H */

View File

@ -405,6 +405,20 @@ void eigrp_hello_receive(struct eigrp *eigrp, struct ip *iph,
inet_ntoa(nbr->src));
}
u_int32_t FRR_MAJOR;
u_int32_t FRR_MINOR;
void eigrp_sw_version_initialize(void)
{
char ver_string[] = VERSION;
char *dash = strstr(ver_string, "-");
if (dash)
dash[0] = '\0';
sscanf(ver_string, "%d.%d", &FRR_MAJOR, &FRR_MINOR);
}
/**
* @fn eigrp_sw_version_encode
*
@ -425,10 +439,8 @@ static u_int16_t eigrp_sw_version_encode(struct stream *s)
stream_putw(s, EIGRP_TLV_SW_VERSION);
stream_putw(s, length);
// encode the version of quagga we're running
// DVS: need to figure out a cleaner way to do this
stream_putc(s, 0); //!< major os version
stream_putc(s, 99); //!< minor os version
stream_putc(s, FRR_MAJOR); //!< major os version
stream_putc(s, FRR_MINOR); //!< minor os version
/* and the core eigrp version */
stream_putc(s, EIGRP_MAJOR_VERSION);
@ -614,11 +626,11 @@ static struct eigrp_packet *eigrp_hello_encode(struct eigrp_interface *ei,
u_int16_t length = EIGRP_HEADER_LEN;
// allocate a new packet to be sent
ep = eigrp_packet_new(ei->ifp->mtu);
ep = eigrp_packet_new(ei->ifp->mtu, NULL);
if (ep) {
// encode common header feilds
eigrp_packet_header_init(EIGRP_OPC_HELLO, ei, ep->s, 0, 0, ack);
eigrp_packet_header_init(EIGRP_OPC_HELLO, ei->eigrp, ep->s, 0, 0, ack);
// encode Authentication TLV
if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
@ -707,7 +719,7 @@ void eigrp_hello_send_ack(struct eigrp_neighbor *nbr)
inet_ntoa(nbr->src));
/* Add packet to the top of the interface output queue*/
eigrp_fifo_push_head(nbr->ei->obuf, ep);
eigrp_fifo_push(nbr->ei->obuf, ep);
/* Hook thread to write packet. */
if (nbr->ei->on_write_q == 0) {
@ -755,7 +767,7 @@ void eigrp_hello_send(struct eigrp_interface *ei, u_char flags,
if (ep) {
// Add packet to the top of the interface output queue
eigrp_fifo_push_head(ei->obuf, ep);
eigrp_fifo_push(ei->obuf, ep);
/* Hook thread to write packet. */
if (ei->on_write_q == 0) {

View File

@ -53,6 +53,7 @@
#include "eigrpd/eigrp_network.h"
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_memory.h"
#include "eigrpd/eigrp_fsm.h"
static void eigrp_delete_from_if(struct interface *, struct eigrp_interface *);
@ -150,8 +151,8 @@ struct list *eigrp_iflist;
void eigrp_if_init()
{
/* Initialize Zebra interface data structure. */
if_add_hook(IF_NEW_HOOK, eigrp_if_new_hook);
if_add_hook(IF_DELETE_HOOK, eigrp_if_delete_hook);
hook_register_prio(if_add, 0, eigrp_if_new_hook);
hook_register_prio(if_del, 0, eigrp_if_delete_hook);
}
int eigrp_if_new_hook(struct interface *ifp)
@ -224,14 +225,14 @@ void eigrp_del_if_params(struct eigrp_if_params *eip)
struct eigrp_if_params *eigrp_lookup_if_params(struct interface *ifp,
struct in_addr addr)
{
struct prefix_ipv4 p;
struct prefix p;
struct route_node *rn;
p.family = AF_INET;
p.prefixlen = IPV4_MAX_PREFIXLEN;
p.prefix = addr;
p.u.prefix4 = addr;
rn = route_node_lookup(IF_OIFS_PARAMS(ifp), (struct prefix *)&p);
rn = route_node_lookup(IF_OIFS_PARAMS(ifp), &p);
if (rn) {
route_unlock_node(rn);
@ -279,49 +280,63 @@ int eigrp_if_up(struct eigrp_interface *ei)
/*Add connected entry to topology table*/
struct prefix_ipv4 dest_addr;
dest_addr.family = AF_INET;
dest_addr.prefix = ei->connected->address->u.prefix4;
dest_addr.prefixlen = ei->connected->address->prefixlen;
apply_mask_ipv4(&dest_addr);
pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
&dest_addr);
if (pe == NULL) {
pe = eigrp_prefix_entry_new();
pe->serno = eigrp->serno;
pe->destination_ipv4 = prefix_ipv4_new();
prefix_copy((struct prefix *)pe->destination_ipv4,
(struct prefix *)&dest_addr);
pe->af = AF_INET;
pe->nt = EIGRP_TOPOLOGY_TYPE_CONNECTED;
pe->state = EIGRP_FSM_STATE_PASSIVE;
pe->fdistance = eigrp_calculate_metrics(eigrp, metric);
pe->req_action |= EIGRP_FSM_NEED_UPDATE;
eigrp_prefix_entry_add(eigrp->topology_table, pe);
listnode_add(eigrp->topology_changes_internalIPV4, pe);
}
ne = eigrp_neighbor_entry_new();
ne->ei = ei;
ne->reported_metric = metric;
ne->total_metric = metric;
ne->distance = eigrp_calculate_metrics(eigrp, metric);
ne->reported_distance = 0;
ne->prefix = pe;
ne->adv_router = eigrp->neighbor_self;
ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
eigrp_neighbor_entry_add(pe, ne);
for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei2)) {
if (ei2->nbrs->count != 0) {
struct prefix dest_addr;
dest_addr.family = AF_INET;
dest_addr.u.prefix4 = ei->connected->address->u.prefix4;
dest_addr.prefixlen = ei->connected->address->prefixlen;
apply_mask(&dest_addr);
pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
&dest_addr);
if (pe == NULL) {
pe = eigrp_prefix_entry_new();
pe->serno = eigrp->serno;
pe->destination = (struct prefix *)prefix_ipv4_new();
prefix_copy(pe->destination, &dest_addr);
pe->af = AF_INET;
pe->nt = EIGRP_TOPOLOGY_TYPE_CONNECTED;
ne->prefix = pe;
pe->reported_metric = metric;
pe->state = EIGRP_FSM_STATE_PASSIVE;
pe->fdistance = eigrp_calculate_metrics(eigrp, metric);
pe->req_action |= EIGRP_FSM_NEED_UPDATE;
eigrp_prefix_entry_add(eigrp->topology_table, pe);
listnode_add(eigrp->topology_changes_internalIPV4, pe);
eigrp_neighbor_entry_add(pe, ne);
for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei2)) {
eigrp_update_send(ei2);
}
}
pe->req_action &= ~EIGRP_FSM_NEED_UPDATE;
listnode_delete(eigrp->topology_changes_internalIPV4, pe);
pe->req_action &= ~EIGRP_FSM_NEED_UPDATE;
listnode_delete(eigrp->topology_changes_internalIPV4, pe);
} else {
struct eigrp_fsm_action_message msg;
ne->prefix = pe;
eigrp_neighbor_entry_add(pe, ne);
msg.packet_type = EIGRP_OPC_UPDATE;
msg.eigrp = eigrp;
msg.data_type = EIGRP_CONNECTED;
msg.adv_router = NULL;
msg.entry = ne;
msg.prefix = pe;
eigrp_fsm_event(&msg);
}
return 1;
}
@ -416,7 +431,7 @@ u_char eigrp_default_iftype(struct interface *ifp)
void eigrp_if_free(struct eigrp_interface *ei, int source)
{
struct prefix_ipv4 dest_addr;
struct prefix dest_addr;
struct eigrp_prefix_entry *pe;
struct eigrp *eigrp = eigrp_lookup();
@ -425,10 +440,8 @@ void eigrp_if_free(struct eigrp_interface *ei, int source)
eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL);
}
dest_addr.family = AF_INET;
dest_addr.prefix = ei->connected->address->u.prefix4;
dest_addr.prefixlen = ei->connected->address->prefixlen;
apply_mask_ipv4(&dest_addr);
dest_addr = *ei->connected->address;
apply_mask(&dest_addr);
pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
&dest_addr);
if (pe)
@ -532,11 +545,11 @@ struct eigrp_interface *eigrp_if_lookup_recv_if(struct eigrp *eigrp,
struct interface *ifp)
{
struct route_node *rn;
struct prefix_ipv4 addr;
struct prefix addr;
struct eigrp_interface *ei, *match;
addr.family = AF_INET;
addr.prefix = src;
addr.u.prefix4 = src;
addr.prefixlen = IPV4_MAX_BITLEN;
match = NULL;
@ -551,7 +564,7 @@ struct eigrp_interface *eigrp_if_lookup_recv_if(struct eigrp *eigrp,
continue;
if (prefix_match(CONNECTED_PREFIX(ei->connected),
(struct prefix *)&addr)) {
&addr)) {
if ((match == NULL) || (match->address->prefixlen
< ei->address->prefixlen))
match = ei;

View File

@ -159,6 +159,8 @@ int main(int argc, char **argv, char **envp)
}
}
eigrp_sw_version_initialize();
/* EIGRP master init. */
eigrp_master_init();
eigrp_om->master = frr_init();

View File

@ -357,3 +357,11 @@ void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty)
/* delete neighbor */
eigrp_nbr_delete(nbr);
}
int eigrp_nbr_split_horizon_check(struct eigrp_neighbor_entry *ne, struct eigrp_interface *ei)
{
if (ne->distance == EIGRP_MAX_METRIC)
return 0;
return (ne->ei == ei);
}

View File

@ -53,4 +53,6 @@ extern struct eigrp_neighbor *eigrp_nbr_lookup_by_addr_process(struct eigrp *,
struct in_addr);
extern void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty);
extern int eigrp_nbr_split_horizon_check(struct eigrp_neighbor_entry *ne,
struct eigrp_interface *ei);
#endif /* _ZEBRA_EIGRP_NEIGHBOR_H */

View File

@ -229,7 +229,7 @@ int eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p,
return ret;
}
int eigrp_network_set(struct eigrp *eigrp, struct prefix_ipv4 *p)
int eigrp_network_set(struct eigrp *eigrp, struct prefix *p)
{
struct route_node *rn;
struct interface *ifp;
@ -242,7 +242,7 @@ int eigrp_network_set(struct eigrp *eigrp, struct prefix_ipv4 *p)
return 0;
}
struct prefix_ipv4 *pref = prefix_ipv4_new();
struct prefix *pref = prefix_new();
PREFIX_COPY_IPV4(pref, p);
rn->info = (void *)pref;
@ -253,7 +253,7 @@ int eigrp_network_set(struct eigrp *eigrp, struct prefix_ipv4 *p)
/* Get target interface. */
for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
zlog_debug("Setting up %s", ifp->name);
eigrp_network_run_interface(eigrp, (struct prefix *)p, ifp);
eigrp_network_run_interface(eigrp, p, ifp);
}
return 1;
}
@ -334,21 +334,21 @@ void eigrp_if_update(struct interface *ifp)
}
}
int eigrp_network_unset(struct eigrp *eigrp, struct prefix_ipv4 *p)
int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p)
{
struct route_node *rn;
struct listnode *node, *nnode;
struct eigrp_interface *ei;
struct prefix *pref;
rn = route_node_lookup(eigrp->networks, (struct prefix *)p);
rn = route_node_lookup(eigrp->networks, p);
if (rn == NULL)
return 0;
pref = rn->info;
route_unlock_node(rn);
if (!IPV4_ADDR_SAME(&pref->u.prefix4, &p->prefix))
if (!IPV4_ADDR_SAME(&pref->u.prefix4, &p->u.prefix4))
return 0;
prefix_ipv4_free(rn->info);

View File

@ -32,8 +32,8 @@
extern int eigrp_sock_init(void);
extern int eigrp_if_ipmulticast(struct eigrp *, struct prefix *, unsigned int);
extern int eigrp_network_set(struct eigrp *, struct prefix_ipv4 *);
extern int eigrp_network_unset(struct eigrp *eigrp, struct prefix_ipv4 *p);
extern int eigrp_network_set(struct eigrp *eigrp, struct prefix *p);
extern int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p);
extern int eigrp_hello_timer(struct thread *);
extern void eigrp_if_update(struct interface *);

View File

@ -299,18 +299,6 @@ int eigrp_check_sha256_digest(struct stream *s,
return 1;
}
/*
* eigrp_packet_dump
*
* This routing dumps the contents of the IP packet either received or
* built by EIGRP.
*/
static void eigrp_packet_dump(struct stream *s)
{
// not yet...
return;
}
int eigrp_write(struct thread *thread)
{
struct eigrp *eigrp = THREAD_ARG(thread);
@ -322,6 +310,7 @@ int eigrp_write(struct thread *thread)
struct msghdr msg;
struct iovec iov[2];
u_int16_t opcode = 0;
u_int32_t seqno, ack;
int ret;
int flags = 0;
@ -347,7 +336,7 @@ int eigrp_write(struct thread *thread)
#endif /* WANT_EIGRP_WRITE_FRAGMENT */
/* Get one packet from queue. */
ep = eigrp_fifo_head(ei->obuf);
ep = eigrp_fifo_next(ei->obuf);
assert(ep);
assert(ep->length >= EIGRP_HEADER_LEN);
@ -357,6 +346,25 @@ int eigrp_write(struct thread *thread)
memset(&iph, 0, sizeof(struct ip));
memset(&sa_dst, 0, sizeof(sa_dst));
/*
* We build and schedule packets to go out
* in the future. In the mean time we may
* process some update packets from the
* neighbor, thus making it necessary
* to update the ack we are using for
* this outgoing packet.
*/
eigrph = (struct eigrp_header *)STREAM_DATA(ep->s);
opcode = eigrph->opcode;
seqno = ntohl(eigrph->sequence);
ack = ntohl(eigrph->ack);
if (ep->nbr && (ack != ep->nbr->recv_sequence_number)) {
eigrph->ack = htonl(ep->nbr->recv_sequence_number);
ack = ep->nbr->recv_sequence_number;
eigrph->checksum = 0;
eigrp_packet_checksum(ei, ep->s, ep->length);
}
sa_dst.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
sa_dst.sin_len = sizeof(sa_dst);
@ -412,8 +420,9 @@ int eigrp_write(struct thread *thread)
if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND)) {
eigrph = (struct eigrp_header *)STREAM_DATA(ep->s);
opcode = eigrph->opcode;
zlog_debug("Sending [%s] to [%s] via [%s] ret [%d].",
zlog_debug("Sending [%s][%d/%d] to [%s] via [%s] ret [%d].",
lookup_msg(eigrp_packet_type_str, opcode, NULL),
seqno, ack,
inet_ntoa(ep->dst), IF_NAME(ei), ret);
}
@ -425,22 +434,10 @@ int eigrp_write(struct thread *thread)
iph.ip_len, ei->ifp->name, ei->ifp->mtu,
safe_strerror(errno));
/* Show debug sending packet. */
if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND)
&& (IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))) {
zlog_debug(
"-----------------------------------------------------");
eigrp_ip_header_dump(&iph);
stream_set_getp(ep->s, 0);
eigrp_packet_dump(ep->s);
zlog_debug(
"-----------------------------------------------------");
}
/* Now delete packet from queue. */
eigrp_packet_delete(ei);
if (eigrp_fifo_head(ei->obuf) == NULL) {
if (eigrp_fifo_next(ei->obuf) == NULL) {
ei->on_write_q = 0;
list_delete_node(eigrp->oi_write_q, node);
}
@ -530,7 +527,7 @@ int eigrp_read(struct thread *thread)
/* Self-originated packet should be discarded silently. */
if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src)
|| (IPV4_ADDR_SAME(&iph->ip_src.s_addr, &ei->address->u.prefix4))) {
|| (IPV4_ADDR_SAME(&iph->ip_src, &ei->address->u.prefix4))) {
if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
zlog_debug(
"eigrp_read[%s]: Dropping self-originated packet",
@ -615,52 +612,51 @@ int eigrp_read(struct thread *thread)
start of the eigrp TLVs */
opcode = eigrph->opcode;
if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
zlog_debug(
"Received [%s] length [%u] via [%s] src [%s] dst [%s]",
lookup_msg(eigrp_packet_type_str, opcode, NULL), length,
IF_NAME(ei), inet_ntoa(iph->ip_src),
inet_ntoa(iph->ip_dst));
if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) {
char src[100], dst[100];
strcpy(src, inet_ntoa(iph->ip_src));
strcpy(dst, inet_ntoa(iph->ip_dst));
zlog_debug("Received [%s][%d/%d] length [%u] via [%s] src [%s] dst [%s]",
lookup_msg(eigrp_packet_type_str, opcode, NULL),
ntohl(eigrph->sequence), ntohl(eigrph->ack), length,
IF_NAME(ei), src, dst);
}
/* Read rest of the packet and call each sort of packet routine. */
stream_forward_getp(ibuf, EIGRP_HEADER_LEN);
/* New testing block of code for handling Acks */
if (ntohl(eigrph->ack) != 0) {
struct eigrp_packet *ep = NULL;
nbr = eigrp_nbr_get(ei, eigrph, iph);
/* neighbor must be valid, eigrp_nbr_get creates if none existed
*/
// neighbor must be valid, eigrp_nbr_get creates if none existed
assert(nbr);
struct eigrp_packet *ep;
ep = eigrp_fifo_next(nbr->retrans_queue);
if ((ep) && (ntohl(eigrph->ack) == ep->sequence_number)) {
ep = eigrp_fifo_pop(nbr->retrans_queue);
eigrp_packet_free(ep);
ep = eigrp_fifo_tail(nbr->retrans_queue);
if (ep) {
if (ntohl(eigrph->ack) == ep->sequence_number) {
if ((nbr->state == EIGRP_NEIGHBOR_PENDING)
&& (ntohl(eigrph->ack)
== nbr->init_sequence_number)) {
eigrp_nbr_state_set(nbr,
EIGRP_NEIGHBOR_UP);
zlog_info(
"Neighbor adjacency became full");
nbr->init_sequence_number = 0;
nbr->recv_sequence_number =
ntohl(eigrph->sequence);
eigrp_update_send_EOT(nbr);
}
ep = eigrp_fifo_pop_tail(nbr->retrans_queue);
eigrp_packet_free(ep);
if (nbr->retrans_queue->count > 0) {
eigrp_send_packet_reliably(nbr);
}
if ((nbr->state == EIGRP_NEIGHBOR_PENDING)
&& (ntohl(eigrph->ack) == nbr->init_sequence_number)) {
eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_UP);
zlog_info("Neighbor(%s) adjacency became full",
inet_ntoa(nbr->src));
nbr->init_sequence_number = 0;
nbr->recv_sequence_number =
ntohl(eigrph->sequence);
eigrp_update_send_EOT(nbr);
}
else
eigrp_send_packet_reliably(nbr);
}
ep = eigrp_fifo_tail(nbr->multicast_queue);
ep = eigrp_fifo_next(nbr->multicast_queue);
if (ep) {
if (ntohl(eigrph->ack) == ep->sequence_number) {
ep = eigrp_fifo_pop_tail(nbr->multicast_queue);
ep = eigrp_fifo_pop(nbr->multicast_queue);
eigrp_packet_free(ep);
if (nbr->multicast_queue->count > 0) {
eigrp_send_packet_reliably(nbr);
@ -826,13 +822,14 @@ void eigrp_fifo_reset(struct eigrp_fifo *fifo)
fifo->count = 0;
}
struct eigrp_packet *eigrp_packet_new(size_t size)
struct eigrp_packet *eigrp_packet_new(size_t size, struct eigrp_neighbor *nbr)
{
struct eigrp_packet *new;
new = XCALLOC(MTYPE_EIGRP_PACKET, sizeof(struct eigrp_packet));
new->s = stream_new(size);
new->retrans_counter = 0;
new->nbr = nbr;
return new;
}
@ -841,13 +838,13 @@ void eigrp_send_packet_reliably(struct eigrp_neighbor *nbr)
{
struct eigrp_packet *ep;
ep = eigrp_fifo_tail(nbr->retrans_queue);
ep = eigrp_fifo_next(nbr->retrans_queue);
if (ep) {
struct eigrp_packet *duplicate;
duplicate = eigrp_packet_duplicate(ep, nbr);
/* Add packet to the top of the interface output queue*/
eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
eigrp_fifo_push(nbr->ei->obuf, duplicate);
/*Start retransmission timer*/
thread_add_timer(master, eigrp_unack_packet_retrans, nbr,
@ -880,7 +877,7 @@ void eigrp_packet_checksum(struct eigrp_interface *ei, struct stream *s,
}
/* Make EIGRP header. */
void eigrp_packet_header_init(int type, struct eigrp_interface *ei,
void eigrp_packet_header_init(int type, struct eigrp *eigrp,
struct stream *s, u_int32_t flags,
u_int32_t sequence, u_int32_t ack)
{
@ -893,15 +890,15 @@ void eigrp_packet_header_init(int type, struct eigrp_interface *ei,
eigrph->opcode = (u_char)type;
eigrph->checksum = 0;
eigrph->vrid = htons(ei->eigrp->vrid);
eigrph->ASNumber = htons(ei->eigrp->AS);
eigrph->vrid = htons(eigrp->vrid);
eigrph->ASNumber = htons(eigrp->AS);
eigrph->ack = htonl(ack);
eigrph->sequence = htonl(sequence);
// if(flags == EIGRP_INIT_FLAG)
// eigrph->sequence = htonl(3);
eigrph->flags = htonl(flags);
if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
if (IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
zlog_debug("Packet Header Init Seq [%u] Ack [%u]",
htonl(eigrph->sequence), htonl(eigrph->ack));
@ -909,7 +906,7 @@ void eigrp_packet_header_init(int type, struct eigrp_interface *ei,
}
/* Add new packet to head of fifo. */
void eigrp_fifo_push_head(struct eigrp_fifo *fifo, struct eigrp_packet *ep)
void eigrp_fifo_push(struct eigrp_fifo *fifo, struct eigrp_packet *ep)
{
ep->next = fifo->head;
ep->previous = NULL;
@ -925,14 +922,8 @@ void eigrp_fifo_push_head(struct eigrp_fifo *fifo, struct eigrp_packet *ep)
fifo->count++;
}
/* Return first fifo entry. */
struct eigrp_packet *eigrp_fifo_head(struct eigrp_fifo *fifo)
{
return fifo->head;
}
/* Return last fifo entry. */
struct eigrp_packet *eigrp_fifo_tail(struct eigrp_fifo *fifo)
struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *fifo)
{
return fifo->tail;
}
@ -947,27 +938,6 @@ void eigrp_packet_delete(struct eigrp_interface *ei)
eigrp_packet_free(ep);
}
/* Delete first packet from fifo. */
struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *fifo)
{
struct eigrp_packet *ep;
ep = fifo->head;
if (ep) {
fifo->head = ep->next;
if (fifo->head == NULL)
fifo->tail = NULL;
else
fifo->head->previous = NULL;
fifo->count--;
}
return ep;
}
void eigrp_packet_free(struct eigrp_packet *ep)
{
if (ep->s)
@ -1028,14 +998,14 @@ int eigrp_unack_packet_retrans(struct thread *thread)
nbr = (struct eigrp_neighbor *)THREAD_ARG(thread);
struct eigrp_packet *ep;
ep = eigrp_fifo_tail(nbr->retrans_queue);
ep = eigrp_fifo_next(nbr->retrans_queue);
if (ep) {
struct eigrp_packet *duplicate;
duplicate = eigrp_packet_duplicate(ep, nbr);
/* Add packet to the top of the interface output queue*/
eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
eigrp_fifo_push(nbr->ei->obuf, duplicate);
ep->retrans_counter++;
if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
@ -1065,13 +1035,13 @@ int eigrp_unack_multicast_packet_retrans(struct thread *thread)
nbr = (struct eigrp_neighbor *)THREAD_ARG(thread);
struct eigrp_packet *ep;
ep = eigrp_fifo_tail(nbr->multicast_queue);
ep = eigrp_fifo_next(nbr->multicast_queue);
if (ep) {
struct eigrp_packet *duplicate;
duplicate = eigrp_packet_duplicate(ep, nbr);
/* Add packet to the top of the interface output queue*/
eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
eigrp_fifo_push(nbr->ei->obuf, duplicate);
ep->retrans_counter++;
if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
@ -1096,9 +1066,9 @@ int eigrp_unack_multicast_packet_retrans(struct thread *thread)
}
/* Get packet from tail of fifo. */
struct eigrp_packet *eigrp_fifo_pop_tail(struct eigrp_fifo *fifo)
struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *fifo)
{
struct eigrp_packet *ep;
struct eigrp_packet *ep = NULL;
ep = fifo->tail;
@ -1121,7 +1091,7 @@ struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old,
{
struct eigrp_packet *new;
new = eigrp_packet_new(nbr->ei->ifp->mtu);
new = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
new->length = old->length;
new->retrans_counter = old->retrans_counter;
new->dst = old->dst;
@ -1131,6 +1101,16 @@ struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old,
return new;
}
static struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new()
{
struct TLV_IPv4_Internal_type *new;
new = XCALLOC(MTYPE_EIGRP_IPV4_INT_TLV,
sizeof(struct TLV_IPv4_Internal_type));
return new;
}
struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s)
{
struct TLV_IPv4_Internal_type *tlv;
@ -1187,21 +1167,21 @@ u_int16_t eigrp_add_internalTLV_to_stream(struct stream *s,
u_int16_t length;
stream_putw(s, EIGRP_TLV_IPv4_INT);
if (pe->destination_ipv4->prefixlen <= 8) {
if (pe->destination->prefixlen <= 8) {
stream_putw(s, 0x001A);
length = 0x001A;
}
if ((pe->destination_ipv4->prefixlen > 8)
&& (pe->destination_ipv4->prefixlen <= 16)) {
if ((pe->destination->prefixlen > 8)
&& (pe->destination->prefixlen <= 16)) {
stream_putw(s, 0x001B);
length = 0x001B;
}
if ((pe->destination_ipv4->prefixlen > 16)
&& (pe->destination_ipv4->prefixlen <= 24)) {
if ((pe->destination->prefixlen > 16)
&& (pe->destination->prefixlen <= 24)) {
stream_putw(s, 0x001C);
length = 0x001C;
}
if (pe->destination_ipv4->prefixlen > 24) {
if (pe->destination->prefixlen > 24) {
stream_putw(s, 0x001D);
length = 0x001D;
}
@ -1220,34 +1200,18 @@ u_int16_t eigrp_add_internalTLV_to_stream(struct stream *s,
stream_putc(s, pe->reported_metric.tag);
stream_putc(s, pe->reported_metric.flags);
stream_putc(s, pe->destination_ipv4->prefixlen);
stream_putc(s, pe->destination->prefixlen);
if (pe->destination_ipv4->prefixlen <= 8) {
stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
}
if ((pe->destination_ipv4->prefixlen > 8)
&& (pe->destination_ipv4->prefixlen <= 16)) {
stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
stream_putc(s, pe->destination->u.prefix4.s_addr & 0xFF);
if (pe->destination->prefixlen > 8)
stream_putc(s,
(pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
}
if ((pe->destination_ipv4->prefixlen > 16)
&& (pe->destination_ipv4->prefixlen <= 24)) {
stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
(pe->destination->u.prefix4.s_addr >> 8) & 0xFF);
if (pe->destination->prefixlen > 16)
stream_putc(s,
(pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
(pe->destination->u.prefix4.s_addr >> 16) & 0xFF);
if (pe->destination->prefixlen > 24)
stream_putc(s,
(pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF);
}
if (pe->destination_ipv4->prefixlen > 24) {
stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
stream_putc(s,
(pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
stream_putc(s,
(pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF);
stream_putc(s,
(pe->destination_ipv4->prefix.s_addr >> 24) & 0xFF);
}
(pe->destination->u.prefix4.s_addr >> 24) & 0xFF);
return length;
}
@ -1362,16 +1326,6 @@ void eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *authTLV)
XFREE(MTYPE_EIGRP_AUTH_SHA256_TLV, authTLV);
}
struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new()
{
struct TLV_IPv4_Internal_type *new;
new = XCALLOC(MTYPE_EIGRP_IPV4_INT_TLV,
sizeof(struct TLV_IPv4_Internal_type));
return new;
}
void eigrp_IPv4_InternalTLV_free(
struct TLV_IPv4_Internal_type *IPv4_InternalTLV)
{

View File

@ -36,23 +36,21 @@
extern int eigrp_read(struct thread *);
extern int eigrp_write(struct thread *);
extern struct eigrp_packet *eigrp_packet_new(size_t);
extern struct eigrp_packet *eigrp_packet_new(size_t, struct eigrp_neighbor *);
extern struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *,
struct eigrp_neighbor *);
extern void eigrp_packet_free(struct eigrp_packet *);
extern void eigrp_packet_delete(struct eigrp_interface *);
extern void eigrp_packet_header_init(int, struct eigrp_interface *,
extern void eigrp_packet_header_init(int, struct eigrp *,
struct stream *, u_int32_t, u_int32_t,
u_int32_t);
extern void eigrp_packet_checksum(struct eigrp_interface *, struct stream *,
u_int16_t);
extern struct eigrp_fifo *eigrp_fifo_new(void);
extern struct eigrp_packet *eigrp_fifo_head(struct eigrp_fifo *);
extern struct eigrp_packet *eigrp_fifo_tail(struct eigrp_fifo *);
extern struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *);
extern struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *);
extern struct eigrp_packet *eigrp_fifo_pop_tail(struct eigrp_fifo *);
extern void eigrp_fifo_push_head(struct eigrp_fifo *, struct eigrp_packet *);
extern void eigrp_fifo_push(struct eigrp_fifo *, struct eigrp_packet *);
extern void eigrp_fifo_free(struct eigrp_fifo *);
extern void eigrp_fifo_reset(struct eigrp_fifo *);
@ -73,6 +71,7 @@ extern int eigrp_unack_multicast_packet_retrans(struct thread *);
* untill there is reason to have their own header, these externs are found in
* eigrp_hello.c
*/
extern void eigrp_sw_version_initialize(void);
extern void eigrp_hello_send(struct eigrp_interface *, u_char,
struct in_addr *);
extern void eigrp_hello_send_ack(struct eigrp_neighbor *);
@ -153,7 +152,6 @@ extern int eigrp_check_sha256_digest(struct stream *,
struct eigrp_neighbor *, u_char);
extern struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new(void);
extern void eigrp_IPv4_InternalTLV_free(struct TLV_IPv4_Internal_type *);
extern struct TLV_Sequence_Type *eigrp_SequenceTLV_new(void);

View File

@ -91,8 +91,10 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph,
{
struct eigrp_neighbor *nbr;
struct TLV_IPv4_Internal_type *tlv;
struct prefix dest_addr;
u_int16_t type;
u_int16_t length;
/* increment statistics. */
ei->query_in++;
@ -107,15 +109,14 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph,
while (s->endp > s->getp) {
type = stream_getw(s);
if (type == EIGRP_TLV_IPv4_INT) {
struct prefix_ipv4 dest_addr;
switch (type) {
case EIGRP_TLV_IPv4_INT:
stream_set_getp(s, s->getp - sizeof(u_int16_t));
tlv = eigrp_read_ipv4_tlv(s);
dest_addr.family = AF_INET;
dest_addr.prefix = tlv->destination;
dest_addr.u.prefix4 = tlv->destination;
dest_addr.prefixlen = tlv->prefix_length;
struct eigrp_prefix_entry *dest =
eigrp_topology_table_lookup_ipv4(
@ -124,24 +125,32 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph,
/* If the destination exists (it should, but one never
* know)*/
if (dest != NULL) {
struct eigrp_fsm_action_message *msg;
msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
sizeof(struct
eigrp_fsm_action_message));
struct eigrp_fsm_action_message msg;
struct eigrp_neighbor_entry *entry =
eigrp_prefix_entry_lookup(dest->entries,
nbr);
msg->packet_type = EIGRP_OPC_QUERY;
msg->eigrp = eigrp;
msg->data_type = EIGRP_TLV_IPv4_INT;
msg->adv_router = nbr;
msg->data.ipv4_int_type = tlv;
msg->entry = entry;
msg->prefix = dest;
int event = eigrp_get_fsm_event(msg);
eigrp_fsm_event(msg, event);
msg.packet_type = EIGRP_OPC_QUERY;
msg.eigrp = eigrp;
msg.data_type = EIGRP_INT;
msg.adv_router = nbr;
msg.metrics = tlv->metric;
msg.entry = entry;
msg.prefix = dest;
eigrp_fsm_event(&msg);
}
eigrp_IPv4_InternalTLV_free(tlv);
break;
case EIGRP_TLV_IPv4_EXT:
/* DVS: processing of external routes needs packet and fsm work.
* for now, lets just not creash the box
*/
default:
length = stream_getw(s);
// -2 for type, -2 for len
for (length-=4; length ; length--) {
(void)stream_getc(s);
}
}
}
eigrp_hello_send_ack(nbr);
@ -159,10 +168,10 @@ void eigrp_send_query(struct eigrp_interface *ei)
char has_tlv;
bool ep_saved = false;
ep = eigrp_packet_new(ei->ifp->mtu);
ep = eigrp_packet_new(ei->ifp->mtu, NULL);
/* Prepare EIGRP INIT UPDATE header */
eigrp_packet_header_init(EIGRP_OPC_QUERY, ei, ep->s, 0,
eigrp_packet_header_init(EIGRP_OPC_QUERY, ei->eigrp, ep->s, 0,
ei->eigrp->sequence_number, 0);
// encode Authentication TLV, if needed
@ -207,7 +216,7 @@ void eigrp_send_query(struct eigrp_interface *ei)
for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr)) {
if (nbr->state == EIGRP_NEIGHBOR_UP) {
/*Put packet to retransmission queue*/
eigrp_fifo_push_head(nbr->retrans_queue, ep);
eigrp_fifo_push(nbr->retrans_queue, ep);
ep_saved = true;
if (nbr->retrans_queue->count == 1) {

View File

@ -84,40 +84,36 @@ void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
plist = e->prefix[EIGRP_FILTER_OUT];
alist_i = nbr->ei->list[EIGRP_FILTER_OUT];
plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT];
zlog_info("REPLY Send: Filtering");
zlog_info("REPLY SEND Prefix: %s", inet_ntoa(nbr->src));
/* Check if any list fits */
if ((alist
&& access_list_apply(alist, (struct prefix *)pe2->destination_ipv4)
&& access_list_apply(alist, pe2->destination)
== FILTER_DENY)
|| (plist
&& prefix_list_apply(plist,
(struct prefix *)pe2->destination_ipv4)
pe2->destination)
== PREFIX_DENY)
|| (alist_i
&& access_list_apply(alist_i,
(struct prefix *)pe2->destination_ipv4)
pe2->destination)
== FILTER_DENY)
|| (plist_i
&& prefix_list_apply(plist_i,
(struct prefix *)pe2->destination_ipv4)
pe2->destination)
== PREFIX_DENY)) {
zlog_info("REPLY SEND: Setting Metric to max");
pe2->reported_metric.delay = EIGRP_MAX_METRIC;
} else {
zlog_info("REPLY SEND: Not setting metric");
}
/*
* End of filtering
*/
ep = eigrp_packet_new(nbr->ei->ifp->mtu);
ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
/* Prepare EIGRP INIT UPDATE header */
eigrp_packet_header_init(EIGRP_OPC_REPLY, nbr->ei, ep->s, 0,
eigrp_packet_header_init(EIGRP_OPC_REPLY, e, ep->s, 0,
nbr->ei->eigrp->sequence_number, 0);
// encode Authentication TLV, if needed
@ -144,7 +140,7 @@ void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
ep->sequence_number = nbr->ei->eigrp->sequence_number;
/*Put packet to retransmission queue*/
eigrp_fifo_push_head(nbr->retrans_queue, ep);
eigrp_fifo_push(nbr->retrans_queue, ep);
if (nbr->retrans_queue->count == 1) {
eigrp_send_packet_reliably(nbr);
@ -183,14 +179,14 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
while (s->endp > s->getp) {
type = stream_getw(s);
if (type == EIGRP_TLV_IPv4_INT) {
struct prefix_ipv4 dest_addr;
struct prefix dest_addr;
stream_set_getp(s, s->getp - sizeof(u_int16_t));
tlv = eigrp_read_ipv4_tlv(s);
dest_addr.family = AF_INET;
dest_addr.prefix = tlv->destination;
dest_addr.u.prefix4 = tlv->destination;
dest_addr.prefixlen = tlv->prefix_length;
struct eigrp_prefix_entry *dest =
eigrp_topology_table_lookup_ipv4(
@ -200,9 +196,7 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
*/
assert(dest);
struct eigrp_fsm_action_message *msg;
msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
sizeof(struct eigrp_fsm_action_message));
struct eigrp_fsm_action_message msg;
struct eigrp_neighbor_entry *entry =
eigrp_prefix_entry_lookup(dest->entries, nbr);
@ -241,15 +235,14 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
* End of filtering
*/
msg->packet_type = EIGRP_OPC_REPLY;
msg->eigrp = eigrp;
msg->data_type = EIGRP_TLV_IPv4_INT;
msg->adv_router = nbr;
msg->data.ipv4_int_type = tlv;
msg->entry = entry;
msg->prefix = dest;
int event = eigrp_get_fsm_event(msg);
eigrp_fsm_event(msg, event);
msg.packet_type = EIGRP_OPC_REPLY;
msg.eigrp = eigrp;
msg.data_type = EIGRP_INT;
msg.adv_router = nbr;
msg.metrics = tlv->metric;
msg.entry = entry;
msg.prefix = dest;
eigrp_fsm_event(&msg);
eigrp_IPv4_InternalTLV_free(tlv);

View File

@ -78,14 +78,14 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
while (s->endp > s->getp) {
type = stream_getw(s);
if (type == EIGRP_TLV_IPv4_INT) {
struct prefix_ipv4 dest_addr;
struct prefix dest_addr;
stream_set_getp(s, s->getp - sizeof(u_int16_t));
tlv = eigrp_read_ipv4_tlv(s);
dest_addr.family = AFI_IP;
dest_addr.prefix = tlv->destination;
dest_addr.u.prefix4 = tlv->destination;
dest_addr.prefixlen = tlv->prefix_length;
struct eigrp_prefix_entry *dest =
eigrp_topology_table_lookup_ipv4(
@ -94,22 +94,18 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
/* If the destination exists (it should, but one never
* know)*/
if (dest != NULL) {
struct eigrp_fsm_action_message *msg;
msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
sizeof(struct
eigrp_fsm_action_message));
struct eigrp_fsm_action_message msg;
struct eigrp_neighbor_entry *entry =
eigrp_prefix_entry_lookup(dest->entries,
nbr);
msg->packet_type = EIGRP_OPC_SIAQUERY;
msg->eigrp = eigrp;
msg->data_type = EIGRP_TLV_IPv4_INT;
msg->adv_router = nbr;
msg->data.ipv4_int_type = tlv;
msg->entry = entry;
msg->prefix = dest;
int event = eigrp_get_fsm_event(msg);
eigrp_fsm_event(msg, event);
msg.packet_type = EIGRP_OPC_SIAQUERY;
msg.eigrp = eigrp;
msg.data_type = EIGRP_INT;
msg.adv_router = nbr;
msg.metrics = tlv->metric;
msg.entry = entry;
msg.prefix = dest;
eigrp_fsm_event(&msg);
}
eigrp_IPv4_InternalTLV_free(tlv);
}
@ -123,10 +119,10 @@ void eigrp_send_siaquery(struct eigrp_neighbor *nbr,
struct eigrp_packet *ep;
u_int16_t length = EIGRP_HEADER_LEN;
ep = eigrp_packet_new(nbr->ei->ifp->mtu);
ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
/* Prepare EIGRP INIT UPDATE header */
eigrp_packet_header_init(EIGRP_OPC_SIAQUERY, nbr->ei, ep->s, 0,
eigrp_packet_header_init(EIGRP_OPC_SIAQUERY, nbr->ei->eigrp, ep->s, 0,
nbr->ei->eigrp->sequence_number, 0);
// encode Authentication TLV, if needed
@ -153,7 +149,7 @@ void eigrp_send_siaquery(struct eigrp_neighbor *nbr,
if (nbr->state == EIGRP_NEIGHBOR_UP) {
/*Put packet to retransmission queue*/
eigrp_fifo_push_head(nbr->retrans_queue, ep);
eigrp_fifo_push(nbr->retrans_queue, ep);
if (nbr->retrans_queue->count == 1) {
eigrp_send_packet_reliably(nbr);

View File

@ -77,14 +77,14 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
while (s->endp > s->getp) {
type = stream_getw(s);
if (type == EIGRP_TLV_IPv4_INT) {
struct prefix_ipv4 dest_addr;
struct prefix dest_addr;
stream_set_getp(s, s->getp - sizeof(u_int16_t));
tlv = eigrp_read_ipv4_tlv(s);
dest_addr.family = AFI_IP;
dest_addr.prefix = tlv->destination;
dest_addr.u.prefix4 = tlv->destination;
dest_addr.prefixlen = tlv->prefix_length;
struct eigrp_prefix_entry *dest =
eigrp_topology_table_lookup_ipv4(
@ -93,22 +93,18 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
/* If the destination exists (it should, but one never
* know)*/
if (dest != NULL) {
struct eigrp_fsm_action_message *msg;
msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
sizeof(struct
eigrp_fsm_action_message));
struct eigrp_fsm_action_message msg;
struct eigrp_neighbor_entry *entry =
eigrp_prefix_entry_lookup(dest->entries,
nbr);
msg->packet_type = EIGRP_OPC_SIAQUERY;
msg->eigrp = eigrp;
msg->data_type = EIGRP_TLV_IPv4_INT;
msg->adv_router = nbr;
msg->data.ipv4_int_type = tlv;
msg->entry = entry;
msg->prefix = dest;
int event = eigrp_get_fsm_event(msg);
eigrp_fsm_event(msg, event);
msg.packet_type = EIGRP_OPC_SIAQUERY;
msg.eigrp = eigrp;
msg.data_type = EIGRP_INT;
msg.adv_router = nbr;
msg.metrics = tlv->metric;
msg.entry = entry;
msg.prefix = dest;
eigrp_fsm_event(&msg);
}
eigrp_IPv4_InternalTLV_free(tlv);
}
@ -122,10 +118,10 @@ void eigrp_send_siareply(struct eigrp_neighbor *nbr,
struct eigrp_packet *ep;
u_int16_t length = EIGRP_HEADER_LEN;
ep = eigrp_packet_new(nbr->ei->ifp->mtu);
ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
/* Prepare EIGRP INIT UPDATE header */
eigrp_packet_header_init(EIGRP_OPC_SIAREPLY, nbr->ei, ep->s, 0,
eigrp_packet_header_init(EIGRP_OPC_SIAREPLY, nbr->ei->eigrp, ep->s, 0,
nbr->ei->eigrp->sequence_number, 0);
// encode Authentication TLV, if needed
@ -152,7 +148,7 @@ void eigrp_send_siareply(struct eigrp_neighbor *nbr,
if (nbr->state == EIGRP_NEIGHBOR_UP) {
/*Put packet to retransmission queue*/
eigrp_fifo_push_head(nbr->retrans_queue, ep);
eigrp_fifo_push(nbr->retrans_queue, ep);
if (nbr->retrans_queue->count == 1) {
eigrp_send_packet_reliably(nbr);

View File

@ -311,6 +311,8 @@ struct eigrp_packet {
/* EIGRP packet length. */
u_int16_t length;
struct eigrp_neighbor *nbr;
};
struct eigrp_fifo {
@ -467,10 +469,7 @@ struct eigrp_prefix_entry {
u_char af; // address family
u_char req_action; // required action
struct prefix_ipv4
*destination_ipv4; // pointer to struct with ipv4 address
struct prefix_ipv6
*destination_ipv6; // pointer to struct with ipv6 address
struct prefix *destination;
// If network type is REMOTE_EXTERNAL, pointer will have reference to
// its external TLV
@ -497,6 +496,11 @@ struct eigrp_neighbor_entry {
};
//---------------------------------------------------------------------------------------------------------------------------------------------
typedef enum {
EIGRP_CONNECTED,
EIGRP_INT,
EIGRP_EXT,
} msg_data_t;
/* EIGRP Finite State Machine */
@ -506,11 +510,8 @@ struct eigrp_fsm_action_message {
struct eigrp_neighbor *adv_router; // advertising neighbor
struct eigrp_neighbor_entry *entry;
struct eigrp_prefix_entry *prefix;
int data_type; // internal or external tlv type
union {
struct TLV_IPv4_External_type *ipv4_ext_data;
struct TLV_IPv4_Internal_type *ipv4_int_type;
} data;
msg_data_t data_type; // internal or external tlv type
struct eigrp_metrics metrics;
};
#endif /* _ZEBRA_EIGRP_STRUCTURES_H_ */

View File

@ -81,25 +81,18 @@ static int eigrp_prefix_entry_cmp(struct eigrp_prefix_entry *node1,
{
if (node1->af == AF_INET) {
if (node2->af == AF_INET) {
if (node1->destination_ipv4->prefix.s_addr
< node2->destination_ipv4->prefix.s_addr) {
return -1; // if it belong above node2
} else {
if (node1->destination_ipv4->prefix.s_addr
> node2->destination_ipv4->prefix.s_addr) {
return 1; // if it belongs under node2
} else {
return 0; // same value... ERROR...in
// case of adding same prefix
// again
}
}
} else {
if (node1->destination->u.prefix4.s_addr
< node2->destination->u.prefix4.s_addr)
return -1;
if (node1->destination->u.prefix4.s_addr
> node2->destination->u.prefix4.s_addr)
return 1;
else
return 0;
} else
return 1;
}
} else { // TODO check if the prefix dont exists
return 1; // add to end
}
} else
return 1;
}
/*
@ -125,8 +118,7 @@ struct eigrp_prefix_entry *eigrp_prefix_entry_new()
new->rij = list_new();
new->entries->cmp = (int (*)(void *, void *))eigrp_neighbor_entry_cmp;
new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC;
new->destination_ipv4 = NULL;
new->destination_ipv6 = NULL;
new->destination = NULL;
return new;
}
@ -137,9 +129,8 @@ struct eigrp_prefix_entry *eigrp_prefix_entry_new()
static int eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *entry1,
struct eigrp_neighbor_entry *entry2)
{
if (entry1->distance
< entry2->distance) // parameter used in list_add_sort ()
return -1; // actually set to sort by distance
if (entry1->distance < entry2->distance)
return -1;
if (entry1->distance > entry2->distance)
return 1;
@ -205,7 +196,7 @@ void eigrp_neighbor_entry_add(struct eigrp_prefix_entry *node,
listnode_add_sort(node->entries, entry);
entry->prefix = node;
eigrp_zebra_route_add(node->destination_ipv4, l);
eigrp_zebra_route_add(node->destination, l);
}
list_delete(l);
@ -230,7 +221,7 @@ void eigrp_prefix_entry_delete(struct list *topology,
list_free(node->entries);
list_free(node->rij);
listnode_delete(topology, node);
eigrp_zebra_route_delete(node->destination_ipv4);
eigrp_zebra_route_delete(node->destination);
XFREE(MTYPE_EIGRP_PREFIX_ENTRY, node);
}
}
@ -243,7 +234,7 @@ void eigrp_neighbor_entry_delete(struct eigrp_prefix_entry *node,
{
if (listnode_lookup(node->entries, entry) != NULL) {
listnode_delete(node->entries, entry);
eigrp_zebra_route_delete(node->destination_ipv4);
eigrp_zebra_route_delete(node->destination);
XFREE(MTYPE_EIGRP_NEIGHBOR_ENTRY, entry);
}
}
@ -270,16 +261,12 @@ unsigned int eigrp_topology_table_isempty(struct list *topology)
struct eigrp_prefix_entry *
eigrp_topology_table_lookup_ipv4(struct list *topology_table,
struct prefix_ipv4 *address)
struct prefix *address)
{
struct eigrp_prefix_entry *data;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(topology_table, node, data)) {
if ((data->af == AF_INET)
&& (data->destination_ipv4->prefix.s_addr
== address->prefix.s_addr)
&& (data->destination_ipv4->prefixlen
== address->prefixlen))
if (prefix_same(data->destination, address))
return data;
}
@ -380,37 +367,56 @@ enum metric_change eigrp_topology_update_distance(struct eigrp_fsm_action_messag
struct eigrp_prefix_entry *prefix = msg->prefix;
struct eigrp_neighbor_entry *entry = msg->entry;
enum metric_change change = METRIC_SAME;
u_int32_t new_reported_distance;
assert(entry);
struct TLV_IPv4_External_type *ext_data = NULL;
struct TLV_IPv4_Internal_type *int_data = NULL;
if (msg->data_type == EIGRP_TLV_IPv4_INT) {
u_int32_t new_reported_distance;
switch(msg->data_type) {
case EIGRP_CONNECTED:
if (prefix->nt == EIGRP_TOPOLOGY_TYPE_CONNECTED)
return change;
int_data = msg->data.ipv4_int_type;
if (eigrp_metrics_is_same(int_data->metric,
change = METRIC_DECREASE;
break;
case EIGRP_INT:
if (prefix->nt == EIGRP_TOPOLOGY_TYPE_CONNECTED) {
change = METRIC_INCREASE;
goto distance_done;
}
if (eigrp_metrics_is_same(msg->metrics,
entry->reported_metric)) {
return change; // No change
}
new_reported_distance = eigrp_calculate_metrics(eigrp,
int_data->metric);
msg->metrics);
if (entry->reported_distance < new_reported_distance)
if (entry->reported_distance < new_reported_distance) {
change = METRIC_INCREASE;
else
goto distance_done;
} else
change = METRIC_DECREASE;
entry->reported_metric = int_data->metric;
entry->reported_metric = msg->metrics;
entry->reported_distance = new_reported_distance;
eigrp_calculate_metrics(eigrp, int_data->metric);
eigrp_calculate_metrics(eigrp, msg->metrics);
entry->distance = eigrp_calculate_total_metrics(eigrp, entry);
} else {
ext_data = msg->data.ipv4_ext_data;
if (eigrp_metrics_is_same(ext_data->metric,
entry->reported_metric))
return change;
break;
case EIGRP_EXT:
if (prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL) {
if (eigrp_metrics_is_same(msg->metrics,
entry->reported_metric))
return change;
} else {
change = METRIC_INCREASE;
goto distance_done;
}
break;
default:
zlog_err("%s: Please implement handler", __PRETTY_FUNCTION__);
break;
}
distance_done:
/*
* Move to correct position in list according to new distance
*/
@ -464,13 +470,14 @@ void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix)
struct eigrp_neighbor_entry *entry;
if (successors) {
eigrp_zebra_route_add(prefix->destination_ipv4, successors);
eigrp_zebra_route_add(prefix->destination,
successors);
for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
entry->flags |= EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG;
list_delete(successors);
} else {
eigrp_zebra_route_delete(prefix->destination_ipv4);
eigrp_zebra_route_delete(prefix->destination);
for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry))
entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG;
}
@ -485,24 +492,19 @@ void eigrp_topology_neighbor_down(struct eigrp *eigrp,
for (ALL_LIST_ELEMENTS(eigrp->topology_table, node1, node11, prefix)) {
for (ALL_LIST_ELEMENTS(prefix->entries, node2, node22, entry)) {
if (entry->adv_router == nbr) {
struct eigrp_fsm_action_message *msg;
msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
sizeof(struct
eigrp_fsm_action_message));
struct TLV_IPv4_Internal_type *tlv =
eigrp_IPv4_InternalTLV_new();
tlv->metric.delay = EIGRP_MAX_METRIC;
msg->packet_type = EIGRP_OPC_UPDATE;
msg->eigrp = eigrp;
msg->data_type = EIGRP_TLV_IPv4_INT;
msg->adv_router = nbr;
msg->data.ipv4_int_type = tlv;
msg->entry = entry;
msg->prefix = prefix;
int event = eigrp_get_fsm_event(msg);
eigrp_fsm_event(msg, event);
}
struct eigrp_fsm_action_message msg;
if (entry->adv_router != nbr)
continue;
msg.metrics.delay = EIGRP_MAX_METRIC;
msg.packet_type = EIGRP_OPC_UPDATE;
msg.eigrp = eigrp;
msg.data_type = EIGRP_INT;
msg.adv_router = nbr;
msg.entry = entry;
msg.prefix = prefix;
eigrp_fsm_event(&msg);
}
}

View File

@ -49,7 +49,7 @@ extern void eigrp_neighbor_entry_delete(struct eigrp_prefix_entry *,
extern void eigrp_topology_delete_all(struct list *);
extern unsigned int eigrp_topology_table_isempty(struct list *);
extern struct eigrp_prefix_entry *
eigrp_topology_table_lookup_ipv4(struct list *, struct prefix_ipv4 *);
eigrp_topology_table_lookup_ipv4(struct list *, struct prefix *);
extern struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *);
extern struct list *
eigrp_topology_get_successor_max(struct eigrp_prefix_entry *pe,

View File

@ -112,47 +112,31 @@ static void eigrp_update_receive_GR_ask(struct eigrp *eigrp,
{
struct listnode *node1;
struct eigrp_prefix_entry *prefix;
struct TLV_IPv4_Internal_type *tlv_max;
struct eigrp_fsm_action_message fsm_msg;
/* iterate over all prefixes which weren't advertised by neighbor */
for (ALL_LIST_ELEMENTS_RO(nbr_prefixes, node1, prefix)) {
zlog_debug("GR receive: Neighbor not advertised %s/%d",
inet_ntoa(prefix->destination_ipv4->prefix),
prefix->destination_ipv4->prefixlen);
char buffer[PREFIX_STRLEN];
zlog_debug("GR receive: Neighbor not advertised %s",
prefix2str(prefix->destination,
buffer, PREFIX_STRLEN));
/* create internal IPv4 TLV with infinite delay */
tlv_max = eigrp_IPv4_InternalTLV_new();
tlv_max->type = EIGRP_TLV_IPv4_INT;
tlv_max->length = 28U;
tlv_max->metric = prefix->reported_metric;
fsm_msg.metrics = prefix->reported_metric;
/* set delay to MAX */
tlv_max->metric.delay = EIGRP_MAX_METRIC;
tlv_max->destination = prefix->destination_ipv4->prefix;
tlv_max->prefix_length = prefix->destination_ipv4->prefixlen;
/* prepare message for FSM */
struct eigrp_fsm_action_message *fsm_msg;
fsm_msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
sizeof(struct eigrp_fsm_action_message));
fsm_msg.metrics.delay = EIGRP_MAX_METRIC;
struct eigrp_neighbor_entry *entry =
eigrp_prefix_entry_lookup(prefix->entries, nbr);
fsm_msg->packet_type = EIGRP_OPC_UPDATE;
fsm_msg->eigrp = eigrp;
fsm_msg->data_type = EIGRP_TLV_IPv4_INT;
fsm_msg->adv_router = nbr;
fsm_msg->data.ipv4_int_type = tlv_max;
fsm_msg->entry = entry;
fsm_msg->prefix = prefix;
fsm_msg.packet_type = EIGRP_OPC_UPDATE;
fsm_msg.eigrp = eigrp;
fsm_msg.data_type = EIGRP_INT;
fsm_msg.adv_router = nbr;
fsm_msg.entry = entry;
fsm_msg.prefix = prefix;
/* send message to FSM */
int event = eigrp_get_fsm_event(fsm_msg);
eigrp_fsm_event(fsm_msg, event);
/* free memory used by TLV */
eigrp_IPv4_InternalTLV_free(tlv_max);
eigrp_fsm_event(&fsm_msg);
}
}
@ -169,9 +153,11 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
struct eigrp_neighbor_entry *ne;
u_int32_t flags;
u_int16_t type;
u_int16_t length;
u_char same;
struct access_list *alist;
struct prefix_list *plist;
struct prefix dest_addr;
struct eigrp *e;
u_char graceful_restart;
u_char graceful_restart_final;
@ -287,16 +273,15 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
/*If there is topology information*/
while (s->endp > s->getp) {
type = stream_getw(s);
if (type == EIGRP_TLV_IPv4_INT) {
struct prefix_ipv4 dest_addr;
switch (type) {
case EIGRP_TLV_IPv4_INT:
stream_set_getp(s, s->getp - sizeof(u_int16_t));
tlv = eigrp_read_ipv4_tlv(s);
/*searching if destination exists */
dest_addr.family = AF_INET;
dest_addr.prefix = tlv->destination;
dest_addr.u.prefix4 = tlv->destination;
dest_addr.prefixlen = tlv->prefix_length;
struct eigrp_prefix_entry *dest =
eigrp_topology_table_lookup_ipv4(
@ -310,31 +295,26 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
remove_received_prefix_gr(nbr_prefixes,
dest);
struct eigrp_fsm_action_message *msg;
msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
sizeof(struct
eigrp_fsm_action_message));
struct eigrp_fsm_action_message msg;
struct eigrp_neighbor_entry *entry =
eigrp_prefix_entry_lookup(dest->entries,
nbr);
msg->packet_type = EIGRP_OPC_UPDATE;
msg->eigrp = eigrp;
msg->data_type = EIGRP_TLV_IPv4_INT;
msg->adv_router = nbr;
msg->data.ipv4_int_type = tlv;
msg->entry = entry;
msg->prefix = dest;
int event = eigrp_get_fsm_event(msg);
eigrp_fsm_event(msg, event);
msg.packet_type = EIGRP_OPC_UPDATE;
msg.eigrp = eigrp;
msg.data_type = EIGRP_INT;
msg.adv_router = nbr;
msg.metrics = tlv->metric;
msg.entry = entry;
msg.prefix = dest;
eigrp_fsm_event(&msg);
} else {
/*Here comes topology information save*/
pe = eigrp_prefix_entry_new();
pe->serno = eigrp->serno;
pe->destination_ipv4 = prefix_ipv4_new();
prefix_copy(
(struct prefix *)pe->destination_ipv4,
(struct prefix *)&dest_addr);
pe->destination = (struct prefix *)prefix_ipv4_new();
prefix_copy(pe->destination,
&dest_addr);
pe->af = AF_INET;
pe->state = EIGRP_FSM_STATE_PASSIVE;
pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE;
@ -358,9 +338,8 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
/* Check if access-list fits */
if (alist
&& access_list_apply(
alist,
(struct prefix *)&dest_addr)
&& access_list_apply(alist,
&dest_addr)
== FILTER_DENY) {
/* If yes, set reported metric to Max */
ne->reported_metric.delay =
@ -375,9 +354,8 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
/* Check if prefix-list fits */
if (plist
&& prefix_list_apply(
plist,
(struct prefix *)&dest_addr)
&& prefix_list_apply(plist,
&dest_addr)
== PREFIX_DENY) {
/* If yes, set reported metric to Max */
ne->reported_metric.delay =
@ -389,9 +367,8 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
/* Check if access-list fits */
if (alist
&& access_list_apply(
alist,
(struct prefix *)&dest_addr)
&& access_list_apply(alist,
&dest_addr)
== FILTER_DENY) {
/* If yes, set reported metric to Max */
ne->reported_metric.delay =
@ -402,9 +379,8 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
/* Check if prefix-list fits */
if (plist
&& prefix_list_apply(
plist,
(struct prefix *)&dest_addr)
&& prefix_list_apply(plist,
&dest_addr)
== PREFIX_DENY) {
/* If yes, set reported metric to Max */
ne->reported_metric.delay =
@ -436,6 +412,18 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
pe);
}
eigrp_IPv4_InternalTLV_free(tlv);
break;
case EIGRP_TLV_IPv4_EXT:
/* DVS: processing of external routes needs packet and fsm work.
* for now, lets just not creash the box
*/
default:
length = stream_getw(s);
// -2 for type, -2 for len
for (length-=4; length ; length--) {
(void)stream_getc(s);
}
}
}
@ -463,7 +451,7 @@ void eigrp_update_send_init(struct eigrp_neighbor *nbr)
struct eigrp_packet *ep;
u_int16_t length = EIGRP_HEADER_LEN;
ep = eigrp_packet_new(nbr->ei->ifp->mtu);
ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
/* Prepare EIGRP INIT UPDATE header */
if (IS_DEBUG_EIGRP_PACKET(0, RECV))
@ -471,9 +459,10 @@ void eigrp_update_send_init(struct eigrp_neighbor *nbr)
nbr->ei->eigrp->sequence_number,
nbr->recv_sequence_number);
eigrp_packet_header_init(
EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_INIT_FLAG,
nbr->ei->eigrp->sequence_number, nbr->recv_sequence_number);
eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp,
ep->s, EIGRP_INIT_FLAG,
nbr->ei->eigrp->sequence_number,
nbr->recv_sequence_number);
// encode Authentication TLV, if needed
if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
@ -497,7 +486,7 @@ void eigrp_update_send_init(struct eigrp_neighbor *nbr)
ep->length, ep->sequence_number, inet_ntoa(ep->dst));
/*Put packet to retransmission queue*/
eigrp_fifo_push_head(nbr->retrans_queue, ep);
eigrp_fifo_push(nbr->retrans_queue, ep);
if (nbr->retrans_queue->count == 1) {
eigrp_send_packet_reliably(nbr);
@ -528,7 +517,42 @@ static void eigrp_update_place_on_nbr_queue(struct eigrp_neighbor *nbr,
ep->length, ep->sequence_number, inet_ntoa(ep->dst));
/*Put packet to retransmission queue*/
eigrp_fifo_push_head(nbr->retrans_queue, ep);
eigrp_fifo_push(nbr->retrans_queue, ep);
if (nbr->retrans_queue->count == 1)
eigrp_send_packet_reliably(nbr);
}
static void eigrp_update_send_to_all_nbrs(struct eigrp_interface *ei,
struct eigrp_packet *ep)
{
struct listnode *node, *nnode;
struct eigrp_neighbor *nbr;
bool packet_sent = false;
for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr)) {
struct eigrp_packet *ep_dup;
if (nbr->state != EIGRP_NEIGHBOR_UP)
continue;
if (packet_sent)
ep_dup = eigrp_packet_duplicate(ep, NULL);
else
ep_dup = ep;
ep_dup->nbr = nbr;
packet_sent = true;
/*Put packet to retransmission queue*/
eigrp_fifo_push(nbr->retrans_queue, ep_dup);
if (nbr->retrans_queue->count == 1) {
eigrp_send_packet_reliably(nbr);
}
}
if (!packet_sent)
eigrp_packet_free(ep);
}
void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
@ -543,15 +567,15 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
struct access_list *alist_i;
struct prefix_list *plist_i;
struct eigrp *e;
struct prefix_ipv4 *dest_addr;
struct prefix *dest_addr;
u_int32_t seq_no = nbr->ei->eigrp->sequence_number;
ep = eigrp_packet_new(nbr->ei->ifp->mtu);
ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
/* Prepare EIGRP EOT UPDATE header */
eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG,
seq_no,
nbr->recv_sequence_number);
eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp,
ep->s, EIGRP_EOT_FLAG,
seq_no, nbr->recv_sequence_number);
// encode Authentication TLV, if needed
if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
@ -561,18 +585,17 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe)) {
for (ALL_LIST_ELEMENTS(pe->entries, node2, nnode2, te)) {
if ((te->ei == nbr->ei)
&& (te->prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE))
if (eigrp_nbr_split_horizon_check(te, nbr->ei))
continue;
if ((length + 0x001D) > (u_int16_t)nbr->ei->ifp->mtu) {
eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length);
eigrp_send_packet_reliably(nbr);
seq_no++;
length = EIGRP_HEADER_LEN;
ep = eigrp_packet_new(nbr->ei->ifp->mtu);
eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG,
ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp,
ep->s, EIGRP_EOT_FLAG,
seq_no, nbr->recv_sequence_number);
if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
@ -582,7 +605,7 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
}
}
/* Get destination address from prefix */
dest_addr = pe->destination_ipv4;
dest_addr = pe->destination;
/*
* Filtering
@ -599,13 +622,13 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
/* Check if any list fits */
if ((alist
&& access_list_apply (alist,
(struct prefix *) dest_addr) == FILTER_DENY)||
dest_addr) == FILTER_DENY)||
(plist && prefix_list_apply (plist,
(struct prefix *) dest_addr) == PREFIX_DENY)||
dest_addr) == PREFIX_DENY)||
(alist_i && access_list_apply (alist_i,
(struct prefix *) dest_addr) == FILTER_DENY)||
dest_addr) == FILTER_DENY)||
(plist_i && prefix_list_apply (plist_i,
(struct prefix *) dest_addr) == PREFIX_DENY)) {
dest_addr) == PREFIX_DENY)) {
//pe->reported_metric.delay = EIGRP_MAX_METRIC;
continue;
} else {
@ -615,14 +638,13 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
}
eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length);
eigrp_send_packet_reliably(nbr);
nbr->ei->eigrp->sequence_number = seq_no++;
}
void eigrp_update_send(struct eigrp_interface *ei)
{
struct eigrp_packet *ep;
struct listnode *node, *nnode;
struct eigrp_neighbor *nbr;
struct eigrp_prefix_entry *pe;
u_char has_tlv;
struct access_list *alist;
@ -630,16 +652,19 @@ void eigrp_update_send(struct eigrp_interface *ei)
struct access_list *alist_i;
struct prefix_list *plist_i;
struct eigrp *e;
struct prefix_ipv4 *dest_addr;
bool packet_sent = false;
struct prefix *dest_addr;
u_int32_t seq_no = ei->eigrp->sequence_number;
if (ei->nbrs->count == 0)
return;
u_int16_t length = EIGRP_HEADER_LEN;
ep = eigrp_packet_new(ei->ifp->mtu);
ep = eigrp_packet_new(ei->ifp->mtu, NULL);
/* Prepare EIGRP INIT UPDATE header */
eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei, ep->s, 0,
ei->eigrp->sequence_number, 0);
eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei->eigrp,
ep->s, 0, seq_no, 0);
// encode Authentication TLV, if needed
if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
@ -650,57 +675,77 @@ void eigrp_update_send(struct eigrp_interface *ei)
has_tlv = 0;
for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node,
nnode, pe)) {
if (pe->req_action & EIGRP_FSM_NEED_UPDATE) {
/* Get destination address from prefix */
dest_addr = pe->destination_ipv4;
struct eigrp_neighbor_entry *ne;
/*
* Filtering
*/
// TODO: Work in progress
/* get list from eigrp process */
e = eigrp_lookup();
/* Get access-lists and prefix-lists from process and
* interface */
alist = e->list[EIGRP_FILTER_OUT];
plist = e->prefix[EIGRP_FILTER_OUT];
alist_i = ei->list[EIGRP_FILTER_OUT];
plist_i = ei->prefix[EIGRP_FILTER_OUT];
if (!(pe->req_action & EIGRP_FSM_NEED_UPDATE))
continue;
/* Check if any list fits */
if ((alist
&& access_list_apply(alist,
(struct prefix *)dest_addr)
== FILTER_DENY)
|| (plist
&& prefix_list_apply(plist,
(struct prefix *)dest_addr)
== PREFIX_DENY)
|| (alist_i
&& access_list_apply(alist_i,
(struct prefix *)dest_addr)
== FILTER_DENY)
|| (plist_i
&& prefix_list_apply(plist_i,
(struct prefix *)dest_addr)
== PREFIX_DENY)) {
zlog_info("PROC OUT: Skipping");
// pe->reported_metric.delay = EIGRP_MAX_METRIC;
zlog_info("PROC OUT Prefix: %s",
inet_ntoa(dest_addr->prefix));
continue;
} else {
zlog_info("PROC OUT: NENastavujem metriku ");
length += eigrp_add_internalTLV_to_stream(ep->s,
pe);
has_tlv = 1;
ne = listnode_head(pe->entries);
if (eigrp_nbr_split_horizon_check(ne, ei))
continue;
if ((length + 0x001D) > (u_int16_t)ei->ifp->mtu) {
if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
&& (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) {
eigrp_make_md5_digest(ei, ep->s, EIGRP_AUTH_UPDATE_FLAG);
}
/*
* End of filtering
*/
/* NULL the pointer */
dest_addr = NULL;
eigrp_packet_checksum(ei, ep->s, length);
ep->length = length;
ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS);
ep->sequence_number = seq_no;
seq_no++;
eigrp_update_send_to_all_nbrs(ei, ep);
length = EIGRP_HEADER_LEN;
ep = eigrp_packet_new(ei->ifp->mtu, NULL);
eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei->eigrp,
ep->s, 0, seq_no, 0);
if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
&& (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) {
length += eigrp_add_authTLV_MD5_to_stream(ep->s, ei);
}
has_tlv = 0;
}
/* Get destination address from prefix */
dest_addr = pe->destination;
/*
* Filtering
*/
e = eigrp_lookup();
/* Get access-lists and prefix-lists from process and
* interface */
alist = e->list[EIGRP_FILTER_OUT];
plist = e->prefix[EIGRP_FILTER_OUT];
alist_i = ei->list[EIGRP_FILTER_OUT];
plist_i = ei->prefix[EIGRP_FILTER_OUT];
/* Check if any list fits */
if ((alist
&& access_list_apply(alist,
dest_addr)
== FILTER_DENY)
|| (plist
&& prefix_list_apply(plist,
dest_addr)
== PREFIX_DENY)
|| (alist_i
&& access_list_apply(alist_i,
dest_addr)
== FILTER_DENY)
|| (plist_i
&& prefix_list_apply(plist_i,
dest_addr)
== PREFIX_DENY)) {
// pe->reported_metric.delay = EIGRP_MAX_METRIC;
continue;
} else {
length += eigrp_add_internalTLV_to_stream(ep->s,
pe);
has_tlv = 1;
}
}
@ -727,20 +772,8 @@ void eigrp_update_send(struct eigrp_interface *ei)
zlog_debug("Enqueuing Update length[%u] Seq [%u]", length,
ep->sequence_number);
for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr)) {
if (nbr->state == EIGRP_NEIGHBOR_UP) {
packet_sent = true;
/*Put packet to retransmission queue*/
eigrp_fifo_push_head(nbr->retrans_queue, ep);
if (nbr->retrans_queue->count == 1) {
eigrp_send_packet_reliably(nbr);
}
}
}
if (!packet_sent)
eigrp_packet_free(ep);
eigrp_update_send_to_all_nbrs(ei, ep);
ei->eigrp->sequence_number = seq_no++;
}
void eigrp_update_send_all(struct eigrp *eigrp,
@ -762,8 +795,6 @@ void eigrp_update_send_all(struct eigrp *eigrp,
pe->req_action &= ~EIGRP_FSM_NEED_UPDATE;
listnode_delete(eigrp->topology_changes_internalIPV4,
pe);
zlog_debug("UPDATE COUNT: %d",
eigrp->topology_changes_internalIPV4->count);
}
}
}
@ -789,14 +820,13 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
u_int16_t length = EIGRP_HEADER_LEN;
struct listnode *node, *nnode;
struct eigrp_prefix_entry *pe;
struct prefix_ipv4 *dest_addr;
struct prefix *dest_addr;
struct eigrp *e;
struct access_list *alist, *alist_i;
struct prefix_list *plist, *plist_i;
struct list *prefixes;
u_int32_t flags;
unsigned int send_prefixes;
struct TLV_IPv4_Internal_type *tlv_max;
/* get prefixes to send to neighbor */
prefixes = nbr->nbr_gr_prefixes_send;
@ -835,10 +865,10 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
}
}
ep = eigrp_packet_new(nbr->ei->ifp->mtu);
ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
/* Prepare EIGRP Graceful restart UPDATE header */
eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, flags,
eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp, ep->s, flags,
nbr->ei->eigrp->sequence_number,
nbr->recv_sequence_number);
@ -853,7 +883,7 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
/*
* Filtering
*/
dest_addr = pe->destination_ipv4;
dest_addr = pe->destination;
/* get list from eigrp process */
e = eigrp_lookup();
/* Get access-lists and prefix-lists from process and interface
@ -865,22 +895,20 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
/* Check if any list fits */
if ((alist
&& access_list_apply(alist, (struct prefix *)dest_addr)
&& access_list_apply(alist, dest_addr)
== FILTER_DENY)
|| (plist
&& prefix_list_apply(plist, (struct prefix *)dest_addr)
&& prefix_list_apply(plist, dest_addr)
== PREFIX_DENY)
|| (alist_i
&& access_list_apply(alist_i,
(struct prefix *)dest_addr)
&& access_list_apply(alist_i, dest_addr)
== FILTER_DENY)
|| (plist_i
&& prefix_list_apply(plist_i,
(struct prefix *)dest_addr)
&& prefix_list_apply(plist_i, dest_addr)
== PREFIX_DENY)) {
/* do not send filtered route */
zlog_info("Filtered prefix %s won't be sent out.",
inet_ntoa(dest_addr->prefix));
inet_ntoa(dest_addr->u.prefix4));
} else {
/* sending route which wasn't filtered */
length += eigrp_add_internalTLV_to_stream(ep->s, pe);
@ -894,56 +922,39 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
/* Check if any list fits */
if ((alist
&& access_list_apply(alist, (struct prefix *)dest_addr)
&& access_list_apply(alist, dest_addr)
== FILTER_DENY)
|| (plist
&& prefix_list_apply(plist, (struct prefix *)dest_addr)
&& prefix_list_apply(plist, dest_addr)
== PREFIX_DENY)
|| (alist_i
&& access_list_apply(alist_i,
(struct prefix *)dest_addr)
&& access_list_apply(alist_i, dest_addr)
== FILTER_DENY)
|| (plist_i
&& prefix_list_apply(plist_i,
(struct prefix *)dest_addr)
&& prefix_list_apply(plist_i, dest_addr)
== PREFIX_DENY)) {
/* do not send filtered route */
zlog_info("Filtered prefix %s will be removed.",
inet_ntoa(dest_addr->prefix));
tlv_max = eigrp_IPv4_InternalTLV_new();
tlv_max->type = EIGRP_TLV_IPv4_INT;
tlv_max->length = 28U;
tlv_max->metric = pe->reported_metric;
/* set delay to MAX */
tlv_max->metric.delay = EIGRP_MAX_METRIC;
tlv_max->destination = pe->destination_ipv4->prefix;
tlv_max->prefix_length =
pe->destination_ipv4->prefixlen;
inet_ntoa(dest_addr->u.prefix4));
/* prepare message for FSM */
struct eigrp_fsm_action_message *fsm_msg;
fsm_msg = XCALLOC(
MTYPE_EIGRP_FSM_MSG,
sizeof(struct eigrp_fsm_action_message));
struct eigrp_fsm_action_message fsm_msg;
struct eigrp_neighbor_entry *entry =
eigrp_prefix_entry_lookup(pe->entries, nbr);
fsm_msg->packet_type = EIGRP_OPC_UPDATE;
fsm_msg->eigrp = e;
fsm_msg->data_type = EIGRP_TLV_IPv4_INT;
fsm_msg->adv_router = nbr;
fsm_msg->data.ipv4_int_type = tlv_max;
fsm_msg->entry = entry;
fsm_msg->prefix = pe;
fsm_msg.packet_type = EIGRP_OPC_UPDATE;
fsm_msg.eigrp = e;
fsm_msg.data_type = EIGRP_INT;
fsm_msg.adv_router = nbr;
fsm_msg.metrics = pe->reported_metric;
/* Set delay to MAX */
fsm_msg.metrics.delay = EIGRP_MAX_METRIC;
fsm_msg.entry = entry;
fsm_msg.prefix = pe;
/* send message to FSM */
int event = eigrp_get_fsm_event(fsm_msg);
eigrp_fsm_event(fsm_msg, event);
/* free memory used by TLV */
eigrp_IPv4_InternalTLV_free(tlv_max);
eigrp_fsm_event(&fsm_msg);
}
/*
* End of filtering
@ -980,7 +991,7 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
ep->length, ep->sequence_number, inet_ntoa(ep->dst));
/*Put packet to retransmission queue*/
eigrp_fifo_push_head(nbr->retrans_queue, ep);
eigrp_fifo_push(nbr->retrans_queue, ep);
if (nbr->retrans_queue->count == 1) {
eigrp_send_packet_reliably(nbr);

View File

@ -391,10 +391,10 @@ DEFUN (eigrp_network,
"EIGRP network prefix\n")
{
VTY_DECLVAR_CONTEXT(eigrp, eigrp);
struct prefix_ipv4 p;
struct prefix p;
int ret;
str2prefix_ipv4(argv[1]->arg, &p);
str2prefix(argv[1]->arg, &p);
ret = eigrp_network_set(eigrp, &p);
@ -414,10 +414,10 @@ DEFUN (no_eigrp_network,
"EIGRP network prefix\n")
{
VTY_DECLVAR_CONTEXT(eigrp, eigrp);
struct prefix_ipv4 p;
struct prefix p;
int ret;
str2prefix_ipv4(argv[2]->arg, &p);
str2prefix(argv[2]->arg, &p);
ret = eigrp_network_unset(eigrp, &p);

View File

@ -66,8 +66,8 @@ static int eigrp_interface_state_down(int, struct zclient *, zebra_size_t,
vrf_id_t vrf_id);
static struct interface *zebra_interface_if_lookup(struct stream *);
static int eigrp_zebra_read_ipv4(int, struct zclient *, zebra_size_t,
vrf_id_t vrf_id);
static int eigrp_zebra_read_route(int, struct zclient *, zebra_size_t,
vrf_id_t vrf_id);
/* Zebra structure to hold current status. */
struct zclient *zclient = NULL;
@ -112,59 +112,31 @@ void eigrp_zebra_init(void)
zclient->interface_down = eigrp_interface_state_down;
zclient->interface_address_add = eigrp_interface_address_add;
zclient->interface_address_delete = eigrp_interface_address_delete;
zclient->redistribute_route_ipv4_add = eigrp_zebra_read_ipv4;
zclient->redistribute_route_ipv4_del = eigrp_zebra_read_ipv4;
zclient->redistribute_route_add = eigrp_zebra_read_route;
zclient->redistribute_route_del = eigrp_zebra_read_route;
}
/* Zebra route add and delete treatment. */
static int eigrp_zebra_read_ipv4(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
static int eigrp_zebra_read_route(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct stream *s;
struct zapi_ipv4 api;
struct prefix_ipv4 p;
struct zapi_route api;
struct eigrp *eigrp;
s = zclient->ibuf;
if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1;
/* Type, flags, message. */
api.type = stream_getc(s);
api.instance = stream_getw(s);
api.flags = stream_getc(s);
api.message = stream_getc(s);
/* IPv4 prefix. */
memset(&p, 0, sizeof(struct prefix_ipv4));
p.family = AF_INET;
p.prefixlen = stream_getc(s);
stream_get(&p.prefix, s, PSIZE(p.prefixlen));
if (IPV4_NET127(ntohl(p.prefix.s_addr)))
if (IPV4_NET127(ntohl(api.prefix.u.prefix4.s_addr)))
return 0;
/* Nexthop, ifindex, distance, metric. */
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
api.nexthop_num = stream_getc(s);
stream_get_ipv4(s);
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
api.ifindex_num = stream_getc(s);
/* XXX assert(api.ifindex_num == 1); */
stream_getl(s); /* ifindex, unused */
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc(s);
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl(s);
eigrp = eigrp_lookup();
if (eigrp == NULL)
return 0;
if (command == ZEBRA_IPV4_ROUTE_ADD) {
if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) {
} else /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */
} else /* if (command == ZEBRA_REDISTRIBUTE_ROUTE_DEL) */
{
}
@ -389,90 +361,67 @@ static struct interface *zebra_interface_if_lookup(struct stream *s)
ifname_tmp, strnlen(ifname_tmp, INTERFACE_NAMSIZ), VRF_DEFAULT);
}
void eigrp_zebra_route_add(struct prefix_ipv4 *p, struct list *successors)
void eigrp_zebra_route_add(struct prefix *p, struct list *successors)
{
struct zapi_route api;
struct zapi_nexthop *api_nh;
struct eigrp_neighbor_entry *te;
struct listnode *node;
u_char message;
u_char flags;
int psize;
struct stream *s;
int count = 0;
if (zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP]) {
message = 0;
flags = 0;
if (!zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP])
return;
/* EIGRP pass nexthop and metric */
SET_FLAG(message, ZAPI_MESSAGE_NEXTHOP);
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_EIGRP;
api.safi = SAFI_UNICAST;
memcpy(&api.prefix, p, sizeof(*p));
/* Make packet. */
s = zclient->obuf;
stream_reset(s);
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = successors->count;
/* Put command, type, flags, message. */
zclient_create_header(s, ZEBRA_IPV4_ROUTE_ADD, VRF_DEFAULT);
stream_putc(s, ZEBRA_ROUTE_EIGRP);
stream_putw(s, 0);
stream_putl(s, flags);
stream_putc(s, message);
stream_putw(s, SAFI_UNICAST);
/* Nexthop, ifindex, distance and metric information. */
for (ALL_LIST_ELEMENTS_RO(successors, node, te)) {
api_nh = &api.nexthops[count];
if (te->adv_router->src.s_addr) {
api_nh->gate.ipv4 = te->adv_router->src;
api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
} else
api_nh->type = NEXTHOP_TYPE_IFINDEX;
api_nh->ifindex = te->ei->ifp->ifindex;
/* Put prefix information. */
psize = PSIZE(p->prefixlen);
stream_putc(s, p->prefixlen);
stream_write(s, (u_char *)&p->prefix, psize);
/* Nexthop count. */
stream_putc(s, successors->count);
/* Nexthop, ifindex, distance and metric information. */
for (ALL_LIST_ELEMENTS_RO(successors, node, te)) {
if (te->adv_router->src.s_addr) {
stream_putc(s, NEXTHOP_TYPE_IPV4_IFINDEX);
stream_put_in_addr(s, &te->adv_router->src);
} else
stream_putc(s, NEXTHOP_TYPE_IFINDEX);
stream_putl(s, te->ei->ifp->ifindex);
}
if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) {
char buf[2][INET_ADDRSTRLEN];
zlog_debug("Zebra: Route add %s/%d nexthop %s",
inet_ntop(AF_INET, &p->prefix, buf[0],
sizeof(buf[0])),
p->prefixlen,
inet_ntop(AF_INET, 0 /*&p->nexthop*/, buf[1],
sizeof(buf[1])));
}
stream_putw_at(s, 0, stream_get_endp(s));
zclient_send_message(zclient);
count++;
}
if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) {
char buf[2][PREFIX_STRLEN];
zlog_debug("Zebra: Route add %s nexthop %s",
prefix2str(p, buf[0], PREFIX_STRLEN),
inet_ntop(AF_INET, 0, buf[1], PREFIX_STRLEN));
}
zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
}
void eigrp_zebra_route_delete(struct prefix_ipv4 *p)
void eigrp_zebra_route_delete(struct prefix *p)
{
struct zapi_ipv4 api;
struct zapi_route api;
if (zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP]) {
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_EIGRP;
api.instance = 0;
api.flags = 0;
api.message = 0;
api.safi = SAFI_UNICAST;
zapi_ipv4_route(ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api);
if (!zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP])
return;
if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) {
char buf[2][INET_ADDRSTRLEN];
zlog_debug("Zebra: Route del %s/%d nexthop %s",
inet_ntop(AF_INET, &p->prefix, buf[0],
sizeof(buf[0])),
p->prefixlen,
inet_ntop(AF_INET, 0 /*&p->nexthop*/, buf[1],
sizeof(buf[1])));
}
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_EIGRP;
api.safi = SAFI_UNICAST;
memcpy(&api.prefix, p, sizeof(*p));
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) {
char buf[PREFIX_STRLEN];
zlog_debug("Zebra: Route del %s",
prefix2str(p, buf, PREFIX_STRLEN));
}
return;

View File

@ -33,8 +33,8 @@
extern void eigrp_zebra_init(void);
extern void eigrp_zebra_route_add(struct prefix_ipv4 *, struct list *);
extern void eigrp_zebra_route_delete(struct prefix_ipv4 *);
extern void eigrp_zebra_route_add(struct prefix *, struct list *);
extern void eigrp_zebra_route_delete(struct prefix *);
extern int eigrp_redistribute_set(struct eigrp *, int, struct eigrp_metrics);
extern int eigrp_redistribute_unset(struct eigrp *, int);
extern int eigrp_is_type_redistributed(int);

View File

@ -11,14 +11,28 @@ def run(cmd):
proc.wait()
return rv
clangfmt = run(['git', 'show', 'master:.clang-format'])
argp = argparse.ArgumentParser(description = 'git whitespace-fixing tool')
argp.add_argument('branch', metavar='BRANCH', type = str, nargs = '?', default = 'HEAD')
args = argp.parse_args()
branch = args.branch
commit = run(['git', 'rev-list', '-n', '1', branch, '--']).strip()
beforeid = run(['git', 'rev-list', '-n', '1', 'reindent-master-before', '--']).strip()
afterid = run(['git', 'rev-list', '-n', '1', 'reindent-master-after', '--']).strip()
# frr-3.1-dev = first commit that is on master but not on stable/3.0
masterid = run(['git', 'rev-list', '-n', '1', 'frr-3.1-dev', '--']).strip()
masterbase = run(['git', 'merge-base', commit, masterid]).strip()
if masterbase == masterid:
refbranch = 'master'
else:
refbranch = '3.0'
sys.stderr.write('autodetected base: %s (can be 3.0 or master)\n' % refbranch)
beforeid = run(['git', 'rev-list', '-n', '1', 'reindent-%s-before' % refbranch, '--']).strip()
afterid = run(['git', 'rev-list', '-n', '1', 'reindent-%s-after' % refbranch, '--']).strip()
beforebase = run(['git', 'merge-base', commit, beforeid]).strip()
afterbase = run(['git', 'merge-base', commit, afterid]).strip()
@ -28,10 +42,10 @@ if afterbase == afterid:
sys.exit(1)
if beforebase != beforeid:
sys.stderr.write('you need to rebase your branch onto the tag "reindent-master-before"\n')
sys.stderr.write('you need to rebase your branch onto the tag "reindent-%s-before"\n' % refbranch)
sys.exit(1)
revs = run(['git', 'rev-list', 'reindent-master-before..%s' % commit]).strip().split('\n')
revs = run(['git', 'rev-list', 'reindent-%s-before..%s' % (refbranch, commit)]).strip().split('\n')
revs.reverse()
srcdir = os.getcwd()
@ -39,9 +53,12 @@ tmpdir = tempfile.mkdtemp('frrindent')
os.chdir(tmpdir)
sys.stderr.write('using temporary directory %s; %d revisions\n' % (tmpdir, len(revs)))
run(['git', 'clone', '-s', '-b', 'reindent-master-after', srcdir, 'repo'])
run(['git', 'clone', '-s', '-b', 'reindent-%s-after' % refbranch, srcdir, 'repo'])
os.chdir('repo')
with open('.clang-format', 'w') as fd:
fd.write(clangfmt)
prev = beforeid
for rev in revs:
filestat = run(['git', 'diff', '-z', '--name-status', prev, rev]).rstrip('\0').split('\0')

View File

@ -48,14 +48,15 @@
extern struct zebra_privs_t isisd_privs;
struct bpf_insn llcfilter[] = {
BPF_STMT(BPF_LD + BPF_B + BPF_ABS,
ETHER_HDR_LEN), /* check first byte */
/* check first byte */
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETH_ALEN),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 5),
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 1),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0,
3), /* check second byte */
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 2),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1), /* check third byte */
/* check second byte */
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETH_ALEN + 1),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 3),
/* check third byte */
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETH_ALEN + 2),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1),
BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
BPF_STMT(BPF_RET + BPF_K, 0)};
u_int readblen = 0;
@ -243,15 +244,14 @@ int isis_recv_pdu_bcast(struct isis_circuit *circuit, u_char *ssnpa)
assert(bpf_hdr->bh_caplen == bpf_hdr->bh_datalen);
offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN;
offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETH_ALEN;
/* then we lose the BPF, LLC and ethernet headers */
stream_write(circuit->rcv_stream, readbuff + offset,
bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN);
bpf_hdr->bh_caplen - LLC_LEN - ETH_ALEN);
stream_set_getp(circuit->rcv_stream, 0);
memcpy(ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETH_ALEN,
ETH_ALEN);
memcpy(ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETH_ALEN, ETH_ALEN);
if (ioctl(circuit->fd, BIOCFLUSH, &one) < 0)
zlog_warn("Flushing failed: %s", safe_strerror(errno));
@ -265,7 +265,7 @@ int isis_send_pdu_bcast(struct isis_circuit *circuit, int level)
ssize_t written;
size_t buflen;
buflen = stream_get_endp(circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN;
buflen = stream_get_endp(circuit->snd_stream) + LLC_LEN + ETH_ALEN;
if (buflen > sizeof(sock_buff)) {
zlog_warn(
"isis_send_pdu_bcast: sock_buff size %zu is less than "
@ -291,12 +291,12 @@ int isis_send_pdu_bcast(struct isis_circuit *circuit, int level)
/*
* Then the LLC
*/
sock_buff[ETHER_HDR_LEN] = ISO_SAP;
sock_buff[ETHER_HDR_LEN + 1] = ISO_SAP;
sock_buff[ETHER_HDR_LEN + 2] = 0x03;
sock_buff[ETH_ALEN] = ISO_SAP;
sock_buff[ETH_ALEN + 1] = ISO_SAP;
sock_buff[ETH_ALEN + 2] = 0x03;
/* then we copy the data */
memcpy(sock_buff + (LLC_LEN + ETHER_HDR_LEN), circuit->snd_stream->data,
memcpy(sock_buff + (LLC_LEN + ETH_ALEN), circuit->snd_stream->data,
stream_get_endp(circuit->snd_stream));
/* now we can send this */

View File

@ -1336,8 +1336,8 @@ int isis_if_delete_hook(struct interface *ifp)
void isis_circuit_init()
{
/* Initialize Zebra interface data structure */
if_add_hook(IF_NEW_HOOK, isis_if_new_hook);
if_add_hook(IF_DELETE_HOOK, isis_if_delete_hook);
hook_register_prio(if_add, 0, isis_if_new_hook);
hook_register_prio(if_del, 0, isis_if_delete_hook);
/* Install interface node */
install_node(&interface_node, isis_interface_config_write);

View File

@ -181,7 +181,7 @@ DEFUN (no_isis_passive,
if (if_is_loopback(circuit->interface)) {
vty_out(vty, "Can't set no passive for loopback interface\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
isis_circuit_passive_set(circuit, 0);
@ -206,7 +206,7 @@ DEFUN (isis_circuit_type,
is_type = string2circuit_t(argv[idx_level]->arg);
if (!is_type) {
vty_out(vty, "Unknown circuit-type \n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
if (circuit->state == C_STATE_UP
@ -214,7 +214,7 @@ DEFUN (isis_circuit_type,
&& circuit->area->is_type != is_type) {
vty_out(vty, "Invalid circuit level for area %s.\n",
circuit->area->area_tag);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
isis_circuit_is_type_set(circuit, is_type);
@ -262,7 +262,7 @@ DEFUN (isis_network,
if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_P2P)) {
vty_out(vty,
"isis network point-to-point is valid only on broadcast interfaces\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
@ -283,7 +283,7 @@ DEFUN (no_isis_network,
if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_BROADCAST)) {
vty_out(vty,
"isis network point-to-point is valid only on broadcast interfaces\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
@ -313,7 +313,7 @@ DEFUN (isis_passwd,
argv[idx_word]->arg);
if (rv) {
vty_out(vty, "Too long circuit password (>254)\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
@ -355,7 +355,7 @@ DEFUN (isis_priority,
prio = atoi(argv[idx_number]->arg);
if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) {
vty_out(vty, "Invalid priority %d - should be <0-127>\n", prio);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->priority[0] = prio;
@ -400,7 +400,7 @@ DEFUN (isis_priority_l1,
prio = atoi(argv[idx_number]->arg);
if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) {
vty_out(vty, "Invalid priority %d - should be <0-127>\n", prio);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->priority[0] = prio;
@ -444,7 +444,7 @@ DEFUN (isis_priority_l2,
prio = atoi(argv[idx_number]->arg);
if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) {
vty_out(vty, "Invalid priority %d - should be <0-127>\n", prio);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->priority[1] = prio;
@ -494,7 +494,7 @@ DEFUN (isis_metric,
"Invalid metric %d - should be <0-63> "
"when narrow metric type enabled\n",
met);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
/* RFC4444 */
@ -504,7 +504,7 @@ DEFUN (isis_metric,
"Invalid metric %d - should be <0-16777215> "
"when wide metric type enabled\n",
met);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
isis_circuit_metric_set(circuit, IS_LEVEL_1, met);
@ -554,7 +554,7 @@ DEFUN (isis_metric_l1,
"Invalid metric %d - should be <0-63> "
"when narrow metric type enabled\n",
met);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
/* RFC4444 */
@ -564,7 +564,7 @@ DEFUN (isis_metric_l1,
"Invalid metric %d - should be <0-16777215> "
"when wide metric type enabled\n",
met);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
isis_circuit_metric_set(circuit, IS_LEVEL_1, met);
@ -613,7 +613,7 @@ DEFUN (isis_metric_l2,
"Invalid metric %d - should be <0-63> "
"when narrow metric type enabled\n",
met);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
/* RFC4444 */
@ -623,7 +623,7 @@ DEFUN (isis_metric_l2,
"Invalid metric %d - should be <0-16777215> "
"when wide metric type enabled\n",
met);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
isis_circuit_metric_set(circuit, IS_LEVEL_2, met);
@ -667,7 +667,7 @@ DEFUN (isis_hello_interval,
if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) {
vty_out(vty, "Invalid hello-interval %d - should be <1-600>\n",
interval);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->hello_interval[0] = (u_int16_t)interval;
@ -714,7 +714,7 @@ DEFUN (isis_hello_interval_l1,
if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) {
vty_out(vty, "Invalid hello-interval %ld - should be <1-600>\n",
interval);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->hello_interval[0] = (u_int16_t)interval;
@ -760,7 +760,7 @@ DEFUN (isis_hello_interval_l2,
if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) {
vty_out(vty, "Invalid hello-interval %ld - should be <1-600>\n",
interval);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->hello_interval[1] = (u_int16_t)interval;
@ -806,7 +806,7 @@ DEFUN (isis_hello_multiplier,
vty_out(vty,
"Invalid hello-multiplier %d - should be <2-100>\n",
mult);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->hello_multiplier[0] = (u_int16_t)mult;
@ -854,7 +854,7 @@ DEFUN (isis_hello_multiplier_l1,
vty_out(vty,
"Invalid hello-multiplier %d - should be <2-100>\n",
mult);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->hello_multiplier[0] = (u_int16_t)mult;
@ -901,7 +901,7 @@ DEFUN (isis_hello_multiplier_l2,
vty_out(vty,
"Invalid hello-multiplier %d - should be <2-100>\n",
mult);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->hello_multiplier[1] = (u_int16_t)mult;
@ -979,7 +979,7 @@ DEFUN (csnp_interval,
if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) {
vty_out(vty, "Invalid csnp-interval %lu - should be <1-600>\n",
interval);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->csnp_interval[0] = (u_int16_t)interval;
@ -1026,7 +1026,7 @@ DEFUN (csnp_interval_l1,
if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) {
vty_out(vty, "Invalid csnp-interval %lu - should be <1-600>\n",
interval);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->csnp_interval[0] = (u_int16_t)interval;
@ -1072,7 +1072,7 @@ DEFUN (csnp_interval_l2,
if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) {
vty_out(vty, "Invalid csnp-interval %lu - should be <1-600>\n",
interval);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->csnp_interval[1] = (u_int16_t)interval;
@ -1117,7 +1117,7 @@ DEFUN (psnp_interval,
if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) {
vty_out(vty, "Invalid psnp-interval %lu - should be <1-120>\n",
interval);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->psnp_interval[0] = (u_int16_t)interval;
@ -1164,7 +1164,7 @@ DEFUN (psnp_interval_l1,
if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) {
vty_out(vty, "Invalid psnp-interval %lu - should be <1-120>\n",
interval);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->psnp_interval[0] = (u_int16_t)interval;
@ -1210,7 +1210,7 @@ DEFUN (psnp_interval_l2,
if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) {
vty_out(vty, "Invalid psnp-interval %lu - should be <1-120>\n",
interval);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
circuit->psnp_interval[1] = (u_int16_t)interval;
@ -1253,12 +1253,12 @@ DEFUN (circuit_topology,
if (circuit->area && circuit->area->oldmetric) {
vty_out(vty,
"Multi topology IS-IS can only be used with wide metrics\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
if (mtid == (uint16_t)-1) {
vty_out(vty, "Don't know topology '%s'\n", arg);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
return isis_circuit_mt_enabled_set(circuit, mtid, true);
@ -1281,12 +1281,12 @@ DEFUN (no_circuit_topology,
if (circuit->area && circuit->area->oldmetric) {
vty_out(vty,
"Multi topology IS-IS can only be used with wide metrics\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
if (mtid == (uint16_t)-1) {
vty_out(vty, "Don't know topology '%s'\n", arg);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
return isis_circuit_mt_enabled_set(circuit, mtid, false);
@ -1298,11 +1298,11 @@ static int validate_metric_style_narrow(struct vty *vty, struct isis_area *area)
struct listnode *node;
if (!vty)
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
if (!area) {
vty_out(vty, "ISIS area is invalid\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
@ -1311,14 +1311,14 @@ static int validate_metric_style_narrow(struct vty *vty, struct isis_area *area)
&& (circuit->te_metric[0] > MAX_NARROW_LINK_METRIC)) {
vty_out(vty, "ISIS circuit %s metric is invalid\n",
circuit->interface->name);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
if ((area->is_type & IS_LEVEL_2)
&& (circuit->is_type & IS_LEVEL_2)
&& (circuit->te_metric[1] > MAX_NARROW_LINK_METRIC)) {
vty_out(vty, "ISIS circuit %s metric is invalid\n",
circuit->interface->name);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
}
@ -1345,7 +1345,7 @@ DEFUN (metric_style,
if (area_is_mt(area)) {
vty_out(vty,
"Narrow metrics cannot be used while multi topology IS-IS is active\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
ret = validate_metric_style_narrow(vty, area);
@ -1373,7 +1373,7 @@ DEFUN (no_metric_style,
if (area_is_mt(area)) {
vty_out(vty,
"Narrow metrics cannot be used while multi topology IS-IS is active\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
ret = validate_metric_style_narrow(vty, area);
@ -1470,7 +1470,7 @@ static int area_lsp_mtu_set(struct vty *vty, unsigned int lsp_mtu)
"ISIS area contains circuit %s, which has a maximum PDU size of %zu.\n",
circuit->interface->name,
isis_circuit_pdu_size(circuit));
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
}
@ -1568,7 +1568,7 @@ static int set_lsp_gen_interval(struct vty *vty, struct isis_area *area,
"LSP gen interval %us must be less than "
"the LSP refresh interval %us\n",
interval, area->lsp_refresh[lvl - 1]);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
}
@ -1817,7 +1817,7 @@ static int area_max_lsp_lifetime_set(struct vty *vty, int level,
"the configured LSP gen interval %us\n",
refresh_interval,
area->lsp_gen_interval[lvl - 1]);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
}
}
@ -1890,14 +1890,14 @@ static int area_lsp_refresh_interval_set(struct vty *vty, int level,
"LSP refresh interval %us must be greater than "
"the configured LSP gen interval %us\n",
interval, area->lsp_gen_interval[lvl - 1]);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
if (interval > (area->max_lsp_lifetime[lvl - 1] - 300)) {
vty_out(vty,
"LSP refresh interval %us must be less than "
"the configured LSP lifetime %us less 300\n",
interval, area->max_lsp_lifetime[lvl - 1]);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
}
@ -1961,7 +1961,7 @@ static int area_passwd_set(struct vty *vty, int level,
if (passwd && strlen(passwd) > 254) {
vty_out(vty, "Too long area password (>254)\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
type_set(area, level, passwd, snp_auth);

View File

@ -245,260 +245,91 @@ static int isis_zebra_link_params(int command, struct zclient *zclient,
return 0;
}
static void isis_zebra_route_add_ipv4(struct prefix *prefix,
struct isis_route_info *route_info)
static void isis_zebra_route_add_route(struct prefix *prefix,
struct isis_route_info *route_info)
{
u_char message;
u_int32_t flags;
int psize;
struct stream *stream;
struct zapi_route api;
struct zapi_nexthop *api_nh;
struct isis_nexthop *nexthop;
struct listnode *node;
if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
return;
if (vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_ISIS],
VRF_DEFAULT)) {
message = 0;
flags = 0;
SET_FLAG(message, ZAPI_MESSAGE_NEXTHOP);
SET_FLAG(message, ZAPI_MESSAGE_METRIC);
#if 0
SET_FLAG (message, ZAPI_MESSAGE_DISTANCE);
#endif
stream = zclient->obuf;
stream_reset(stream);
zclient_create_header(stream, ZEBRA_IPV4_ROUTE_ADD,
VRF_DEFAULT);
/* type */
stream_putc(stream, ZEBRA_ROUTE_ISIS);
/* instance */
stream_putw(stream, 0);
/* flags */
stream_putl(stream, flags);
/* message */
stream_putc(stream, message);
/* SAFI */
stream_putw(stream, SAFI_UNICAST);
/* prefix information */
psize = PSIZE(prefix->prefixlen);
stream_putc(stream, prefix->prefixlen);
stream_write(stream, (u_char *)&prefix->u.prefix4, psize);
stream_putc(stream, listcount(route_info->nexthops));
/* Nexthop, ifindex, distance and metric information */
for (ALL_LIST_ELEMENTS_RO(route_info->nexthops, node,
nexthop)) {
/* FIXME: can it be ? */
if (nexthop->ip.s_addr != INADDR_ANY) {
stream_putc(stream, NEXTHOP_TYPE_IPV4_IFINDEX);
stream_put_in_addr(stream, &nexthop->ip);
stream_putl(stream, nexthop->ifindex);
} else {
stream_putc(stream, NEXTHOP_TYPE_IFINDEX);
stream_putl(stream, nexthop->ifindex);
}
}
#if 0
if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE))
stream_putc (stream, route_info->depth);
#endif
if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC))
stream_putl(stream, route_info->cost);
stream_putw_at(stream, 0, stream_get_endp(stream));
zclient_send_message(zclient);
SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
}
}
static void isis_zebra_route_del_ipv4(struct prefix *prefix,
struct isis_route_info *route_info)
{
struct zapi_ipv4 api;
struct prefix_ipv4 prefix4;
if (vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_ISIS],
VRF_DEFAULT)) {
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_ISIS;
api.instance = 0;
api.flags = 0;
api.message = 0;
api.safi = SAFI_UNICAST;
prefix4.family = AF_INET;
prefix4.prefixlen = prefix->prefixlen;
prefix4.prefix = prefix->u.prefix4;
zapi_ipv4_route(ZEBRA_IPV4_ROUTE_DELETE, zclient, &prefix4,
&api);
}
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
return;
}
static void isis_zebra_route_add_ipv6(struct prefix *prefix,
struct isis_route_info *route_info)
{
struct zapi_ipv6 api;
struct in6_addr **nexthop_list;
ifindex_t *ifindex_list;
struct isis_nexthop6 *nexthop6;
int i, size;
struct listnode *node;
struct prefix_ipv6 prefix6;
int count = 0;
if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
return;
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_ISIS;
api.instance = 0;
api.flags = 0;
api.message = 0;
api.safi = SAFI_UNICAST;
api.prefix = *prefix;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX);
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = route_info->cost;
#if 0
SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
api.distance = route_info->depth;
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
api.distance = route_info->depth;
#endif
api.nexthop_num = listcount(route_info->nexthops6);
api.ifindex_num = listcount(route_info->nexthops6);
/* allocate memory for nexthop_list */
size = sizeof(struct isis_nexthop6 *)
* listcount(route_info->nexthops6);
nexthop_list = (struct in6_addr **)XMALLOC(MTYPE_ISIS_TMP, size);
if (!nexthop_list) {
zlog_err("isis_zebra_add_route_ipv6: out of memory!");
return;
}
/* allocate memory for ifindex_list */
size = sizeof(unsigned int) * listcount(route_info->nexthops6);
ifindex_list = (ifindex_t *)XMALLOC(MTYPE_ISIS_TMP, size);
if (!ifindex_list) {
zlog_err("isis_zebra_add_route_ipv6: out of memory!");
XFREE(MTYPE_ISIS_TMP, nexthop_list);
return;
}
/* for each nexthop */
i = 0;
for (ALL_LIST_ELEMENTS_RO(route_info->nexthops6, node, nexthop6)) {
if (!IN6_IS_ADDR_LINKLOCAL(&nexthop6->ip6)
&& !IN6_IS_ADDR_UNSPECIFIED(&nexthop6->ip6)) {
api.nexthop_num--;
api.ifindex_num--;
continue;
/* Nexthops */
switch (prefix->family) {
case AF_INET:
for (ALL_LIST_ELEMENTS_RO(route_info->nexthops, node,
nexthop)) {
api_nh = &api.nexthops[count];
/* FIXME: can it be ? */
if (nexthop->ip.s_addr != INADDR_ANY) {
api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
api_nh->gate.ipv4 = nexthop->ip;
} else {
api_nh->type = NEXTHOP_TYPE_IFINDEX;
}
api_nh->ifindex = nexthop->ifindex;
count++;
}
break;
case AF_INET6:
for (ALL_LIST_ELEMENTS_RO(route_info->nexthops6, node,
nexthop6)) {
if (!IN6_IS_ADDR_LINKLOCAL(&nexthop6->ip6)
&& !IN6_IS_ADDR_UNSPECIFIED(&nexthop6->ip6)) {
continue;
}
nexthop_list[i] = &nexthop6->ip6;
ifindex_list[i] = nexthop6->ifindex;
i++;
api_nh = &api.nexthops[count];
api_nh->gate.ipv6 = nexthop6->ip6;
api_nh->ifindex = nexthop6->ifindex;
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
count++;
}
break;
}
if (!count)
return;
api.nexthop = nexthop_list;
api.ifindex = ifindex_list;
api.nexthop_num = count;
if (api.nexthop_num && api.ifindex_num) {
prefix6.family = AF_INET6;
prefix6.prefixlen = prefix->prefixlen;
memcpy(&prefix6.prefix, &prefix->u.prefix6,
sizeof(struct in6_addr));
zapi_ipv6_route(ZEBRA_IPV6_ROUTE_ADD, zclient, &prefix6, NULL,
&api);
SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
}
XFREE(MTYPE_ISIS_TMP, nexthop_list);
XFREE(MTYPE_ISIS_TMP, ifindex_list);
return;
zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC);
}
static void isis_zebra_route_del_ipv6(struct prefix *prefix,
struct isis_route_info *route_info)
static void isis_zebra_route_del_route(struct prefix *prefix,
struct isis_route_info *route_info)
{
struct zapi_ipv6 api;
struct in6_addr **nexthop_list;
ifindex_t *ifindex_list;
struct isis_nexthop6 *nexthop6;
int i, size;
struct listnode *node;
struct prefix_ipv6 prefix6;
struct zapi_route api;
if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
return;
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_ISIS;
api.instance = 0;
api.flags = 0;
api.message = 0;
api.safi = SAFI_UNICAST;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX);
api.nexthop_num = listcount(route_info->nexthops6);
api.ifindex_num = listcount(route_info->nexthops6);
api.prefix = *prefix;
/* allocate memory for nexthop_list */
size = sizeof(struct isis_nexthop6 *)
* listcount(route_info->nexthops6);
nexthop_list = (struct in6_addr **)XMALLOC(MTYPE_ISIS_TMP, size);
if (!nexthop_list) {
zlog_err("isis_zebra_route_del_ipv6: out of memory!");
return;
}
/* allocate memory for ifindex_list */
size = sizeof(unsigned int) * listcount(route_info->nexthops6);
ifindex_list = (ifindex_t *)XMALLOC(MTYPE_ISIS_TMP, size);
if (!ifindex_list) {
zlog_err("isis_zebra_route_del_ipv6: out of memory!");
XFREE(MTYPE_ISIS_TMP, nexthop_list);
return;
}
/* for each nexthop */
i = 0;
for (ALL_LIST_ELEMENTS_RO(route_info->nexthops6, node, nexthop6)) {
if (!IN6_IS_ADDR_LINKLOCAL(&nexthop6->ip6)
&& !IN6_IS_ADDR_UNSPECIFIED(&nexthop6->ip6)) {
api.nexthop_num--;
api.ifindex_num--;
continue;
}
nexthop_list[i] = &nexthop6->ip6;
ifindex_list[i] = nexthop6->ifindex;
i++;
}
api.nexthop = nexthop_list;
api.ifindex = ifindex_list;
if (api.nexthop_num && api.ifindex_num) {
prefix6.family = AF_INET6;
prefix6.prefixlen = prefix->prefixlen;
memcpy(&prefix6.prefix, &prefix->u.prefix6,
sizeof(struct in6_addr));
zapi_ipv6_route(ZEBRA_IPV6_ROUTE_DELETE, zclient, &prefix6,
NULL, &api);
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
}
XFREE(MTYPE_ISIS_TMP, nexthop_list);
XFREE(MTYPE_ISIS_TMP, ifindex_list);
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
}
void isis_zebra_route_update(struct prefix *prefix,
@ -507,144 +338,38 @@ void isis_zebra_route_update(struct prefix *prefix,
if (zclient->sock < 0)
return;
if ((prefix->family == AF_INET
&& !vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_ISIS],
VRF_DEFAULT))
|| (prefix->family == AF_INET6
&& !vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_ISIS],
VRF_DEFAULT)))
return;
if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
if (prefix->family == AF_INET)
isis_zebra_route_add_ipv4(prefix, route_info);
else if (prefix->family == AF_INET6)
isis_zebra_route_add_ipv6(prefix, route_info);
} else {
if (prefix->family == AF_INET)
isis_zebra_route_del_ipv4(prefix, route_info);
else if (prefix->family == AF_INET6)
isis_zebra_route_del_ipv6(prefix, route_info);
}
return;
}
static int isis_zebra_read_ipv4(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct stream *stream;
struct zapi_ipv4 api;
struct prefix_ipv4 p;
struct prefix *p_generic = (struct prefix *)&p;
stream = zclient->ibuf;
memset(&api, 0, sizeof(api));
memset(&p, 0, sizeof(struct prefix_ipv4));
api.type = stream_getc(stream);
api.instance = stream_getw(stream);
api.flags = stream_getl(stream);
api.message = stream_getc(stream);
p.family = AF_INET;
p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc(stream));
stream_get(&p.prefix, stream, PSIZE(p.prefixlen));
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
api.nexthop_num = stream_getc(stream);
(void)stream_get_ipv4(stream);
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
api.ifindex_num = stream_getc(stream);
stream_getl(stream);
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc(stream);
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl(stream);
/*
* Avoid advertising a false default reachability. (A default
* route installed by IS-IS gets redistributed from zebra back
* into IS-IS causing us to start advertising default reachabity
* without this check)
*/
if (p.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS)
command = ZEBRA_IPV4_ROUTE_DELETE;
if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
isis_redist_add(api.type, p_generic, api.distance, api.metric);
if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE))
isis_zebra_route_add_route(prefix, route_info);
else
isis_redist_delete(api.type, p_generic);
return 0;
isis_zebra_route_del_route(prefix, route_info);
}
static int isis_zebra_read_ipv6(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
static int isis_zebra_read(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct stream *stream;
struct zapi_ipv6 api;
struct prefix_ipv6 p;
struct prefix src_p;
struct prefix *p_generic = (struct prefix *)&p;
struct in6_addr nexthop;
unsigned long ifindex __attribute__((unused));
struct zapi_route api;
stream = zclient->ibuf;
memset(&api, 0, sizeof(api));
memset(&p, 0, sizeof(struct prefix_ipv6));
memset(&nexthop, 0, sizeof(nexthop));
ifindex = 0;
if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1;
api.type = stream_getc(stream);
api.instance = stream_getw(stream);
api.flags = stream_getl(stream);
api.message = stream_getc(stream);
p.family = AF_INET6;
p.prefixlen = stream_getc(stream);
stream_get(&p.prefix, stream, PSIZE(p.prefixlen));
memset(&src_p, 0, sizeof(struct prefix));
src_p.family = AF_INET6;
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) {
src_p.prefixlen = stream_getc(stream);
stream_get(&src_p.u.prefix6, stream, PSIZE(src_p.prefixlen));
}
if (src_p.prefixlen)
/* we completely ignore srcdest routes for now. */
/* we completely ignore srcdest routes for now. */
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
return 0;
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
api.nexthop_num = stream_getc(stream); /* this is always 1 */
stream_get(&nexthop, stream, sizeof(nexthop));
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
api.ifindex_num = stream_getc(stream);
ifindex = stream_getl(stream);
}
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc(stream);
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl(stream);
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG))
api.tag = stream_getl(stream);
/*
* Avoid advertising a false default reachability. (A default
* route installed by IS-IS gets redistributed from zebra back
* into IS-IS causing us to start advertising default reachabity
* without this check)
*/
if (p.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS)
command = ZEBRA_IPV6_ROUTE_DELETE;
if (api.prefix.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS)
command = ZEBRA_REDISTRIBUTE_ROUTE_DEL;
if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
isis_redist_add(api.type, p_generic, api.distance, api.metric);
if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
isis_redist_add(api.type, &api.prefix, api.distance,
api.metric);
else
isis_redist_delete(api.type, p_generic);
isis_redist_delete(api.type, &api.prefix);
return 0;
}
@ -692,10 +417,8 @@ void isis_zebra_init(struct thread_master *master)
zclient->interface_address_add = isis_zebra_if_address_add;
zclient->interface_address_delete = isis_zebra_if_address_del;
zclient->interface_link_params = isis_zebra_link_params;
zclient->redistribute_route_ipv4_add = isis_zebra_read_ipv4;
zclient->redistribute_route_ipv4_del = isis_zebra_read_ipv4;
zclient->redistribute_route_ipv6_add = isis_zebra_read_ipv6;
zclient->redistribute_route_ipv6_del = isis_zebra_read_ipv6;
zclient->redistribute_route_add = isis_zebra_read;
zclient->redistribute_route_del = isis_zebra_read;
return;
}

View File

@ -347,14 +347,14 @@ int area_net_title(struct vty *vty, const char *net_title)
"area address must be at least 8..20 octets long (%d)\n",
addr->addr_len);
XFREE(MTYPE_ISIS_AREA_ADDR, addr);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
if (addr->area_addr[addr->addr_len - 1] != 0) {
vty_out(vty,
"nsel byte (last byte) in area address must be 0\n");
XFREE(MTYPE_ISIS_AREA_ADDR, addr);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
if (isis->sysid_set == 0) {
@ -374,7 +374,7 @@ int area_net_title(struct vty *vty, const char *net_title)
vty_out(vty,
"System ID must not change when defining additional area addresses\n");
XFREE(MTYPE_ISIS_AREA_ADDR, addr);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
/* now we see that we don't already have this address */
@ -419,7 +419,7 @@ int area_clear_net_title(struct vty *vty, const char *net_title)
vty_out(vty,
"Unsupported area address length %d, should be 8...20 \n",
addr.addr_len);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
memcpy(addr.area_addr, buff, (int)addr.addr_len);
@ -758,17 +758,18 @@ void print_debug(struct vty *vty, int flags, int onoff)
vty_out(vty, "IS-IS LSP scheduling debugging is %s\n", onoffs);
}
DEFUN (show_debugging,
show_debugging_isis_cmd,
"show debugging isis",
SHOW_STR
"State of each debugging option\n"
ISIS_STR)
DEFUN_NOSH (show_debugging,
show_debugging_isis_cmd,
"show debugging [isis]",
SHOW_STR
"State of each debugging option\n"
ISIS_STR)
{
if (isis->debugs) {
vty_out(vty, "IS-IS:\n");
vty_out (vty, "IS-IS debugging status:\n");
if (isis->debugs)
print_debug(vty, isis->debugs, 1);
}
return CMD_SUCCESS;
}
@ -1259,8 +1260,8 @@ DEFUN (show_isis_spf_ietf,
if (area->spf_timer[level - 1]) {
struct timeval remain = thread_timer_remain(
area->spf_timer[level - 1]);
vty_out(vty, "Pending, due in %ld msec\n",
remain.tv_sec * 1000
vty_out(vty, "Pending, due in %lld msec\n",
(long long)remain.tv_sec * 1000
+ remain.tv_usec / 1000);
} else {
vty_out(vty, "Not scheduled\n");
@ -1404,7 +1405,7 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level)
(u_char)strtol((char *)number, NULL, 16);
pos -= 4;
if (strncmp(pos, ".", 1) != 0)
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING;
}
if (strncmp(pos, ".", 1) == 0) {
memcpy(number, ++pos, 2);
@ -1569,16 +1570,16 @@ DEFUN (isis_topology,
if (area->oldmetric) {
vty_out(vty,
"Multi topology IS-IS can only be used with wide metrics\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
if (mtid == (uint16_t)-1) {
vty_out(vty, "Don't know topology '%s'\n", arg);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
if (mtid == ISIS_MT_IPV4_UNICAST) {
vty_out(vty, "Cannot configure IPv4 unicast topology\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
area_set_mt_enabled(area, mtid, true);
@ -1602,16 +1603,16 @@ DEFUN (no_isis_topology,
if (area->oldmetric) {
vty_out(vty,
"Multi topology IS-IS can only be used with wide metrics\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
if (mtid == (uint16_t)-1) {
vty_out(vty, "Don't know topology '%s'\n", arg);
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
if (mtid == ISIS_MT_IPV4_UNICAST) {
vty_out(vty, "Cannot configure IPv4 unicast topology\n");
return CMD_ERR_AMBIGUOUS;
return CMD_WARNING_CONFIG_FAILED;
}
area_set_mt_enabled(area, mtid, false);

View File

@ -25,8 +25,6 @@
#include "vty.h"
#define ISISD_VERSION "0.0.7"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
#include "isisd/isis_redist.h"

View File

@ -19,7 +19,7 @@
#ifndef _CONTROL_H_
#define _CONTROL_H_
#include "openbsd-queue.h"
#include "queue.h"
struct ctl_conn {
TAILQ_ENTRY(ctl_conn) entry;

View File

@ -21,7 +21,7 @@
#ifndef _LDE_H_
#define _LDE_H_
#include "openbsd-queue.h"
#include "queue.h"
#include "openbsd-tree.h"
#include "if.h"

View File

@ -684,13 +684,13 @@ DEFPY (ldp_show_l2vpn_atom_vc,
return (ldp_vty_show_atom_vc(vty, json));
}
DEFPY (ldp_show_debugging_mpls_ldp,
ldp_show_debugging_mpls_ldp_cmd,
"show debugging mpls ldp",
"Show running system information\n"
"Debugging functions\n"
"MPLS information\n"
"Label Distribution Protocol\n")
DEFUN_NOSH (ldp_show_debugging_mpls_ldp,
ldp_show_debugging_mpls_ldp_cmd,
"show debugging [mpls ldp]",
"Show running system information\n"
"Debugging functions\n"
"MPLS information\n"
"Label Distribution Protocol\n")
{
return (ldp_vty_show_debugging(vty));
}

View File

@ -396,19 +396,34 @@ static int
ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
vrf_id_t vrf_id)
{
struct stream *s;
u_char type;
u_char message_flags;
struct zapi_route api;
struct zapi_nexthop *api_nh;
struct kroute kr;
int nhnum = 0, nhlen;
size_t nhmark;
int add = 0;
int i, add = 0;
if (zapi_route_decode(zclient->ibuf, &api) < 0)
return -1;
/* we completely ignore srcdest routes for now. */
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
return (0);
memset(&kr, 0, sizeof(kr));
s = zclient->ibuf;
kr.af = api.prefix.family;
switch (kr.af) {
case AF_INET:
kr.prefix.v4 = api.prefix.u.prefix4;
break;
case AF_INET6:
kr.prefix.v6 = api.prefix.u.prefix6;
break;
default:
break;
}
kr.prefixlen = api.prefix.prefixlen;
kr.priority = api.distance;
type = stream_getc(s);
switch (type) {
switch (api.type) {
case ZEBRA_ROUTE_CONNECT:
kr.flags |= F_CONNECTED;
break;
@ -419,84 +434,38 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
break;
}
stream_getl(s); /* flags, unused */
stream_getw(s); /* instance, unused */
message_flags = stream_getc(s);
switch (command) {
case ZEBRA_REDISTRIBUTE_IPV4_ADD:
case ZEBRA_REDISTRIBUTE_IPV4_DEL:
kr.af = AF_INET;
nhlen = sizeof(struct in_addr);
break;
case ZEBRA_REDISTRIBUTE_IPV6_ADD:
case ZEBRA_REDISTRIBUTE_IPV6_DEL:
kr.af = AF_INET6;
nhlen = sizeof(struct in6_addr);
break;
default:
fatalx("ldp_zebra_read_route: unknown command");
}
kr.prefixlen = stream_getc(s);
stream_get(&kr.prefix, s, PSIZE(kr.prefixlen));
if (bad_addr(kr.af, &kr.prefix) ||
(kr.af == AF_INET6 && IN6_IS_SCOPE_EMBED(&kr.prefix.v6)))
return (0);
if (kr.af == AF_INET6 &&
CHECK_FLAG(message_flags, ZAPI_MESSAGE_SRCPFX)) {
uint8_t src_prefixlen;
src_prefixlen = stream_getc(s);
/* we completely ignore srcdest routes for now. */
if (src_prefixlen)
return (0);
}
if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP)) {
nhnum = stream_getc(s);
nhmark = stream_get_getp(s);
stream_set_getp(s, nhmark + nhnum * (nhlen + 5));
}
if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_DISTANCE))
kr.priority = stream_getc(s);
if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_METRIC))
stream_getl(s); /* metric, not used */
if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP))
stream_set_getp(s, nhmark);
if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD ||
command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
add = 1;
if (nhnum == 0)
if (api.nexthop_num == 0)
debug_zebra_in("route %s %s/%d (%s)", (add) ? "add" : "delete",
log_addr(kr.af, &kr.prefix), kr.prefixlen,
zebra_route_string(type));
zebra_route_string(api.type));
/* loop through all the nexthops */
for (; nhnum > 0; nhnum--) {
for (i = 0; i < api.nexthop_num; i++) {
api_nh = &api.nexthops[i];
switch (kr.af) {
case AF_INET:
kr.nexthop.v4.s_addr = stream_get_ipv4(s);
kr.nexthop.v4 = api_nh->gate.ipv4;
break;
case AF_INET6:
stream_get(&kr.nexthop.v6, s, sizeof(kr.nexthop.v6));
kr.nexthop.v6 = api_nh->gate.ipv6;
break;
default:
break;
}
stream_getc(s); /* ifindex_num, unused. */
kr.ifindex = stream_getl(s);
kr.ifindex = api_nh->ifindex;;
debug_zebra_in("route %s %s/%d nexthop %s ifindex %u (%s)",
(add) ? "add" : "delete", log_addr(kr.af, &kr.prefix),
kr.prefixlen, log_addr(kr.af, &kr.nexthop), kr.ifindex,
zebra_route_string(type));
zebra_route_string(api.type));
if (add)
main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, &kr,
@ -553,10 +522,8 @@ ldp_zebra_init(struct thread_master *master)
zclient->interface_down = ldp_interface_status_change;
zclient->interface_address_add = ldp_interface_address_add;
zclient->interface_address_delete = ldp_interface_address_delete;
zclient->redistribute_route_ipv4_add = ldp_zebra_read_route;
zclient->redistribute_route_ipv4_del = ldp_zebra_read_route;
zclient->redistribute_route_ipv6_add = ldp_zebra_read_route;
zclient->redistribute_route_ipv6_del = ldp_zebra_read_route;
zclient->redistribute_route_add = ldp_zebra_read_route;
zclient->redistribute_route_del = ldp_zebra_read_route;
zclient->pw_status_update = ldp_zebra_read_pw_status_update;
}

View File

@ -392,6 +392,8 @@ ldpd_shutdown(void)
pid_t pid;
int status;
frr_early_fini();
/* close pipes */
msgbuf_clear(&iev_ldpe->ibuf.w);
close(iev_ldpe->ibuf.fd);
@ -423,13 +425,9 @@ ldpd_shutdown(void)
vrf_terminate();
access_list_reset();
cmd_terminate();
vty_terminate();
ldp_zebra_destroy();
zprivs_terminate(&ldpd_privs);
thread_master_free(master);
closezlog();
frr_fini();
exit(0);
}

View File

@ -22,7 +22,7 @@
#ifndef _LDPD_H_
#define _LDPD_H_
#include "openbsd-queue.h"
#include "queue.h"
#include "openbsd-tree.h"
#include "imsg.h"
#include "thread.h"

View File

@ -21,7 +21,7 @@
#ifndef _LDPE_H_
#define _LDPE_H_
#include "openbsd-queue.h"
#include "queue.h"
#include "openbsd-tree.h"
#ifdef __OpenBSD__
#include <net/pfkeyv2.h>

View File

@ -42,6 +42,7 @@
#include "command_graph.h"
#include "qobj.h"
#include "defaults.h"
#include "libfrr.h"
DEFINE_MTYPE(LIB, HOST, "Host config")
DEFINE_MTYPE(LIB, STRVEC, "String vector")
@ -376,21 +377,23 @@ void install_element(enum node_type ntype, struct cmd_element *cmd)
return;
}
cnode = vector_slot(cmdvec, ntype);
cnode = vector_lookup(cmdvec, ntype);
if (cnode == NULL) {
fprintf(stderr,
"Command node %d doesn't exist, please check it\n",
ntype);
fprintf(stderr,
"Have you called install_node before this install_element?\n");
"%s[%s]:\n"
"\tnode %d (%s) does not exist.\n"
"\tplease call install_node() before install_element()\n",
cmd->name, cmd->string, ntype, node_names[ntype]);
exit(EXIT_FAILURE);
}
if (hash_lookup(cnode->cmd_hash, cmd) != NULL) {
fprintf(stderr,
"Multiple command installs to node %d of command:\n%s\n",
ntype, cmd->string);
"%s[%s]:\n"
"\tnode %d (%s) already has this command installed.\n"
"\tduplicate install_element call?\n",
cmd->name, cmd->string, ntype, node_names[ntype]);
return;
}
@ -423,21 +426,23 @@ void uninstall_element(enum node_type ntype, struct cmd_element *cmd)
return;
}
cnode = vector_slot(cmdvec, ntype);
cnode = vector_lookup(cmdvec, ntype);
if (cnode == NULL) {
fprintf(stderr,
"Command node %d doesn't exist, please check it\n",
ntype);
fprintf(stderr,
"Have you called install_node before this install_element?\n");
"%s[%s]:\n"
"\tnode %d (%s) does not exist.\n"
"\tplease call install_node() before uninstall_element()\n",
cmd->name, cmd->string, ntype, node_names[ntype]);
exit(EXIT_FAILURE);
}
if (hash_release(cnode->cmd_hash, cmd) == NULL) {
fprintf(stderr,
"Trying to uninstall non-installed command (node %d):\n%s\n",
ntype, cmd->string);
"%s[%s]:\n"
"\tnode %d (%s) does not have this command installed.\n"
"\tduplicate uninstall_element call?\n",
cmd->name, cmd->string, ntype, node_names[ntype]);
return;
}
@ -572,6 +577,9 @@ static int config_write_host(struct vty *vty)
else if (!host.motd)
vty_out(vty, "no banner motd\n");
if (debug_memstats_at_exit)
vty_out(vty, "!\ndebug memstats-at-exit\n");
return 1;
}
@ -2417,6 +2425,17 @@ DEFUN (no_config_log_timestamp_precision,
return CMD_SUCCESS;
}
DEFUN (debug_memstats,
debug_memstats_cmd,
"[no] debug memstats-at-exit",
NO_STR
DEBUG_STR
"Print memory type statistics at exit\n")
{
debug_memstats_at_exit = !!strcmp(argv[0]->text, "no");
return CMD_SUCCESS;
}
int cmd_banner_motd_file(const char *file)
{
int success = CMD_SUCCESS;
@ -2589,6 +2608,7 @@ void cmd_init(int terminal)
/* Each node's basic commands. */
install_element(VIEW_NODE, &show_version_cmd);
install_element(ENABLE_NODE, &show_startup_config_cmd);
install_element(ENABLE_NODE, &debug_memstats_cmd);
if (terminal) {
install_element(VIEW_NODE, &config_list_cmd);
@ -2624,6 +2644,7 @@ void cmd_init(int terminal)
install_element(CONFIG_NODE, &domainname_cmd);
install_element(CONFIG_NODE, &no_domainname_cmd);
install_element(CONFIG_NODE, &frr_version_defaults_cmd);
install_element(CONFIG_NODE, &debug_memstats_cmd);
if (terminal > 0) {
install_element(CONFIG_NODE, &password_cmd);

View File

@ -46,8 +46,9 @@ DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack")
static int add_nexthops(struct list *, struct graph_node *,
struct graph_node **, size_t);
static struct list *command_match_r(struct graph_node *, vector, unsigned int,
struct graph_node **);
static enum matcher_rv command_match_r(struct graph_node *, vector,
unsigned int, struct graph_node **,
struct list **);
static int score_precedence(enum cmd_token_type);
@ -80,14 +81,12 @@ static enum match_type match_variable(struct cmd_token *, const char *);
static enum match_type match_mac(const char *, bool);
/* matching functions */
static enum matcher_rv matcher_rv;
enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
struct list **argv, const struct cmd_element **el)
{
struct graph_node *stack[MAXDEPTH];
matcher_rv = MATCHER_NO_MATCH;
enum matcher_rv status;
*argv = NULL;
// prepend a dummy token to match that pesky start node
vector vvline = vector_init(vline->alloced + 1);
@ -97,9 +96,8 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
vvline->active = vline->active + 1;
struct graph_node *start = vector_slot(cmdgraph->nodes, 0);
if ((*argv = command_match_r(start, vvline, 0,
stack))) // successful match
{
status = command_match_r(start, vvline, 0, stack, argv);
if (status == MATCHER_OK) { // successful match
struct listnode *head = listhead(*argv);
struct listnode *tail = listtail(*argv);
@ -115,6 +113,9 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
// input, with each cmd_token->arg holding the corresponding
// input
assert(*el);
} else if (*argv) {
del_arglist(*argv);
*argv = NULL;
}
if (!*el) {
@ -129,7 +130,7 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
// free vector
vector_free(vvline);
return matcher_rv;
return status;
}
/**
@ -183,11 +184,15 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
*
* If no match was found, the return value is NULL.
*/
static struct list *command_match_r(struct graph_node *start, vector vline,
unsigned int n, struct graph_node **stack)
static enum matcher_rv command_match_r(struct graph_node *start, vector vline,
unsigned int n,
struct graph_node **stack,
struct list **currbest)
{
assert(n < vector_active(vline));
enum matcher_rv status = MATCHER_NO_MATCH;
// get the minimum match level that can count as a full match
struct cmd_token *token = start->data;
enum match_type minmatch = min_match_level(token->type);
@ -196,11 +201,11 @@ static struct list *command_match_r(struct graph_node *start, vector vline,
* this disallows matching the same one more than once if there is a
* circle in the graph (used for keyword arguments) */
if (n == MAXDEPTH)
return NULL;
return MATCHER_NO_MATCH;
if (!token->allowrepeat)
for (size_t s = 0; s < n; s++)
if (stack[s] == start)
return NULL;
return MATCHER_NO_MATCH;
// get the current operating input token
char *input_token = vector_slot(vline, n);
@ -231,7 +236,7 @@ static struct list *command_match_r(struct graph_node *start, vector vline,
// if we don't match this node, die
if (match_token(token, input_token) < minmatch)
return NULL;
return MATCHER_NO_MATCH;
stack[n] = start;
@ -244,86 +249,92 @@ static struct list *command_match_r(struct graph_node *start, vector vline,
add_nexthops(next, start, NULL, 0);
// determine the best match
int ambiguous = 0;
struct list *currbest = NULL;
for (ALL_LIST_ELEMENTS_RO(next, ln, gn)) {
// if we've matched all input we're looking for END_TKN
if (n + 1 == vector_active(vline)) {
struct cmd_token *tok = gn->data;
if (tok->type == END_TKN) {
if (currbest) // there is more than one END_TKN
// in the follow set
{
ambiguous = 1;
// if more than one END_TKN in the follow set
if (*currbest) {
status = MATCHER_AMBIGUOUS;
break;
} else {
status = MATCHER_OK;
}
currbest = list_new();
*currbest = list_new();
// node should have one child node with the
// element
struct graph_node *leaf =
vector_slot(gn->to, 0);
// last node in the list will hold the
// cmd_element;
// this is important because list_delete()
// expects
// that all nodes have the same data type, so
// when
// deleting this list the last node must be
// manually deleted
// cmd_element; this is important because
// list_delete() expects that all nodes have
// the same data type, so when deleting this
// list the last node must be manually deleted
struct cmd_element *el = leaf->data;
listnode_add(currbest, el);
currbest->del =
listnode_add(*currbest, el);
(*currbest)->del =
(void (*)(void *)) & cmd_token_del;
// do not break immediately; continue walking
// through the follow set
// to ensure that there is exactly one END_TKN
// through the follow set to ensure that there
// is exactly one END_TKN
}
continue;
}
// else recurse on candidate child node
struct list *result = command_match_r(gn, vline, n + 1, stack);
struct list *result = NULL;
enum matcher_rv rstat =
command_match_r(gn, vline, n + 1, stack, &result);
// save the best match
if (result && currbest) {
if (result && *currbest) {
// pick the best of two matches
struct list *newbest =
disambiguate(currbest, result, vline, n + 1);
// set ambiguity flag
ambiguous =
!newbest || (ambiguous && newbest == currbest);
disambiguate(*currbest, result, vline, n + 1);
// current best and result are ambiguous
if (!newbest)
status = MATCHER_AMBIGUOUS;
// current best is still the best, but ambiguous
else if (newbest == *currbest
&& status == MATCHER_AMBIGUOUS)
status = MATCHER_AMBIGUOUS;
// result is better, but also ambiguous
else if (newbest == result
&& rstat == MATCHER_AMBIGUOUS)
status = MATCHER_AMBIGUOUS;
// one or the other is superior and not ambiguous
else
status = MATCHER_OK;
// delete the unnecessary result
struct list *todelete =
((newbest && newbest == result) ? currbest
((newbest && newbest == result) ? *currbest
: result);
del_arglist(todelete);
currbest = newbest ? newbest : currbest;
} else if (result)
currbest = result;
}
if (currbest) {
if (ambiguous) {
del_arglist(currbest);
currbest = NULL;
matcher_rv = MATCHER_AMBIGUOUS;
} else {
// copy token, set arg and prepend to currbest
struct cmd_token *token = start->data;
struct cmd_token *copy = cmd_token_dup(token);
copy->arg = XSTRDUP(MTYPE_CMD_ARG, input_token);
listnode_add_before(currbest, currbest->head, copy);
matcher_rv = MATCHER_OK;
*currbest = newbest ? newbest : *currbest;
} else if (result) {
status = rstat;
*currbest = result;
} else if (!*currbest) {
status = MAX(rstat, status);
}
} else if (n + 1 == vector_active(vline)
&& matcher_rv == MATCHER_NO_MATCH)
matcher_rv = MATCHER_INCOMPLETE;
}
if (*currbest) {
// copy token, set arg and prepend to currbest
struct cmd_token *token = start->data;
struct cmd_token *copy = cmd_token_dup(token);
copy->arg = XSTRDUP(MTYPE_CMD_ARG, input_token);
listnode_add_before(*currbest, (*currbest)->head, copy);
} else if (n + 1 == vector_active(vline) && status == MATCHER_NO_MATCH)
status = MATCHER_INCOMPLETE;
// cleanup
list_delete(next);
return currbest;
return status;
}
static void stack_del(void *val)
@ -432,12 +443,12 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
* next = set of all nodes reachable from all nodes in `matched`
*/
matcher_rv = idx == vector_active(vline) && next->count
? MATCHER_OK
: MATCHER_NO_MATCH;
enum matcher_rv mrv = idx == vector_active(vline) && next->count
? MATCHER_OK
: MATCHER_NO_MATCH;
*completions = NULL;
if (!MATCHER_ERROR(matcher_rv)) {
if (!MATCHER_ERROR(mrv)) {
// extract cmd_token into list
*completions = list_new();
for (ALL_LIST_ELEMENTS_RO(next, node, gstack)) {
@ -448,7 +459,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
list_delete(current);
list_delete(next);
return matcher_rv;
return mrv;
}
/**

81
lib/compiler.h Normal file
View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2015-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_COMPILER_H
#define _FRR_COMPILER_H
/* function attributes, use like
* void prototype(void) __attribute__((_CONSTRUCTOR(100)));
*/
#if defined(__clang__)
# if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5)
# define _RET_NONNULL , returns_nonnull
# endif
# define _CONSTRUCTOR(x) constructor(x)
#elif defined(__GNUC__)
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
# define _RET_NONNULL , returns_nonnull
# endif
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
# define _CONSTRUCTOR(x) constructor(x)
# define _DESTRUCTOR(x) destructor(x)
# define _ALLOC_SIZE(x) alloc_size(x)
# endif
#endif
#ifdef __sun
/* Solaris doesn't do constructor priorities due to linker restrictions */
# undef _CONSTRUCTOR
# undef _DESTRUCTOR
#endif
/* fallback versions */
#ifndef _RET_NONNULL
# define _RET_NONNULL
#endif
#ifndef _CONSTRUCTOR
# define _CONSTRUCTOR(x) constructor
#endif
#ifndef _DESTRUCTOR
# define _DESTRUCTOR(x) destructor
#endif
#ifndef _ALLOC_SIZE
# define _ALLOC_SIZE(x)
#endif
/*
* for warnings on macros, put in the macro content like this:
* #define MACRO BLA CPP_WARN("MACRO has been deprecated")
*/
#define CPP_STR(X) #X
#if defined(__ICC)
#define CPP_NOTICE(text) _Pragma(CPP_STR(message __FILE__ ": " text))
#define CPP_WARN(text) CPP_NOTICE(text)
#elif (defined(__GNUC__) \
&& (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \
|| (defined(__clang__) \
&& (__clang_major__ >= 4 \
|| (__clang_major__ == 3 && __clang_minor__ >= 5)))
#define CPP_WARN(text) _Pragma(CPP_STR(GCC warning text))
#define CPP_NOTICE(text) _Pragma(CPP_STR(message text))
#else
#define CPP_WARN(text)
#endif
#endif /* _FRR_COMPILER_H */

679
lib/freebsd-queue.h Normal file
View File

@ -0,0 +1,679 @@
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
* $FreeBSD$
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines four types of data structures: singly-linked lists,
* singly-linked tail queues, lists and tail queues.
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A singly-linked tail queue is headed by a pair of pointers, one to the
* head of the list and the other to the tail of the list. The elements are
* singly linked for minimum space and pointer manipulation overhead at the
* expense of O(n) removal for arbitrary elements. New elements can be added
* to the list after an existing element, at the head of the list, or at the
* end of the list. Elements being removed from the head of the tail queue
* should use the explicit macro for this purpose for optimum efficiency.
* A singly-linked tail queue may only be traversed in the forward direction.
* Singly-linked tail queues are ideal for applications with large datasets
* and few or no removals or for implementing a FIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* For details on the use of these macros, see the queue(3) manual page.
*
*
* SLIST LIST STAILQ TAILQ
* _HEAD + + + +
* _HEAD_INITIALIZER + + + +
* _ENTRY + + + +
* _INIT + + + +
* _EMPTY + + + +
* _FIRST + + + +
* _NEXT + + + +
* _PREV - - - +
* _LAST - - + +
* _FOREACH + + + +
* _FOREACH_SAFE + + + +
* _FOREACH_REVERSE - - - +
* _FOREACH_REVERSE_SAFE - - - +
* _INSERT_HEAD + + + +
* _INSERT_BEFORE - + - +
* _INSERT_AFTER + + + +
* _INSERT_TAIL - - + +
* _CONCAT - - + +
* _REMOVE_AFTER + - + -
* _REMOVE_HEAD + - + -
* _REMOVE + + + +
* _SWAP + + + +
*
*/
#ifdef QUEUE_MACRO_DEBUG
/* Store the last 2 places the queue element or head was altered */
struct qm_trace {
char *lastfile;
int lastline;
char *prevfile;
int prevline;
};
#define TRACEBUF struct qm_trace trace;
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
#define QMD_TRACE_HEAD(head) \
do { \
(head)->trace.prevline = (head)->trace.lastline; \
(head)->trace.prevfile = (head)->trace.lastfile; \
(head)->trace.lastline = __LINE__; \
(head)->trace.lastfile = __FILE__; \
} while (0)
#define QMD_TRACE_ELEM(elem) \
do { \
(elem)->trace.prevline = (elem)->trace.lastline; \
(elem)->trace.prevfile = (elem)->trace.lastfile; \
(elem)->trace.lastline = __LINE__; \
(elem)->trace.lastfile = __FILE__; \
} while (0)
#else
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
#define QMD_SAVELINK(name, link)
#define TRACEBUF
#define TRASHIT(x)
#endif /* QUEUE_MACRO_DEBUG */
/*
* Singly-linked List declarations.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ \
NULL \
}
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_FOREACH(var, head, field) \
for ((var) = SLIST_FIRST((head)); (var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST((head)); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); (var) = (tvar))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); ((var) = *(varp)) != NULL; \
(varp) = &SLIST_NEXT((var), field))
#define SLIST_INIT(head) \
do { \
SLIST_FIRST((head)) = NULL; \
} while (0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) \
do { \
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
SLIST_NEXT((slistelm), field) = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) \
do { \
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
SLIST_FIRST((head)) = (elm); \
} while (0)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_REMOVE(head, elm, type, field) \
do { \
QMD_SAVELINK(oldnext, (elm)->field.sle_next); \
if (SLIST_FIRST((head)) == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = SLIST_FIRST((head)); \
while (SLIST_NEXT(curelm, field) != (elm)) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_REMOVE_AFTER(curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) \
do { \
SLIST_NEXT(elm, field) = \
SLIST_NEXT(SLIST_NEXT(elm, field), field); \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) \
do { \
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
} while (0)
#define SLIST_SWAP(head1, head2, type) \
do { \
struct type *swap_first = SLIST_FIRST(head1); \
SLIST_FIRST(head1) = SLIST_FIRST(head2); \
SLIST_FIRST(head2) = swap_first; \
} while (0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first; /* first element */ \
struct type **stqh_last; /* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ \
NULL, &(head).stqh_first \
}
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_CONCAT(head1, head2) \
do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_FOREACH(var, head, field) \
for ((var) = STAILQ_FIRST((head)); (var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); (var) = (tvar))
#define STAILQ_INIT(head) \
do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) \
do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) \
== NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_NEXT((tqelm), field) = (elm); \
} while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) \
do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) \
== NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_FIRST((head)) = (elm); \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) \
do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) \
? NULL \
: ((struct type *)(void *)((char *)((head)->stqh_last) \
- offsetof(struct type, \
field))))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_REMOVE(head, elm, type, field) \
do { \
QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = STAILQ_FIRST((head)); \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)
#define STAILQ_REMOVE_AFTER(head, elm, field) \
do { \
if ((STAILQ_NEXT(elm, field) = \
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) \
== NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) \
do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) \
== NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_SWAP(head1, head2, type) \
do { \
struct type *swap_first = STAILQ_FIRST(head1); \
struct type **swap_last = (head1)->stqh_last; \
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_FIRST(head2) = swap_first; \
(head2)->stqh_last = swap_last; \
if (STAILQ_EMPTY(head1)) \
(head1)->stqh_last = &STAILQ_FIRST(head1); \
if (STAILQ_EMPTY(head2)) \
(head2)->stqh_last = &STAILQ_FIRST(head2); \
} while (0)
/*
* List declarations.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ \
NULL \
}
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_LIST_CHECK_HEAD(head, field) \
do { \
if (LIST_FIRST((head)) != NULL \
&& LIST_FIRST((head))->field.le_prev \
!= &LIST_FIRST((head))) \
panic("Bad list head %p first->prev != head", (head)); \
} while (0)
#define QMD_LIST_CHECK_NEXT(elm, field) \
do { \
if (LIST_NEXT((elm), field) != NULL \
&& LIST_NEXT((elm), field)->field.le_prev \
!= &((elm)->field.le_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_LIST_CHECK_PREV(elm, field) \
do { \
if (*(elm)->field.le_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_LIST_CHECK_HEAD(head, field)
#define QMD_LIST_CHECK_NEXT(elm, field)
#define QMD_LIST_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_FOREACH(var, head, field) \
for ((var) = LIST_FIRST((head)); (var); (var) = LIST_NEXT((var), field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); (var) = (tvar))
#define LIST_INIT(head) \
do { \
LIST_FIRST((head)) = NULL; \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) \
do { \
QMD_LIST_CHECK_NEXT(listelm, field); \
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) \
!= NULL) \
LIST_NEXT((listelm), field)->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_NEXT((listelm), field) = (elm); \
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) \
do { \
QMD_LIST_CHECK_PREV(listelm, field); \
(elm)->field.le_prev = (listelm)->field.le_prev; \
LIST_NEXT((elm), field) = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) \
do { \
QMD_LIST_CHECK_HEAD((head), field); \
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
LIST_FIRST((head))->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_FIRST((head)) = (elm); \
(elm)->field.le_prev = &LIST_FIRST((head)); \
} while (0)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_REMOVE(elm, field) \
do { \
QMD_SAVELINK(oldnext, (elm)->field.le_next); \
QMD_SAVELINK(oldprev, (elm)->field.le_prev); \
QMD_LIST_CHECK_NEXT(elm, field); \
QMD_LIST_CHECK_PREV(elm, field); \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
TRASHIT(*oldnext); \
TRASHIT(*oldprev); \
} while (0)
#define LIST_SWAP(head1, head2, type, field) \
do { \
struct type *swap_tmp = LIST_FIRST((head1)); \
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
LIST_FIRST((head2)) = swap_tmp; \
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
} while (0)
/*
* Tail queue declarations.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ \
NULL, &(head).tqh_first \
}
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
/*
* Tail queue functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_TAILQ_CHECK_HEAD(head, field) \
do { \
if (!TAILQ_EMPTY(head) \
&& TAILQ_FIRST((head))->field.tqe_prev \
!= &TAILQ_FIRST((head))) \
panic("Bad tailq head %p first->prev != head", \
(head)); \
} while (0)
#define QMD_TAILQ_CHECK_TAIL(head, field) \
do { \
if (*(head)->tqh_last != NULL) \
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
} while (0)
#define QMD_TAILQ_CHECK_NEXT(elm, field) \
do { \
if (TAILQ_NEXT((elm), field) != NULL \
&& TAILQ_NEXT((elm), field)->field.tqe_prev \
!= &((elm)->field.tqe_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_TAILQ_CHECK_PREV(elm, field) \
do { \
if (*(elm)->field.tqe_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_TAILQ_CHECK_HEAD(head, field)
#define QMD_TAILQ_CHECK_TAIL(head, headname)
#define QMD_TAILQ_CHECK_NEXT(elm, field)
#define QMD_TAILQ_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define TAILQ_CONCAT(head1, head2, field) \
do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = \
(head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
QMD_TRACE_HEAD(head1); \
QMD_TRACE_HEAD(head2); \
} \
} while (0)
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); (var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); (var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = TAILQ_LAST((head), headname); (var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST((head), headname); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_INIT(head) \
do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) \
do { \
QMD_TAILQ_CHECK_NEXT(listelm, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) \
!= NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) \
do { \
QMD_TAILQ_CHECK_PREV(listelm, field); \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) \
do { \
QMD_TAILQ_CHECK_HEAD(head, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) \
do { \
QMD_TAILQ_CHECK_TAIL(head, field); \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_REMOVE(head, elm, field) \
do { \
QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
QMD_TAILQ_CHECK_NEXT(elm, field); \
QMD_TAILQ_CHECK_PREV(elm, field); \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
QMD_TRACE_HEAD(head); \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
TRASHIT(*oldnext); \
TRASHIT(*oldprev); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_SWAP(head1, head2, type, field) \
do { \
struct type *swap_first = (head1)->tqh_first; \
struct type **swap_last = (head1)->tqh_last; \
(head1)->tqh_first = (head2)->tqh_first; \
(head1)->tqh_last = (head2)->tqh_last; \
(head2)->tqh_first = swap_first; \
(head2)->tqh_last = swap_last; \
if ((swap_first = (head1)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head1)->tqh_first; \
else \
(head1)->tqh_last = &(head1)->tqh_first; \
if ((swap_first = (head2)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head2)->tqh_first; \
else \
(head2)->tqh_last = &(head2)->tqh_first; \
} while (0)
#endif /* !_SYS_QUEUE_H_ */

191
lib/frr_zmq.c Normal file
View File

@ -0,0 +1,191 @@
/*
* libzebra ZeroMQ bindings
* Copyright (C) 2015 David Lamparter
*
* This program 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 of the License, or (at your option)
* any later version.
*
* This program 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 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
*/
#include <zebra.h>
#include <zmq.h>
#include "thread.h"
#include "memory.h"
#include "frr_zmq.h"
#include "log.h"
DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback")
/* libzmq's context */
void *frrzmq_context = NULL;
static unsigned frrzmq_initcount = 0;
void frrzmq_init(void)
{
if (frrzmq_initcount++ == 0) {
frrzmq_context = zmq_ctx_new();
zmq_ctx_set(frrzmq_context, ZMQ_IPV6, 1);
}
}
void frrzmq_finish(void)
{
if (--frrzmq_initcount == 0) {
zmq_ctx_term(frrzmq_context);
frrzmq_context = NULL;
}
}
/* read callback integration */
struct frrzmq_cb {
struct thread *thread;
void *zmqsock;
void *arg;
int fd;
bool cancelled;
void (*cb_msg)(void *arg, void *zmqsock);
void (*cb_part)(void *arg, void *zmqsock,
zmq_msg_t *msg, unsigned partnum);
};
static int frrzmq_read_msg(struct thread *t)
{
struct frrzmq_cb *cb = THREAD_ARG(t);
zmq_msg_t msg;
unsigned partno;
int ret, more;
size_t moresz;
while (1) {
zmq_pollitem_t polli = {
.socket = cb->zmqsock,
.events = ZMQ_POLLIN
};
ret = zmq_poll(&polli, 1, 0);
if (ret < 0)
goto out_err;
if (!(polli.revents & ZMQ_POLLIN))
break;
if (cb->cb_msg) {
cb->cb_msg(cb->arg, cb->zmqsock);
if (cb->cancelled) {
XFREE(MTYPE_ZEROMQ_CB, cb);
return 0;
}
continue;
}
partno = 0;
if (zmq_msg_init(&msg))
goto out_err;
do {
ret = zmq_msg_recv(&msg, cb->zmqsock, ZMQ_NOBLOCK);
if (ret < 0) {
if (errno == EAGAIN)
break;
zmq_msg_close(&msg);
goto out_err;
}
cb->cb_part(cb->arg, cb->zmqsock, &msg, partno);
if (cb->cancelled) {
zmq_msg_close(&msg);
XFREE(MTYPE_ZEROMQ_CB, cb);
return 0;
}
/* cb_part may have read additional parts of the
* message; don't use zmq_msg_more here */
moresz = sizeof(more);
more = 0;
ret = zmq_getsockopt(cb->zmqsock, ZMQ_RCVMORE,
&more, &moresz);
if (ret < 0) {
zmq_msg_close(&msg);
goto out_err;
}
partno++;
} while (more);
zmq_msg_close(&msg);
}
funcname_thread_add_read_write(THREAD_READ, t->master, frrzmq_read_msg,
cb, cb->fd, &cb->thread, t->funcname, t->schedfrom,
t->schedfrom_line);
return 0;
out_err:
zlog_err("ZeroMQ error: %s(%d)", strerror (errno), errno);
return 0;
}
struct frrzmq_cb *funcname_frrzmq_thread_add_read(
struct thread_master *master,
void (*msgfunc)(void *arg, void *zmqsock),
void (*partfunc)(void *arg, void *zmqsock,
zmq_msg_t *msg, unsigned partnum),
void *arg, void *zmqsock, debugargdef)
{
int fd, events;
size_t len;
struct frrzmq_cb *cb;
if (!(msgfunc || partfunc) || (msgfunc && partfunc))
return NULL;
len = sizeof(fd);
if (zmq_getsockopt(zmqsock, ZMQ_FD, &fd, &len))
return NULL;
len = sizeof(events);
if (zmq_getsockopt(zmqsock, ZMQ_EVENTS, &events, &len))
return NULL;
cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
if (!cb)
return NULL;
cb->arg = arg;
cb->zmqsock = zmqsock;
cb->cb_msg = msgfunc;
cb->cb_part = partfunc;
cb->fd = fd;
if (events & ZMQ_POLLIN)
funcname_thread_add_event(master,
frrzmq_read_msg, cb, fd, &cb->thread,
funcname, schedfrom, fromln);
else
funcname_thread_add_read_write(THREAD_READ, master,
frrzmq_read_msg, cb, fd, &cb->thread,
funcname, schedfrom, fromln);
return cb;
}
void frrzmq_thread_cancel(struct frrzmq_cb *cb)
{
if (!cb->thread) {
/* canceling from within callback */
cb->cancelled = 1;
return;
}
thread_cancel(cb->thread);
XFREE(MTYPE_ZEROMQ_CB, cb);
}

88
lib/frr_zmq.h Normal file
View File

@ -0,0 +1,88 @@
/*
* libzebra ZeroMQ bindings
* Copyright (C) 2015 David Lamparter
*
* This program 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 of the License, or (at your option)
* any later version.
*
* This program 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 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 _FRRZMQ_H
#define _FRRZMQ_H
#include "thread.h"
#include <zmq.h>
/* linking/packaging note: this is a separate library that needs to be
* linked into any daemon/library/module that wishes to use its
* functionality. The purpose of this is to encapsulate the libzmq
* dependency and not make libfrr/FRR itself depend on libzmq.
*
* libfrrzmq should be put in LDFLAGS/LIBADD *before* either libfrr or
* libzmq, and both of these should always be listed, e.g.
* foo_LDFLAGS = libfrrzmq.la libfrr.la $(ZEROMQ_LIBS)
*/
/* libzmq's context
*
* this is mostly here as a convenience, it has IPv6 enabled but nothing
* else is tied to it; you can use a separate context without problems
*/
extern void *frrzmq_context;
extern void frrzmq_init (void);
extern void frrzmq_finish (void);
#define debugargdef const char *funcname, const char *schedfrom, int fromln
/* core event registration, one of these 2 macros should be used */
#define frrzmq_thread_add_read_msg(m,f,a,z) funcname_frrzmq_thread_add_read( \
m,f,NULL,a,z,#f,__FILE__,__LINE__)
#define frrzmq_thread_add_read_part(m,f,a,z) funcname_frrzmq_thread_add_read( \
m,NULL,f,a,z,#f,__FILE__,__LINE__)
struct frrzmq_cb;
/* Set up a POLLIN notification to be called from the libfrr main loop.
* This has the following properties:
*
* - since ZeroMQ works with edge triggered notifications, it will loop and
* dispatch as many events as ZeroMQ has pending at the time libfrr calls
* into this code
* - due to this looping (which means it non-single-issue), the callback is
* also persistent. Do _NOT_ re-register the event inside of your
* callback function.
* - either msgfunc or partfunc will be called (only one can be specified)
* - msgfunc is called once for each incoming message
* - if partfunc is specified, the message is read and partfunc is called
* for each ZeroMQ multi-part subpart. Note that you can't send replies
* before all parts have been read because that violates the ZeroMQ FSM.
* - you can safely cancel the callback from within itself
* - installing a callback will check for pending events (ZMQ_EVENTS) and
* may schedule the event to run as soon as libfrr is back in its main
* loop.
*
* TODO #1: add ZMQ_POLLERR / error callback
* TODO #2: add frrzmq_check_events() function to check for edge triggered
* things that may have happened after a zmq_send() call or so
*/
extern struct frrzmq_cb *funcname_frrzmq_thread_add_read(
struct thread_master *master,
void (*msgfunc)(void *arg, void *zmqsock),
void (*partfunc)(void *arg, void *zmqsock,
zmq_msg_t *msg, unsigned partnum),
void *arg, void *zmqsock, debugargdef);
extern void frrzmq_thread_cancel(struct frrzmq_cb *cb);
#endif /* _FRRZMQ_H */

View File

@ -404,7 +404,8 @@ DEFUN (grammar_findambig,
nodegraph = cnode->cmdgraph;
if (!nodegraph)
continue;
vty_out(vty, "scanning node %d\n", scannode - 1);
vty_out(vty, "scanning node %d (%s)\n",
scannode - 1, node_names[scannode - 1]);
}
commands = cmd_graph_permutations(nodegraph);

View File

@ -335,12 +335,13 @@ void hash_free(struct hash *hash)
/* CLI commands ------------------------------------------------------------ */
DEFUN(show_hash_stats,
show_hash_stats_cmd,
"show hashtable [statistics]",
SHOW_STR
"Statistics about hash tables\n"
"Statistics about hash tables\n")
DEFUN_NOSH(show_hash_stats,
show_hash_stats_cmd,
"show debugging hashtable [statistics]",
SHOW_STR
DEBUG_STR
"Statistics about hash tables\n"
"Statistics about hash tables\n")
{
struct hash *h;
struct listnode *ln;

View File

@ -26,17 +26,25 @@
DEFINE_MTYPE_STATIC(LIB, HOOK_ENTRY, "Hook entry")
void _hook_register(struct hook *hook, void *funcptr, void *arg, bool has_arg,
struct frrmod_runtime *module, const char *funcname)
struct frrmod_runtime *module, const char *funcname,
int priority)
{
struct hookent *he = XCALLOC(MTYPE_HOOK_ENTRY, sizeof(*he));
struct hookent *he = XCALLOC(MTYPE_HOOK_ENTRY, sizeof(*he)), **pos;
he->hookfn = funcptr;
he->hookarg = arg;
he->has_arg = has_arg;
he->module = module;
he->fnname = funcname;
he->priority = priority;
he->next = hook->entries;
hook->entries = he;
for (pos = &hook->entries; *pos; pos = &(*pos)->next)
if (hook->reverse
? (*pos)->priority < priority
: (*pos)->priority >= priority)
break;
he->next = *pos;
*pos = he;
}
void _hook_unregister(struct hook *hook, void *funcptr, void *arg, bool has_arg)

View File

@ -74,6 +74,29 @@
* hook_register_arg (some_update_event, event_handler, addonptr);
*
* (addonptr isn't typesafe, but that should be manageable.)
*
* Hooks also support a "priority" value for ordering registered calls
* relative to each other. The priority is a signed integer where lower
* values are called earlier. There is also "Koohs", which is hooks with
* reverse priority ordering (for cleanup/deinit hooks, so you can use the
* same priority value).
*
* Recommended priority value ranges are:
*
* -999 ... 0 ... 999 - main executable / daemon, or library
* -1999 ... -1000 - modules registering calls that should run before
* the daemon's bits
* 1000 ... 1999 - modules calls that should run after daemon's
*
* Note: the default value is 1000, based on the following 2 expectations:
* - most hook_register() usage will be in loadable modules
* - usage of hook_register() in the daemon itself may need relative ordering
* to itself, making an explicit value the expected case
*
* The priority value is passed as extra argument on hook_register_prio() /
* hook_register_arg_prio(). Whether a hook runs in reverse is determined
* solely by the code defining / calling the hook. (DECLARE_KOOH is actually
* the same thing as DECLARE_HOOK, it's just there to make it obvious.)
*/
/* TODO:
@ -94,6 +117,7 @@ struct hookent {
void *hookfn; /* actually a function pointer */
void *hookarg;
bool has_arg;
int priority;
struct frrmod_runtime *module;
const char *fnname;
};
@ -101,8 +125,11 @@ struct hookent {
struct hook {
const char *name;
struct hookent *entries;
bool reverse;
};
#define HOOK_DEFAULT_PRIORITY 1000
/* subscribe/add callback function to a hook
*
* always use hook_register(), which uses the static inline helper from
@ -110,14 +137,21 @@ struct hook {
*/
extern void _hook_register(struct hook *hook, void *funcptr, void *arg,
bool has_arg, struct frrmod_runtime *module,
const char *funcname);
const char *funcname, int priority);
#define hook_register(hookname, func) \
_hook_register(&_hook_##hookname, _hook_typecheck_##hookname(func), \
NULL, false, THIS_MODULE, #func)
NULL, false, THIS_MODULE, #func, HOOK_DEFAULT_PRIORITY)
#define hook_register_arg(hookname, func, arg) \
_hook_register(&_hook_##hookname, \
_hook_typecheck_arg_##hookname(func), arg, true, \
THIS_MODULE, #func)
THIS_MODULE, #func, HOOK_DEFAULT_PRIORITY)
#define hook_register_prio(hookname, prio, func) \
_hook_register(&_hook_##hookname, _hook_typecheck_##hookname(func), \
NULL, false, THIS_MODULE, #func, prio)
#define hook_register_arg_prio(hookname, prio, func, arg) \
_hook_register(&_hook_##hookname, \
_hook_typecheck_arg_##hookname(func), \
arg, true, THIS_MODULE, #func, prio)
extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
bool has_arg);
@ -156,12 +190,14 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
{ \
return (void *)funcptr; \
}
#define DECLARE_KOOH(hookname, arglist, passlist) \
DECLARE_HOOK(hookname, arglist, passlist)
/* use in source file - contains hook-related definitions.
*/
#define DEFINE_HOOK(hookname, arglist, passlist) \
#define DEFINE_HOOK_INT(hookname, arglist, passlist, rev) \
struct hook _hook_##hookname = { \
.name = #hookname, .entries = NULL, \
.name = #hookname, .entries = NULL, .reverse = rev, \
}; \
static int hook_call_##hookname arglist \
{ \
@ -184,4 +220,9 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
return hooksum; \
}
#define DEFINE_HOOK(hookname, arglist, passlist) \
DEFINE_HOOK_INT(hookname, arglist, passlist, false)
#define DEFINE_KOOH(hookname, arglist, passlist) \
DEFINE_HOOK_INT(hookname, arglist, passlist, true)
#endif /* _FRR_HOOK_H */

View File

@ -42,17 +42,12 @@ DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters")
DEFINE_QOBJ_TYPE(interface)
DEFINE_HOOK(if_add, (struct interface *ifp), (ifp))
DEFINE_KOOH(if_del, (struct interface *ifp), (ifp))
/* List of interfaces in only the default VRF */
int ptm_enable = 0;
/* One for each program. This structure is needed to store hooks. */
struct if_master {
int (*if_new_hook)(struct interface *);
int (*if_delete_hook)(struct interface *);
} if_master = {
0,
};
/* Compare interface names, returning an integer greater than, equal to, or
* less than 0, (following the strcmp convention), according to the
* relationship between ifp1 and ifp2. Interface names consist of an
@ -150,10 +145,7 @@ struct interface *if_create(const char *name, int namelen, vrf_id_t vrf_id)
SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
QOBJ_REG(ifp, interface);
if (if_master.if_new_hook)
(*if_master.if_new_hook)(ifp);
hook_call(if_add, ifp);
return ifp;
}
@ -182,9 +174,7 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
/* Delete interface structure. */
void if_delete_retain(struct interface *ifp)
{
if (if_master.if_delete_hook)
(*if_master.if_delete_hook)(ifp);
hook_call(if_del, ifp);
QOBJ_UNREG(ifp);
/* Free connected address list */
@ -209,21 +199,6 @@ void if_delete(struct interface *ifp)
XFREE(MTYPE_IF, ifp);
}
/* Add hook to interface master. */
void if_add_hook(int type, int (*func)(struct interface *ifp))
{
switch (type) {
case IF_NEW_HOOK:
if_master.if_new_hook = func;
break;
case IF_DELETE_HOOK:
if_master.if_delete_hook = func;
break;
default:
break;
}
}
/* Interface existance check by index. */
struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id)
{

View File

@ -25,6 +25,7 @@
#include "linklist.h"
#include "memory.h"
#include "qobj.h"
#include "hook.h"
DECLARE_MTYPE(IF)
DECLARE_MTYPE(CONNECTED_LABEL)
@ -283,6 +284,17 @@ struct interface {
};
DECLARE_QOBJ_TYPE(interface)
/* called from the library code whenever interfaces are created/deleted
* note: interfaces may not be fully realized at that point; also they
* may not exist in the system (ifindex = IFINDEX_INTERNAL)
*
* priority values are important here, daemons should be at 0 while modules
* can use 1000+ so they run after the daemon has initialised daemon-specific
* interface data
*/
DECLARE_HOOK(if_add, (struct interface *ifp), (ifp))
DECLARE_KOOH(if_del, (struct interface *ifp), (ifp))
/* Connected address structure. */
struct connected {
/* Attached interface. */
@ -355,10 +367,6 @@ struct nbr_connected {
? (C)->destination \
: (C)->address)
/* Interface hook sort. */
#define IF_NEW_HOOK 0
#define IF_DELETE_HOOK 1
/* There are some interface flags which are only supported by some
operating system. */
@ -442,7 +450,6 @@ extern int if_is_loopback(struct interface *);
extern int if_is_broadcast(struct interface *);
extern int if_is_pointopoint(struct interface *);
extern int if_is_multicast(struct interface *);
extern void if_add_hook(int, int (*)(struct interface *));
extern void if_init(struct list **);
extern void if_cmd_init(void);
extern void if_terminate(struct list **);

View File

@ -18,7 +18,7 @@
#include <zebra.h>
#include "openbsd-queue.h"
#include "queue.h"
#include "imsg.h"
int ibuf_realloc(struct ibuf *, size_t);

View File

@ -18,7 +18,7 @@
#include <zebra.h>
#include "openbsd-queue.h"
#include "queue.h"
#include "imsg.h"
int imsg_fd_overhead = 0;

View File

@ -37,6 +37,8 @@
#include "network.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
DEFINE_KOOH(frr_early_fini, (), ())
DEFINE_KOOH(frr_fini, (), ())
const char frr_sysconfdir[] = SYSCONFDIR;
const char frr_vtydir[] = DAEMON_VTY_DIR;
@ -50,6 +52,8 @@ char frr_zclientpath[256];
static char pidfile_default[256];
static char vtypath_default[256];
bool debug_memstats_at_exit = 0;
static char comb_optstr[256];
static struct option comb_lo[64];
static struct option *comb_next_lo = &comb_lo[0];
@ -637,7 +641,10 @@ static void frr_daemon_wait(int fd)
exit(0);
/* child failed one way or another ... */
if (WIFEXITED(exitstat))
if (WIFEXITED(exitstat) && WEXITSTATUS(exitstat) == 0)
/* can happen in --terminal case if exit is fast enough */
(void)0;
else if (WIFEXITED(exitstat))
fprintf(stderr, "%s failed to start, exited %d\n", di->name,
WEXITSTATUS(exitstat));
else if (WIFSIGNALED(exitstat))
@ -831,3 +838,50 @@ void frr_run(struct thread_master *master)
while (thread_fetch(master, &thread))
thread_call(&thread);
}
void frr_early_fini(void)
{
hook_call(frr_early_fini);
}
void frr_fini(void)
{
FILE *fp;
char filename[128];
int have_leftovers;
hook_call(frr_fini);
/* memory_init -> nothing needed */
vty_terminate();
cmd_terminate();
zprivs_terminate(di->privs);
/* signal_init -> nothing needed */
thread_master_free(master);
closezlog();
/* frrmod_init -> nothing needed / hooks */
if (!debug_memstats_at_exit)
return;
have_leftovers = log_memstats(stderr, di->name);
/* in case we decide at runtime that we want exit-memstats for
* a daemon, but it has no stderr because it's daemonized
* (only do this if we actually have something to print though)
*/
if (!have_leftovers)
return;
snprintf(filename, sizeof(filename),
"/tmp/frr-memstats-%s-%llu-%llu",
di->name,
(unsigned long long)getpid(),
(unsigned long long)time(NULL));
fp = fopen(filename, "w");
if (fp) {
log_memstats(fp, di->name);
fclose(fp);
}
}

View File

@ -104,6 +104,14 @@ extern void frr_run(struct thread_master *master);
extern bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
const char *path);
/* these two are before the protocol daemon does its own shutdown
* it's named this way being the counterpart to frr_late_init */
DECLARE_KOOH(frr_early_fini, (), ())
extern void frr_early_fini(void);
/* and these two are after the daemon did its own cleanup */
DECLARE_KOOH(frr_fini, (), ())
extern void frr_fini(void);
extern char config_default[256];
extern char frr_zclientpath[256];
extern const char frr_sysconfdir[];
@ -113,4 +121,6 @@ extern const char frr_moduledir[];
extern char frr_protoname[];
extern char frr_protonameinst[];
extern bool debug_memstats_at_exit;
#endif /* _ZEBRA_FRR_H */

View File

@ -701,7 +701,7 @@ void _zlog_assert_failed(const char *assertion, const char *file,
assertion, file, line, (function ? function : "?"));
zlog_backtrace(LOG_CRIT);
zlog_thread_info(LOG_CRIT);
log_memstats_stderr("log");
log_memstats(stderr, "log");
abort();
}
@ -867,6 +867,8 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_INTERFACE_UP),
DESC_ENTRY(ZEBRA_INTERFACE_DOWN),
DESC_ENTRY(ZEBRA_INTERFACE_SET_MASTER),
DESC_ENTRY(ZEBRA_ROUTE_ADD),
DESC_ENTRY(ZEBRA_ROUTE_DELETE),
DESC_ENTRY(ZEBRA_IPV4_ROUTE_ADD),
DESC_ENTRY(ZEBRA_IPV4_ROUTE_DELETE),
DESC_ENTRY(ZEBRA_IPV6_ROUTE_ADD),
@ -893,10 +895,8 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_BFD_DEST_DEREGISTER),
DESC_ENTRY(ZEBRA_BFD_DEST_UPDATE),
DESC_ENTRY(ZEBRA_BFD_DEST_REPLAY),
DESC_ENTRY(ZEBRA_REDISTRIBUTE_IPV4_ADD),
DESC_ENTRY(ZEBRA_REDISTRIBUTE_IPV4_DEL),
DESC_ENTRY(ZEBRA_REDISTRIBUTE_IPV6_ADD),
DESC_ENTRY(ZEBRA_REDISTRIBUTE_IPV6_DEL),
DESC_ENTRY(ZEBRA_REDISTRIBUTE_ROUTE_ADD),
DESC_ENTRY(ZEBRA_REDISTRIBUTE_ROUTE_DEL),
DESC_ENTRY(ZEBRA_VRF_UNREGISTER),
DESC_ENTRY(ZEBRA_VRF_ADD),
DESC_ENTRY(ZEBRA_VRF_DELETE),
@ -908,10 +908,6 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_INTERFACE_LINK_PARAMS),
DESC_ENTRY(ZEBRA_MPLS_LABELS_ADD),
DESC_ENTRY(ZEBRA_MPLS_LABELS_DELETE),
DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_ADD),
DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_DELETE),
DESC_ENTRY(ZEBRA_IPV6_NEXTHOP_ADD),
DESC_ENTRY(ZEBRA_IPV6_NEXTHOP_DELETE),
DESC_ENTRY(ZEBRA_IPMR_ROUTE_STATS),
DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT),
DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK),

View File

@ -104,6 +104,7 @@ int qmem_walk(qmem_walk_fn *func, void *arg)
}
struct exit_dump_args {
FILE *fp;
const char *prefix;
int error;
};
@ -113,7 +114,7 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt)
struct exit_dump_args *eda = arg;
if (!mt) {
fprintf(stderr,
fprintf(eda->fp,
"%s: showing active allocations in "
"memory group %s\n",
eda->prefix, mg->name);
@ -122,15 +123,16 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt)
char size[32];
eda->error++;
snprintf(size, sizeof(size), "%10zu", mt->size);
fprintf(stderr, "%s: memstats: %-30s: %6zu * %s\n",
fprintf(eda->fp, "%s: memstats: %-30s: %6zu * %s\n",
eda->prefix, mt->name, mt->n_alloc,
mt->size == SIZE_VAR ? "(variably sized)" : size);
}
return 0;
}
void log_memstats_stderr(const char *prefix)
int log_memstats(FILE *fp, const char *prefix)
{
struct exit_dump_args eda = {.prefix = prefix, .error = 0};
struct exit_dump_args eda = { .fp = fp, .prefix = prefix, .error = 0 };
qmem_walk(qmem_exit_walker, &eda);
return eda.error;
}

View File

@ -18,7 +18,9 @@
#define _QUAGGA_MEMORY_H
#include <stdlib.h>
#include <stdio.h>
#include <frratomic.h>
#include "compiler.h"
#define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
@ -36,41 +38,6 @@ struct memgroup {
const char *name;
};
#if defined(__clang__)
#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5)
# define _RET_NONNULL , returns_nonnull
#endif
# define _CONSTRUCTOR(x) constructor(x)
#elif defined(__GNUC__)
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
# define _RET_NONNULL , returns_nonnull
#endif
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
# define _CONSTRUCTOR(x) constructor(x)
# define _DESTRUCTOR(x) destructor(x)
# define _ALLOC_SIZE(x) alloc_size(x)
#endif
#endif
#ifdef __sun
/* Solaris doesn't do constructor priorities due to linker restrictions */
#undef _CONSTRUCTOR
#undef _DESTRUCTOR
#endif
#ifndef _RET_NONNULL
# define _RET_NONNULL
#endif
#ifndef _CONSTRUCTOR
# define _CONSTRUCTOR(x) constructor
#endif
#ifndef _DESTRUCTOR
# define _DESTRUCTOR(x) destructor
#endif
#ifndef _ALLOC_SIZE
# define _ALLOC_SIZE(x)
#endif
/* macro usage:
*
* mydaemon.h
@ -194,7 +161,8 @@ static inline size_t mtype_stats_alloc(struct memtype *mt)
* last value from qmem_walk_fn. */
typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt);
extern int qmem_walk(qmem_walk_fn *func, void *arg);
extern void log_memstats_stderr(const char *);
extern int log_memstats(FILE *fp, const char *);
#define log_memstats_stderr(prefix) log_memstats(stderr, prefix)
extern void memory_oom(size_t size, const char *name);

View File

@ -42,8 +42,10 @@ static struct frrmod_info frrmod_default_info = {
.description = "libfrr core module",
};
union _frrmod_runtime_u frrmod_default = {
.r.info = &frrmod_default_info,
.r.finished_loading = 1,
.r = {
.info = &frrmod_default_info,
.finished_loading = 1,
},
};
// if defined(HAVE_SYS_WEAK_ALIAS_ATTRIBUTE)

View File

@ -44,6 +44,9 @@
#define MPLS_DEFAULT_MIN_SRGB_LABEL 16000
#define MPLS_DEFAULT_MAX_SRGB_LABEL 23999
/* Maximum # labels that can be pushed. */
#define MPLS_MAX_LABELS 16
#define IS_MPLS_RESERVED_LABEL(label) \
(label >= MPLS_MIN_RESERVED_LABEL && label <= MPLS_MAX_RESERVED_LABEL)

View File

@ -122,6 +122,14 @@ const char *prefix_list_name(struct prefix_list *plist)
return plist->name;
}
afi_t prefix_list_afi(struct prefix_list *plist)
{
if (plist->master == &prefix_master_ipv4
|| plist->master == &prefix_master_orf_v4)
return AFI_IP;
return AFI_IP6;
}
/* Lookup prefix_list from list of prefix_list by name. */
static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf,
const char *name)

View File

@ -48,6 +48,7 @@ extern void prefix_list_add_hook(void (*func)(struct prefix_list *));
extern void prefix_list_delete_hook(void (*func)(struct prefix_list *));
extern const char *prefix_list_name(struct prefix_list *);
extern afi_t prefix_list_afi(struct prefix_list *);
extern struct prefix_list *prefix_list_lookup(afi_t, const char *);
extern enum prefix_list_type prefix_list_apply(struct prefix_list *, void *);

View File

@ -497,8 +497,7 @@ int prefix_same(const struct prefix *p1, const struct prefix *p2)
if (p1->family == p2->family && p1->prefixlen == p2->prefixlen) {
if (p1->family == AF_INET)
if (IPV4_ADDR_SAME(&p1->u.prefix4.s_addr,
&p2->u.prefix4.s_addr))
if (IPV4_ADDR_SAME(&p1->u.prefix4, &p2->u.prefix4))
return 1;
if (p1->family == AF_INET6)
if (IPV6_ADDR_SAME(&p1->u.prefix6.s6_addr,
@ -1264,5 +1263,6 @@ unsigned prefix_hash_key(void *pp)
* padding and unused prefix bytes. */
memset(&copy, 0, sizeof(copy));
prefix_copy(&copy, (struct prefix *)pp);
return jhash(&copy, sizeof(copy), 0x55aa5a5a);
return jhash(&copy, offsetof(struct prefix, u.prefix)
+ PSIZE(copy.prefixlen), 0x55aa5a5a);
}

View File

@ -33,28 +33,13 @@
#endif
#include "sockunion.h"
#include "ipaddr.h"
#include "compiler.h"
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
/* for compatibility */
#if defined(__ICC)
#define CPP_WARN_STR(X) #X
#define CPP_WARN(text) _Pragma(CPP_WARN_STR(message __FILE__ ": " text))
#elif (defined(__GNUC__) \
&& (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \
|| (defined(__clang__) \
&& (__clang_major__ >= 4 \
|| (__clang_major__ == 3 && __clang_minor__ >= 5)))
#define CPP_WARN_STR(X) #X
#define CPP_WARN(text) _Pragma(CPP_WARN_STR(GCC warning text))
#else
#define CPP_WARN(text)
#endif
#ifdef ETHER_ADDR_LEN
#undef ETHER_ADDR_LEN
#endif
@ -140,7 +125,7 @@ struct prefix {
struct in_addr adv_router;
} lp;
struct ethaddr prefix_eth; /* AF_ETHERNET */
u_char val[8];
u_char val[16];
uintptr_t ptr;
struct evpn_addr prefix_evpn; /* AF_EVPN */
} u __attribute__((aligned(8)));
@ -241,8 +226,20 @@ union prefixconstptr {
#define IPV4_MAX_BITLEN 32
#define IPV4_MAX_PREFIXLEN 32
#define IPV4_ADDR_CMP(D,S) memcmp ((D), (S), IPV4_MAX_BYTELEN)
#define IPV4_ADDR_SAME(D,S) (memcmp ((D), (S), IPV4_MAX_BYTELEN) == 0)
#define IPV4_ADDR_COPY(D,S) memcpy ((D), (S), IPV4_MAX_BYTELEN)
static inline bool ipv4_addr_same(const struct in_addr *a,
const struct in_addr *b)
{
return (a->s_addr == b->s_addr);
}
#define IPV4_ADDR_SAME(A,B) ipv4_addr_same((A), (B))
static inline void ipv4_addr_copy(struct in_addr *dst,
const struct in_addr *src)
{
dst->s_addr = src->s_addr;
}
#define IPV4_ADDR_COPY(D,S) ipv4_addr_copy((D), (S))
#define IPV4_NET0(a) ((((u_int32_t) (a)) & 0xff000000) == 0x00000000)
#define IPV4_NET127(a) ((((u_int32_t) (a)) & 0xff000000) == 0x7f000000)

View File

@ -856,7 +856,9 @@ void zprivs_terminate(struct zebra_privs_t *zprivs)
}
#ifdef HAVE_CAPABILITIES
zprivs_caps_terminate();
if (zprivs->user || zprivs->group || zprivs->cap_num_p
|| zprivs->cap_num_i)
zprivs_caps_terminate();
#else /* !HAVE_CAPABILITIES */
/* only change uid if we don't have the correct one */
if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid)) {

View File

@ -1,679 +1,76 @@
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
* $FreeBSD$
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines four types of data structures: singly-linked lists,
* singly-linked tail queues, lists and tail queues.
* lists and queues implementations
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
* This program 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 of the License, or (at your option)
* any later version.
*
* A singly-linked tail queue is headed by a pair of pointers, one to the
* head of the list and the other to the tail of the list. The elements are
* singly linked for minimum space and pointer manipulation overhead at the
* expense of O(n) removal for arbitrary elements. New elements can be added
* to the list after an existing element, at the head of the list, or at the
* end of the list. Elements being removed from the head of the tail queue
* should use the explicit macro for this purpose for optimum efficiency.
* A singly-linked tail queue may only be traversed in the forward direction.
* Singly-linked tail queues are ideal for applications with large datasets
* and few or no removals or for implementing a FIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* For details on the use of these macros, see the queue(3) manual page.
*
*
* SLIST LIST STAILQ TAILQ
* _HEAD + + + +
* _HEAD_INITIALIZER + + + +
* _ENTRY + + + +
* _INIT + + + +
* _EMPTY + + + +
* _FIRST + + + +
* _NEXT + + + +
* _PREV - - - +
* _LAST - - + +
* _FOREACH + + + +
* _FOREACH_SAFE + + + +
* _FOREACH_REVERSE - - - +
* _FOREACH_REVERSE_SAFE - - - +
* _INSERT_HEAD + + + +
* _INSERT_BEFORE - + - +
* _INSERT_AFTER + + + +
* _INSERT_TAIL - - + +
* _CONCAT - - + +
* _REMOVE_AFTER + - + -
* _REMOVE_HEAD + - + -
* _REMOVE + + + +
* _SWAP + + + +
* This program 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 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
*/
#ifdef QUEUE_MACRO_DEBUG
/* Store the last 2 places the queue element or head was altered */
struct qm_trace {
char *lastfile;
int lastline;
char *prevfile;
int prevline;
};
#define TRACEBUF struct qm_trace trace;
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
#ifndef _FRR_QUEUE_H
#define _FRR_QUEUE_H
#define QMD_TRACE_HEAD(head) \
do { \
(head)->trace.prevline = (head)->trace.lastline; \
(head)->trace.prevfile = (head)->trace.lastfile; \
(head)->trace.lastline = __LINE__; \
(head)->trace.lastfile = __FILE__; \
} while (0)
#if defined(__OpenBSD__) && !defined(STAILQ_HEAD)
#include "openbsd-queue.h"
#define QMD_TRACE_ELEM(elem) \
do { \
(elem)->trace.prevline = (elem)->trace.lastline; \
(elem)->trace.prevfile = (elem)->trace.lastfile; \
(elem)->trace.lastline = __LINE__; \
(elem)->trace.lastfile = __FILE__; \
} while (0)
#else
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
#define QMD_SAVELINK(name, link)
#define TRACEBUF
#define TRASHIT(x)
#endif /* QUEUE_MACRO_DEBUG */
/*
* Singly-linked List declarations.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ \
NULL \
}
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_FOREACH(var, head, field) \
for ((var) = SLIST_FIRST((head)); (var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST((head)); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); (var) = (tvar))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); ((var) = *(varp)) != NULL; \
(varp) = &SLIST_NEXT((var), field))
#define SLIST_INIT(head) \
do { \
SLIST_FIRST((head)) = NULL; \
} while (0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) \
do { \
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
SLIST_NEXT((slistelm), field) = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) \
do { \
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
SLIST_FIRST((head)) = (elm); \
} while (0)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_REMOVE(head, elm, type, field) \
do { \
QMD_SAVELINK(oldnext, (elm)->field.sle_next); \
if (SLIST_FIRST((head)) == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = SLIST_FIRST((head)); \
while (SLIST_NEXT(curelm, field) != (elm)) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_REMOVE_AFTER(curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) \
do { \
SLIST_NEXT(elm, field) = \
SLIST_NEXT(SLIST_NEXT(elm, field), field); \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) \
do { \
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
} while (0)
#define SLIST_SWAP(head1, head2, type) \
do { \
struct type *swap_first = SLIST_FIRST(head1); \
SLIST_FIRST(head1) = SLIST_FIRST(head2); \
SLIST_FIRST(head2) = swap_first; \
} while (0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first; /* first element */ \
struct type **stqh_last; /* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ \
NULL, &(head).stqh_first \
}
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_CONCAT(head1, head2) \
do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_FOREACH(var, head, field) \
for ((var) = STAILQ_FIRST((head)); (var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); (var) = (tvar))
#define STAILQ_INIT(head) \
do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) \
do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) \
== NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_NEXT((tqelm), field) = (elm); \
} while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) \
do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) \
== NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_FIRST((head)) = (elm); \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) \
do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
/* Try to map FreeBSD implementation to OpenBSD one. */
#define STAILQ_HEAD(name, type) SIMPLEQ_HEAD(name, type)
#define STAILQ_HEAD_INITIALIZER(head) SIMPLEQ_HEAD_INITIALIZER(head)
#define STAILQ_ENTRY(entry) SIMPLEQ_ENTRY(entry)
#define STAILQ_CONCAT(head1, head2) SIMPLEQ_CONCAT(head1, head2)
#define STAILQ_EMPTY(head) SIMPLEQ_EMPTY(head)
#define STAILQ_FIRST(head) SIMPLEQ_FIRST(head)
#define STAILQ_FOREACH(var, head, field) SIMPLEQ_FOREACH(var, head, field)
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) SIMPLEQ_FOREACH_SAFE(var, head, field, tvar)
#define STAILQ_INIT(head) SIMPLEQ_INIT(head)
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) SIMPLEQ_INSERT_AFTER(head, tqelm, elm, field)
#define STAILQ_INSERT_HEAD(head, elm, field) SIMPLEQ_INSERT_HEAD(head, elm, field)
#define STAILQ_INSERT_TAIL(head, elm, field) SIMPLEQ_INSERT_TAIL(head, elm, field)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) \
(SIMPLEQ_EMPTY((head)) \
? NULL \
: ((struct type *)(void *)((char *)((head)->stqh_last) \
- __offsetof(struct type, \
: ((struct type *)(void *)((char *)((head)->sqh_last) \
- offsetof(struct type, \
field))))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_NEXT(elm, field) SIMPLEQ_NEXT(elm, field)
#define STAILQ_REMOVE(head, elm, type, field) \
do { \
QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
if (SIMPLEQ_FIRST((head)) == (elm)) { \
SIMPLEQ_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = STAILQ_FIRST((head)); \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \
struct type *curelm = SIMPLEQ_FIRST((head)); \
while (SIMPLEQ_NEXT(curelm, field) != (elm)) \
curelm = SIMPLEQ_NEXT(curelm, field); \
SIMPLEQ_REMOVE_AFTER(head, curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)
#define STAILQ_REMOVE_AFTER(head, elm, field) \
do { \
if ((STAILQ_NEXT(elm, field) = \
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) \
== NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) \
do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) \
== NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_REMOVE_AFTER(head, elm, field) SIMPLEQ_REMOVE_AFTER(head, elm, field)
#define STAILQ_REMOVE_HEAD(head, field) SIMPLEQ_REMOVE_HEAD(head, field)
#define STAILQ_SWAP(head1, head2, type) \
do { \
struct type *swap_first = STAILQ_FIRST(head1); \
struct type **swap_last = (head1)->stqh_last; \
struct type **swap_last = (head1)->sqh_last; \
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
(head1)->stqh_last = (head2)->stqh_last; \
(head1)->sqh_last = (head2)->sqh_last; \
STAILQ_FIRST(head2) = swap_first; \
(head2)->stqh_last = swap_last; \
(head2)->sqh_last = swap_last; \
if (STAILQ_EMPTY(head1)) \
(head1)->stqh_last = &STAILQ_FIRST(head1); \
(head1)->sqh_last = &STAILQ_FIRST(head1); \
if (STAILQ_EMPTY(head2)) \
(head2)->stqh_last = &STAILQ_FIRST(head2); \
} while (0)
/*
* List declarations.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ \
NULL \
}
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_LIST_CHECK_HEAD(head, field) \
do { \
if (LIST_FIRST((head)) != NULL \
&& LIST_FIRST((head))->field.le_prev \
!= &LIST_FIRST((head))) \
panic("Bad list head %p first->prev != head", (head)); \
} while (0)
#define QMD_LIST_CHECK_NEXT(elm, field) \
do { \
if (LIST_NEXT((elm), field) != NULL \
&& LIST_NEXT((elm), field)->field.le_prev \
!= &((elm)->field.le_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_LIST_CHECK_PREV(elm, field) \
do { \
if (*(elm)->field.le_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
(head2)->sqh_last = &STAILQ_FIRST(head2); \
} while (0)
#else
#define QMD_LIST_CHECK_HEAD(head, field)
#define QMD_LIST_CHECK_NEXT(elm, field)
#define QMD_LIST_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#include "freebsd-queue.h"
#endif /* defined(__OpenBSD__) && !defined(STAILQ_HEAD) */
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_FOREACH(var, head, field) \
for ((var) = LIST_FIRST((head)); (var); (var) = LIST_NEXT((var), field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); (var) = (tvar))
#define LIST_INIT(head) \
do { \
LIST_FIRST((head)) = NULL; \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) \
do { \
QMD_LIST_CHECK_NEXT(listelm, field); \
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) \
!= NULL) \
LIST_NEXT((listelm), field)->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_NEXT((listelm), field) = (elm); \
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) \
do { \
QMD_LIST_CHECK_PREV(listelm, field); \
(elm)->field.le_prev = (listelm)->field.le_prev; \
LIST_NEXT((elm), field) = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) \
do { \
QMD_LIST_CHECK_HEAD((head), field); \
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
LIST_FIRST((head))->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_FIRST((head)) = (elm); \
(elm)->field.le_prev = &LIST_FIRST((head)); \
} while (0)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_REMOVE(elm, field) \
do { \
QMD_SAVELINK(oldnext, (elm)->field.le_next); \
QMD_SAVELINK(oldprev, (elm)->field.le_prev); \
QMD_LIST_CHECK_NEXT(elm, field); \
QMD_LIST_CHECK_PREV(elm, field); \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
TRASHIT(*oldnext); \
TRASHIT(*oldprev); \
} while (0)
#define LIST_SWAP(head1, head2, type, field) \
do { \
struct type *swap_tmp = LIST_FIRST((head1)); \
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
LIST_FIRST((head2)) = swap_tmp; \
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
} while (0)
/*
* Tail queue declarations.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ \
NULL, &(head).tqh_first \
}
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
/*
* Tail queue functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_TAILQ_CHECK_HEAD(head, field) \
do { \
if (!TAILQ_EMPTY(head) \
&& TAILQ_FIRST((head))->field.tqe_prev \
!= &TAILQ_FIRST((head))) \
panic("Bad tailq head %p first->prev != head", \
(head)); \
} while (0)
#define QMD_TAILQ_CHECK_TAIL(head, field) \
do { \
if (*(head)->tqh_last != NULL) \
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
} while (0)
#define QMD_TAILQ_CHECK_NEXT(elm, field) \
do { \
if (TAILQ_NEXT((elm), field) != NULL \
&& TAILQ_NEXT((elm), field)->field.tqe_prev \
!= &((elm)->field.tqe_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_TAILQ_CHECK_PREV(elm, field) \
do { \
if (*(elm)->field.tqe_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_TAILQ_CHECK_HEAD(head, field)
#define QMD_TAILQ_CHECK_TAIL(head, headname)
#define QMD_TAILQ_CHECK_NEXT(elm, field)
#define QMD_TAILQ_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define TAILQ_CONCAT(head1, head2, field) \
do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = \
(head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
QMD_TRACE_HEAD(head1); \
QMD_TRACE_HEAD(head2); \
} \
} while (0)
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); (var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); (var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = TAILQ_LAST((head), headname); (var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST((head), headname); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_INIT(head) \
do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) \
do { \
QMD_TAILQ_CHECK_NEXT(listelm, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) \
!= NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) \
do { \
QMD_TAILQ_CHECK_PREV(listelm, field); \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) \
do { \
QMD_TAILQ_CHECK_HEAD(head, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) \
do { \
QMD_TAILQ_CHECK_TAIL(head, field); \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_REMOVE(head, elm, field) \
do { \
QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
QMD_TAILQ_CHECK_NEXT(elm, field); \
QMD_TAILQ_CHECK_PREV(elm, field); \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
QMD_TRACE_HEAD(head); \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
TRASHIT(*oldnext); \
TRASHIT(*oldprev); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_SWAP(head1, head2, type, field) \
do { \
struct type *swap_first = (head1)->tqh_first; \
struct type **swap_last = (head1)->tqh_last; \
(head1)->tqh_first = (head2)->tqh_first; \
(head1)->tqh_last = (head2)->tqh_last; \
(head2)->tqh_first = swap_first; \
(head2)->tqh_last = swap_last; \
if ((swap_first = (head1)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head1)->tqh_first; \
else \
(head1)->tqh_last = &(head1)->tqh_first; \
if ((swap_first = (head2)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head2)->tqh_first; \
else \
(head2)->tqh_last = &(head2)->tqh_first; \
} while (0)
#endif /* !_SYS_QUEUE_H_ */
#endif /* _FRR_QUEUE_H */

View File

@ -245,7 +245,7 @@ core_handler(int signo
#endif
);
/* dump memory stats on core */
log_memstats_stderr("core_handler");
log_memstats(stderr, "core_handler");
abort();
}

View File

@ -226,8 +226,9 @@ void spf_backoff_show(struct spf_backoff *backoff, struct vty *vty,
if (backoff->t_holddown) {
struct timeval remain =
thread_timer_remain(backoff->t_holddown);
vty_out(vty, "%s Still runs for %ld msec\n",
prefix, remain.tv_sec * 1000 + remain.tv_usec / 1000);
vty_out(vty, "%s Still runs for %lld msec\n",
prefix, (long long)remain.tv_sec * 1000
+ remain.tv_usec / 1000);
} else {
vty_out(vty, "%s Inactive\n", prefix);
}
@ -237,8 +238,9 @@ void spf_backoff_show(struct spf_backoff *backoff, struct vty *vty,
if (backoff->t_timetolearn) {
struct timeval remain =
thread_timer_remain(backoff->t_timetolearn);
vty_out(vty, "%s Still runs for %ld msec\n",
prefix, remain.tv_sec * 1000 + remain.tv_usec / 1000);
vty_out(vty, "%s Still runs for %lld msec\n",
prefix, (long long)remain.tv_sec * 1000
+ remain.tv_usec / 1000);
} else {
vty_out(vty, "%s Inactive\n", prefix);
}

View File

@ -85,11 +85,13 @@ pkginclude_HEADERS += \
lib/command.h \
lib/command_graph.h \
lib/command_match.h \
lib/compiler.h \
lib/csv.h \
lib/distribute.h \
lib/event_counter.h \
lib/fifo.h \
lib/filter.h \
lib/freebsd-queue.h \
lib/frr_pthread.h \
lib/frratomic.h \
lib/getopt.h \
@ -125,6 +127,7 @@ pkginclude_HEADERS += \
lib/ptm_lib.h \
lib/pw.h \
lib/qobj.h \
lib/queue.h \
lib/routemap.h \
lib/sbuf.h \
lib/sha256.h \
@ -180,6 +183,21 @@ lib_libfrrsnmp_la_SOURCES = \
lib/snmp.c \
# end
#
# ZeroMQ support
#
if ZEROMQ
lib_LTLIBRARIES += lib/libfrrzmq.la
pkginclude_HEADERS += lib/frr_zmq.h
endif
lib_libfrrzmq_la_CFLAGS = $(WERROR) $(ZEROMQ_CFLAGS)
lib_libfrrzmq_la_LDFLAGS = -version-info 0:0:0
lib_libfrrzmq_la_LIBADD = lib/libfrr.la $(ZEROMQ_LIBS)
lib_libfrrzmq_la_SOURCES = \
lib/frr_zmq.c \
#end
#
# CLI utilities
#
@ -222,7 +240,6 @@ EXTRA_DIST += \
lib/command_lex.h \
lib/command_parse.h \
lib/gitversion.pl \
lib/queue.h \
lib/route_types.pl \
lib/route_types.txt \
# end

View File

@ -31,7 +31,6 @@
DEFINE_MTYPE(LIB, ROUTE_TABLE, "Route table")
DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node")
static void route_node_delete(struct route_node *);
static void route_table_free(struct route_table *);
static int route_table_hash_cmp(const void *a, const void *b)
@ -187,23 +186,6 @@ static void set_link(struct route_node *node, struct route_node *new)
new->parent = node;
}
/* Lock node. */
struct route_node *route_lock_node(struct route_node *node)
{
node->lock++;
return node;
}
/* Unlock node. */
void route_unlock_node(struct route_node *node)
{
assert(node->lock > 0);
node->lock--;
if (node->lock == 0)
route_node_delete(node);
}
/* Find matched prefix. */
struct route_node *route_node_match(const struct route_table *table,
union prefixconstptr pu)
@ -348,7 +330,7 @@ struct route_node *route_node_get(struct route_table *const table,
}
/* Delete node from the routing table. */
static void route_node_delete(struct route_node *node)
void route_node_delete(struct route_node *node)
{
struct route_node *child;
struct route_node *parent;

View File

@ -182,7 +182,6 @@ route_table_init_with_delegate(route_table_delegate_t *);
extern route_table_delegate_t *route_table_get_default_delegate(void);
extern void route_table_finish(struct route_table *);
extern void route_unlock_node(struct route_node *node);
extern struct route_node *route_top(struct route_table *);
extern struct route_node *route_next(struct route_node *);
extern struct route_node *route_next_until(struct route_node *,
@ -193,7 +192,6 @@ extern struct route_node *route_node_lookup(const struct route_table *,
union prefixconstptr);
extern struct route_node *route_node_lookup_maynull(const struct route_table *,
union prefixconstptr);
extern struct route_node *route_lock_node(struct route_node *node);
extern struct route_node *route_node_match(const struct route_table *,
union prefixconstptr);
extern struct route_node *route_node_match_ipv4(const struct route_table *,
@ -205,6 +203,7 @@ extern unsigned long route_table_count(const struct route_table *);
extern struct route_node *route_node_create(route_table_delegate_t *,
struct route_table *);
extern void route_node_delete(struct route_node *);
extern void route_node_destroy(route_table_delegate_t *, struct route_table *,
struct route_node *);
@ -225,6 +224,23 @@ extern void route_table_iter_cleanup(route_table_iter_t *iter);
* Inline functions.
*/
/* Lock node. */
static inline struct route_node *route_lock_node(struct route_node *node)
{
(*(unsigned *)&node->lock)++;
return node;
}
/* Unlock node. */
static inline void route_unlock_node(struct route_node *node)
{
assert(node->lock > 0);
(*(unsigned *)&node->lock)--;
if (node->lock == 0)
route_node_delete(node);
}
/*
* route_table_iter_next
*

View File

@ -31,48 +31,60 @@ struct ttable_style ttable_styles[] = {
.corner = '+',
.rownums_on = false,
.indent = 1,
.border.top = '-',
.border.bottom = '-',
.border.left = '|',
.border.right = '|',
.border.top_on = true,
.border.bottom_on = true,
.border.left_on = true,
.border.right_on = true,
.cell.lpad = 1,
.cell.rpad = 1,
.cell.align = LEFT,
.cell.border.bottom = '-',
.cell.border.bottom_on = true,
.cell.border.top = '-',
.cell.border.top_on = false,
.cell.border.right = '|',
.cell.border.right_on = true,
.cell.border.left = '|',
.cell.border.left_on = false,
.border = {
.top = '-',
.bottom = '-',
.left = '|',
.right = '|',
.top_on = true,
.bottom_on = true,
.left_on = true,
.right_on = true,
},
.cell = {
.lpad = 1,
.rpad = 1,
.align = LEFT,
.border = {
.bottom = '-',
.bottom_on = true,
.top = '-',
.top_on = false,
.right = '|',
.right_on = true,
.left = '|',
.left_on = false,
},
},
}, { // blank, suitable for plaintext alignment
.corner = ' ',
.rownums_on = false,
.indent = 1,
.border.top = ' ',
.border.bottom = ' ',
.border.left = ' ',
.border.right = ' ',
.border.top_on = false,
.border.bottom_on = false,
.border.left_on = false,
.border.right_on = false,
.cell.lpad = 0,
.cell.rpad = 3,
.cell.align = LEFT,
.cell.border.bottom = ' ',
.cell.border.bottom_on = false,
.cell.border.top = ' ',
.cell.border.top_on = false,
.cell.border.right = ' ',
.cell.border.right_on = false,
.cell.border.left = ' ',
.cell.border.left_on = false,
.border = {
.top = ' ',
.bottom = ' ',
.left = ' ',
.right = ' ',
.top_on = false,
.bottom_on = false,
.left_on = false,
.right_on = false,
},
.cell = {
.lpad = 0,
.rpad = 3,
.align = LEFT,
.border = {
.bottom = ' ',
.bottom_on = false,
.top = ' ',
.top_on = false,
.right = ' ',
.right_on = false,
.left = ' ',
.left_on = false,
},
}
}
};
/* clang-format on */

Some files were not shown because too many files have changed in this diff Show More