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 =
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
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);
/* 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 {
{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;
-
- 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));
-
- /* 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_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;
+ struct zapi_route api;
- if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
- babel_ipv6_route_add(&api, &prefix, ifindex, &nexthop);
- else
- babel_ipv6_route_delete(&api, &prefix, ifindex);
+ if (zapi_route_decode(zclient->ibuf, &api) < 0)
+ return -1;
- return 0;
-}
+ /* we completely ignore srcdest routes for now. */
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
+ 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;
#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)
{
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
/* 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);
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)
unsigned int newmetric)
{
int rc;
- int ipv4;
+ int family;
/* Check that the protocol family is consistent. */
if(plen >= 96 && v4mapped(pref)) {
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;
}
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 */
- /* convert to be understandable by quagga */
- /* convert given addresses */
- uchar_to_inaddr(&babel_prefix_addr, pref);
- uchar_to_inaddr(&nexthop.gate.ipv4, gate);
-
- /* 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 */
- 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;
-
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
- if(metric >= KERNEL_INFINITY) {
- api.flags = ZEBRA_FLAG_REJECT;
- api.nexthop_num = 0;
- } else {
- 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;
- }
- 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;
+ api_nh = &api.nexthops[0];
/* convert to be understandable by quagga */
/* convert given addresses */
- uchar_to_in6addr(&babel_prefix_addr, pref);
- uchar_to_in6addr(&nexthop.gate.ipv6, 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_INET6;
- IPV6_ADDR_COPY (&quagga_prefix.u.prefix6, &babel_prefix_addr);
- quagga_prefix.prefixlen = plen;
+ 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;
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;
+ 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 (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
} 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.",
/* 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);
- return 0;
-}
-
-/* Remove redistributed route from Babel table. */
-int
-babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
- unsigned int ifindex)
-{
- 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);
+ 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;
-}
-/* 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)
+babel_route_delete (struct zapi_route *api)
{
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);
+ 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;
}
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);
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
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");
{
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);
/* 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);
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);
}
*/
#include <zebra.h>
+#include <math.h>
#include "prefix.h"
#include "linklist.h"
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;
bgp->main_peers_update_hold = 0;
bgp_start_routeadv(bgp);
- return WQ_SUCCESS;
+ return;
}
/* Best path selection. */
/* 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)
} 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
}
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
bgp_info_reap(rn, old_select);
UNSET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
- return WQ_SUCCESS;
+ return;
}
-static void bgp_processq_del(struct work_queue *wq, void *data)
+static wq_item_status bgp_process_wq(struct work_queue *wq, void *data)
{
- struct bgp_process_queue *pq = 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(pq->bgp);
- if (pq->rn) {
- table = bgp_node_table(pq->rn);
- bgp_unlock_node(pq->rn);
+ bgp_unlock_node(rn);
bgp_table_unlock(table);
}
- XFREE(MTYPE_BGP_PROCESS_QUEUE, pq);
+
+ return WQ_SUCCESS;
+}
+
+static void bgp_processq_del(struct work_queue *wq, void *data)
+{
+ struct bgp_process_queue *pqnode = data;
+
+ bgp_unlock(pqnode->bgp);
+
+ XFREE(MTYPE_BGP_PROCESS_QUEUE, pqnode);
}
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;
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;
}
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)
/* 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)
{
/* 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);
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,
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"
"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;
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);
}
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)) {
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);
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;
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;
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;
}
struct bgp_table_stats {
struct bgp_table *table;
unsigned long long counts[BGP_STATS_MAX];
+ double total_space;
};
#if 0
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]++;
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]);
/* 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);
#define _QUAGGA_BGP_ROUTE_H
#include "queue.h"
+#include "nexthop.h"
#include "bgp_table.h"
struct bgp_nexthop_cache;
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);
#include "mpls.h"
#include "table.h"
+#include "queue.h"
struct bgp_table {
/* afi/safi of this table */
struct bgp_node *prn;
+ STAILQ_ENTRY(bgp_node) pq;
+
mpls_label_t local_label;
uint64_t version;
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"
"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
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)
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) {
/*
/* 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.
}
/* 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;
-
- /* Type, flags, message. */
- api.type = stream_getc(s);
- api.instance = stream_getw(s);
- api.flags = stream_getl(s);
- api.message = stream_getc(s);
-
- /* 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));
-
- /* 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 (zapi_route_decode(zclient->ibuf, &api) < 0)
+ return -1;
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
- api.metric = stream_getl(s);
- else
- api.metric = 0;
+ /* we completely ignore srcdest routes for now. */
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
+ return 0;
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG))
- api.tag = stream_getl(s);
- else
- api.tag = 0;
+ /* ignore link-local address. */
+ if (api.prefix.family == AF_INET6
+ && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
+ return 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
*/
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 (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);
+ if (bgp_debug_zebra(&api.prefix)) {
+ char buf[2][PREFIX_STRLEN];
+
+ 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;
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;
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;
* 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);
-
- 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;
+ SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
- /* resize nexthop buffer size if necessary */
- stream_reset(bgp_nexthop_buf);
- nexthop = NULL;
+ /* 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;
- stream_reset(bgp_label_buf);
+ if (bgp->table_map[afi][safi].name)
+ BGP_INFO_ATTR_BUF_INIT();
- 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)) {
+ if (nh_family == AF_INET) {
+ struct in_addr *nexthop;
- /* 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) {
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;
}
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;
-
- 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);
- }
+ ifindex_t ifindex;
+ struct in6_addr *nexthop;
- /* 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;
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 (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;
- }
- SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
- api.metric = metric;
- api.tag = 0;
+ if (mpinfo->extra
+ && bgp_is_valid_label(&mpinfo->extra->label)) {
+ has_valid_label = 1;
+ label = label_pton(&mpinfo->extra->label);
- if (tag) {
- SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
- api.tag = tag;
+ api_nh->label_num = 1;
+ api_nh->labels[0] = label;
}
+ valid_nh_count++;
+ }
- distance = bgp_distance_apply(p, info, afi, safi, bgp);
- if (distance) {
- SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
- api.distance = distance;
- }
+ if (has_valid_label)
+ SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
- 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);
- }
- }
+ if (!CHECK_FLAG(api.flags, ZEBRA_FLAG_BLACKHOLE))
+ api.nexthop_num = valid_nh_count;
- 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);
- }
- }
+ SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
+ api.metric = metric;
+
+ 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;
+ }
- zapi_ipv6_route(
- valid_nh_count ? ZEBRA_IPV6_ROUTE_ADD
- : ZEBRA_IPV6_ROUTE_DELETE,
- zclient, (struct prefix_ipv6 *)p, NULL, &api);
+ 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 */
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;
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);
-
- if (p->family == AF_INET) {
- struct zapi_ipv4 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.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;
- }
+ SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
- 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);
- }
+ if (bgp_debug_zebra(p)) {
+ char buf[PREFIX_STRLEN];
- 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,
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;
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);
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. */
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.
*/
{
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);
}
}
}
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)
{
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)) {
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;
}
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])
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;
}
* 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))
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;
/* 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
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);
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);
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)
{
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. */
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:
* 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;
/*
* 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;
*
* 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;
-
- s = zclient->ibuf;
- nexthop.s_addr = 0;
-
- /* 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);
- }
+ struct zapi_route api;
+ int add;
- return 0;
-}
+ if (zapi_route_decode(zclient->ibuf, &api) < 0)
+ return -1;
-/* 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);
- else
- api.distance = 0;
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
- api.metric = stream_getl(s);
+ add = (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD);
+ if (add)
+ vnc_redistribute_add(&api.prefix, api.metric, api.type);
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;
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)) {
+ if (BGP_DEBUG(zebra, ZEBRA)) {
+ char buf[PREFIX_STRLEN];
- 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 {
+ prefix2str(&api.prefix, buf, sizeof(buf));
vnc_zlog_debug_verbose(
- "%s: unknown prefix address family, skipping",
- __func__);
- return;
+ "%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);
}
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)
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:
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])
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,
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,
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
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])
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
)
], [], 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 ----------
--- /dev/null
+/_templates
+/_build
+!/Makefile
--- /dev/null
+# 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."
--- /dev/null
+# -*- 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
--- /dev/null
+.. 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.
--- /dev/null
+Welcome to FRR's documentation!
+===============================
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+ library
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
--- /dev/null
+libfrr library facilities
+=========================
+
+.. toctree::
+ :maxdepth: 2
+
+ memtypes
+ hooks
+
+
--- /dev/null
+.. 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.
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);
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);
}
-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;
* 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;
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;
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)
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) {
* 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);
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;
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);
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;
{
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);
}
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);
{
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;
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);
}
{
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
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;
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;
#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 */
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
*
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);
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)
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) {
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) {
#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 *);
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)
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);
/*Add connected entry to topology table*/
- struct prefix_ipv4 dest_addr;
+ 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->adv_router = eigrp->neighbor_self;
+ ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
+
+ struct prefix dest_addr;
dest_addr.family = AF_INET;
- dest_addr.prefix = ei->connected->address->u.prefix4;
+ dest_addr.u.prefix4 = ei->connected->address->u.prefix4;
dest_addr.prefixlen = ei->connected->address->prefixlen;
- apply_mask_ipv4(&dest_addr);
+ 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_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->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);
- }
- 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) {
+ 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;
}
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();
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)
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;
continue;
if (prefix_match(CONNECTED_PREFIX(ei->connected),
- (struct prefix *)&addr)) {
+ &addr)) {
if ((match == NULL) || (match->address->prefixlen
< ei->address->prefixlen))
match = ei;
}
}
+ eigrp_sw_version_initialize();
+
/* EIGRP master init. */
eigrp_master_init();
eigrp_om->master = frr_init();
/* 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);
+}
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 */
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;
return 0;
}
- struct prefix_ipv4 *pref = prefix_ipv4_new();
+ struct prefix *pref = prefix_new();
PREFIX_COPY_IPV4(pref, p);
rn->info = (void *)pref;
/* 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;
}
}
}
-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);
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 *);
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);
struct msghdr msg;
struct iovec iov[2];
u_int16_t opcode = 0;
+ u_int32_t seqno, ack;
int ret;
int flags = 0;
#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);
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);
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);
}
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);
}
/* 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",
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_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);
- }
+ 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);
+
+ 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);
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;
}
{
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,
}
/* 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)
{
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));
}
/* 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;
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;
}
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)
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)
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)
}
/* 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;
{
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;
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;
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;
}
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);
- 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);
+ (pe->destination->u.prefix4.s_addr >> 16) & 0xFF);
+ if (pe->destination->prefixlen > 24)
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;
}
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)
{
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 *);
* 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 *);
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);
{
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++;
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(
/* 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);
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
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) {
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
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);
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(
*/
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);
* 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);
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(
/* 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);
}
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
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);
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(
/* 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);
}
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
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);
/* EIGRP packet length. */
u_int16_t length;
+
+ struct eigrp_neighbor *nbr;
};
struct eigrp_fifo {
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
};
//---------------------------------------------------------------------------------------------------------------------------------------------
+typedef enum {
+ EIGRP_CONNECTED,
+ EIGRP_INT,
+ EIGRP_EXT,
+} msg_data_t;
/* EIGRP Finite State Machine */
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_ */
{
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;
}
/*
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;
}
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;
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);
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);
}
}
{
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);
}
}
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;
}
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
*/
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;
}
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);
}
}
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,
{
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);
-
- /* 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;
- /* 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;
-
+ char buffer[PREFIX_STRLEN];
+ zlog_debug("GR receive: Neighbor not advertised %s",
+ prefix2str(prefix->destination,
+ buffer, PREFIX_STRLEN));
- /* 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 = prefix->reported_metric;
+ /* set delay to MAX */
+ 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);
}
}
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;
/*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(
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;
/* 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 =
/* 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 =
/* 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 =
/* 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 =
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);
+ }
}
}
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))
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)
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);
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)
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) &&
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) &&
}
}
/* Get destination address from prefix */
- dest_addr = pe->destination_ipv4;
+ dest_addr = pe->destination;
/*
* Filtering
/* 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 {
}
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;
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)
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;
}
}
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,
pe->req_action &= ~EIGRP_FSM_NEED_UPDATE;
listnode_delete(eigrp->topology_changes_internalIPV4,
pe);
- zlog_debug("UPDATE COUNT: %d",
- eigrp->topology_changes_internalIPV4->count);
}
}
}
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;
}
}
- 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);
/*
* 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
/* 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);
/* 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
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);
"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);
"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);
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;
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;
-
- /* 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 (zapi_route_decode(zclient->ibuf, &api) < 0)
+ return -1;
- 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) */
{
}
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;
-
- if (zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP]) {
- message = 0;
- flags = 0;
-
- /* EIGRP pass nexthop and metric */
- SET_FLAG(message, ZAPI_MESSAGE_NEXTHOP);
-
- /* Make packet. */
- s = zclient->obuf;
- stream_reset(s);
-
- /* 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);
-
- /* 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));
+ int count = 0;
+
+ if (!zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP])
+ return;
+
+ 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));
+
+ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+ api.nexthop_num = successors->count;
+
+ /* 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;
+
+ count++;
+ }
- zclient_send_message(zclient);
+ 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;
-
- 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 (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])));
- }
+ struct zapi_route api;
+
+ if (!zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP])
+ return;
+
+ 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;
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);
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()
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()
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')
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;
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));
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 "
/*
* 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 */
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);
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);
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
&& 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);
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;
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;
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;
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;
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;
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;
"Invalid metric %d - should be <0-63> "
"when narrow metric type enabled\n",
met);
- return CMD_ERR_AMBIGUOUS;
+ return CMD_WARNING_CONFIG_FAILED;
}
/* RFC4444 */
"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);
"Invalid metric %d - should be <0-63> "
"when narrow metric type enabled\n",
met);
- return CMD_ERR_AMBIGUOUS;
+ return CMD_WARNING_CONFIG_FAILED;
}
/* RFC4444 */
"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);
"Invalid metric %d - should be <0-63> "
"when narrow metric type enabled\n",
met);
- return CMD_ERR_AMBIGUOUS;
+ return CMD_WARNING_CONFIG_FAILED;
}
/* RFC4444 */
"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);
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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);
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);
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)) {
&& (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;
}
}
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);
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);
"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;
}
}
"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;
}
}
"the configured LSP gen interval %us\n",
refresh_interval,
area->lsp_gen_interval[lvl - 1]);
- return CMD_ERR_AMBIGUOUS;
+ return CMD_WARNING_CONFIG_FAILED;
}
}
}
"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;
}
}
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);
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.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_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);
+ 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;
- XFREE(MTYPE_ISIS_TMP, nexthop_list);
- XFREE(MTYPE_ISIS_TMP, ifindex_list);
+ api.nexthop_num = count;
- 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);
-
- /* 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;
- }
+ api.prefix = *prefix;
- 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,
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));
-
- stream = zclient->ibuf;
- memset(&api, 0, sizeof(api));
- memset(&p, 0, sizeof(struct prefix_ipv6));
- memset(&nexthop, 0, sizeof(nexthop));
- ifindex = 0;
-
- 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));
- }
+ struct zapi_route api;
- if (src_p.prefixlen)
- /* we completely ignore srcdest routes for now. */
- return 0;
+ if (zapi_route_decode(zclient->ibuf, &api) < 0)
+ return -1;
- 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);
+ /* we completely ignore srcdest routes for now. */
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
+ return 0;
/*
* Avoid advertising a false default reachability. (A default
* 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;
}
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;
}
"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) {
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 */
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);
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;
}
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");
(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);
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);
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);
#include "vty.h"
-#define ISISD_VERSION "0.0.7"
-
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
#include "isisd/isis_redist.h"
#ifndef _CONTROL_H_
#define _CONTROL_H_
-#include "openbsd-queue.h"
+#include "queue.h"
struct ctl_conn {
TAILQ_ENTRY(ctl_conn) entry;
#ifndef _LDE_H_
#define _LDE_H_
-#include "openbsd-queue.h"
+#include "queue.h"
#include "openbsd-tree.h"
#include "if.h"
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));
}
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;
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,
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;
}
pid_t pid;
int status;
+ frr_early_fini();
+
/* close pipes */
msgbuf_clear(&iev_ldpe->ibuf.w);
close(iev_ldpe->ibuf.fd);
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);
}
#ifndef _LDPD_H_
#define _LDPD_H_
-#include "openbsd-queue.h"
+#include "queue.h"
#include "openbsd-tree.h"
#include "imsg.h"
#include "thread.h"
#ifndef _LDPE_H_
#define _LDPE_H_
-#include "openbsd-queue.h"
+#include "queue.h"
#include "openbsd-tree.h"
#ifdef __OpenBSD__
#include <net/pfkeyv2.h>
#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")
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;
}
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;
}
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;
}
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;
/* 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);
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);
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);
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);
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);
// input, with each cmd_token->arg holding the corresponding
// input
assert(*el);
+ } else if (*argv) {
+ del_arglist(*argv);
+ *argv = NULL;
}
if (!*el) {
// free vector
vector_free(vvline);
- return matcher_rv;
+ return status;
}
/**
*
* 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);
* 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);
// if we don't match this node, die
if (match_token(token, input_token) < minmatch)
- return NULL;
+ return MATCHER_NO_MATCH;
stack[n] = start;
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)
* 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)) {
list_delete(current);
list_delete(next);
- return matcher_rv;
+ return mrv;
}
/**
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*-
+ * 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_ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
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);
/* 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;
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)
* 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:
void *hookfn; /* actually a function pointer */
void *hookarg;
bool has_arg;
+ int priority;
struct frrmod_runtime *module;
const char *fnname;
};
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
*/
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);
{ \
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 \
{ \
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 */
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
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;
}
/* 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 */
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)
{
#include "linklist.h"
#include "memory.h"
#include "qobj.h"
+#include "hook.h"
DECLARE_MTYPE(IF)
DECLARE_MTYPE(CONNECTED_LABEL)
};
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. */
? (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. */
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 **);
#include <zebra.h>
-#include "openbsd-queue.h"
+#include "queue.h"
#include "imsg.h"
int ibuf_realloc(struct ibuf *, size_t);
#include <zebra.h>
-#include "openbsd-queue.h"
+#include "queue.h"
#include "imsg.h"
int imsg_fd_overhead = 0;
#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;
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];
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))
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);
+ }
+}
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[];
extern char frr_protoname[];
extern char frr_protonameinst[];
+extern bool debug_memstats_at_exit;
+
#endif /* _ZEBRA_FRR_H */
assertion, file, line, (function ? function : "?"));
zlog_backtrace(LOG_CRIT);
zlog_thread_info(LOG_CRIT);
- log_memstats_stderr("log");
+ log_memstats(stderr, "log");
abort();
}
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),
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),
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),
}
struct exit_dump_args {
+ FILE *fp;
const char *prefix;
int error;
};
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);
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;
}
#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]))
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
* 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);
.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)
#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)
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)
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 *);
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,
* padding and unused prefix bytes. */
memset(©, 0, sizeof(copy));
prefix_copy(©, (struct prefix *)pp);
- return jhash(©, sizeof(copy), 0x55aa5a5a);
+ return jhash(©, offsetof(struct prefix, u.prefix)
+ + PSIZE(copy.prefixlen), 0x55aa5a5a);
}
#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
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)));
#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)
}
#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)) {
-/*-
- * 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.
+ * 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.
*
- * 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.
+ * 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
*/
-#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)
+#ifndef _FRR_QUEUE_H
+#define _FRR_QUEUE_H
+
+#if defined(__OpenBSD__) && !defined(STAILQ_HEAD)
+#include "openbsd-queue.h"
+
+/* 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) */
-
-#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)
+#include "freebsd-queue.h"
+#endif /* defined(__OpenBSD__) && !defined(STAILQ_HEAD) */
-#endif /* !_SYS_QUEUE_H_ */
+#endif /* _FRR_QUEUE_H */
#endif
);
/* dump memory stats on core */
- log_memstats_stderr("core_handler");
+ log_memstats(stderr, "core_handler");
abort();
}
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);
}
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);
}
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 \
lib/ptm_lib.h \
lib/pw.h \
lib/qobj.h \
+ lib/queue.h \
lib/routemap.h \
lib/sbuf.h \
lib/sha256.h \
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
#
lib/command_lex.h \
lib/command_parse.h \
lib/gitversion.pl \
- lib/queue.h \
lib/route_types.pl \
lib/route_types.txt \
# end
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)
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)
}
/* 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;
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 *,
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 *,
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 *);
* 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
*
.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 */
#include "log.h"
#include "sockunion.h"
#include "qobj.h"
+#include "compiler.h"
#define VTY_BUFSIZ 4096
#define VTY_MAXHIST 20
/* Integrated configuration file. */
#define INTEGRATE_DEFAULT_CONFIG "frr.conf"
-/* 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)
+#if CONFDATE > 20180401
+CPP_NOTICE("It's probably time to remove VTY_NEWLINE compatibility foo.")
#endif
+/* for compatibility */
#define VNL "\n" CPP_WARN("VNL has been replaced with \\n.")
#define VTYNL "\n" CPP_WARN("VTYNL has been replaced with \\n.")
#define VTY_NEWLINE "\n" CPP_WARN("VTY_NEWLINE has been replaced with \\n.")
new->master = m;
SET_FLAG(new->flags, WQ_UNPLUGGED);
- if ((new->items = list_new()) == NULL) {
- XFREE(MTYPE_WORK_QUEUE_NAME, new->name);
- XFREE(MTYPE_WORK_QUEUE, new);
-
- return NULL;
- }
-
- new->items->del = (void (*)(void *))work_queue_item_free;
+ STAILQ_INIT(&new->items);
listnode_add(work_queues, new);
if (wq->thread != NULL)
thread_cancel(wq->thread);
- /* list_delete frees items via callback */
- list_delete(wq->items);
listnode_delete(work_queues, wq);
XFREE(MTYPE_WORK_QUEUE_NAME, wq->name);
static int work_queue_schedule(struct work_queue *wq, unsigned int delay)
{
/* if appropriate, schedule work queue thread */
- if (CHECK_FLAG(wq->flags, WQ_UNPLUGGED) && (wq->thread == NULL)
- && (listcount(wq->items) > 0)) {
+ if (CHECK_FLAG(wq->flags, WQ_UNPLUGGED) && (wq->thread == NULL) &&
+ !work_queue_empty(wq)) {
wq->thread = NULL;
thread_add_timer_msec(wq->master, work_queue_run, wq, delay,
&wq->thread);
}
item->data = data;
- listnode_add(wq->items, item);
+ work_queue_item_enqueue(wq, item);
work_queue_schedule(wq, wq->spec.hold);
return;
}
-static void work_queue_item_remove(struct work_queue *wq, struct listnode *ln)
+static void work_queue_item_remove(struct work_queue *wq,
+ struct work_queue_item *item)
{
- struct work_queue_item *item = listgetdata(ln);
-
assert(item && item->data);
/* call private data deletion callback if needed */
if (wq->spec.del_item_data)
wq->spec.del_item_data(wq, item->data);
- list_delete_node(wq->items, ln);
+ work_queue_item_dequeue(wq, item);
+
work_queue_item_free(item);
return;
}
-static void work_queue_item_requeue(struct work_queue *wq, struct listnode *ln)
+static void work_queue_item_requeue(struct work_queue *wq, struct work_queue_item *item)
{
- LISTNODE_DETACH(wq->items, ln);
- LISTNODE_ATTACH(wq->items, ln); /* attach to end of list */
+ work_queue_item_dequeue(wq, item);
+
+ /* attach to end of list */
+ work_queue_item_enqueue(wq, item);
}
DEFUN (show_work_queues,
for (ALL_LIST_ELEMENTS_RO(work_queues, node, wq)) {
vty_out(vty, "%c %8d %5d %8ld %8ld %7d %6d %8ld %6u %s\n",
(CHECK_FLAG(wq->flags, WQ_UNPLUGGED) ? ' ' : 'P'),
- listcount(wq->items), wq->spec.hold, wq->runs,
+ work_queue_item_count(wq), wq->spec.hold, wq->runs,
wq->yields, wq->cycles.best, wq->cycles.granularity,
wq->cycles.total,
(wq->runs) ? (unsigned int)(wq->cycles.total / wq->runs)
int work_queue_run(struct thread *thread)
{
struct work_queue *wq;
- struct work_queue_item *item;
+ struct work_queue_item *item, *titem;
wq_item_status ret;
unsigned int cycles = 0;
- struct listnode *node, *nnode;
char yielded = 0;
wq = THREAD_ARG(thread);
wq->thread = NULL;
- assert(wq && wq->items);
+ assert(wq);
/* calculate cycle granularity:
* list iteration == 1 run
if (wq->cycles.granularity == 0)
wq->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY;
- for (ALL_LIST_ELEMENTS(wq->items, node, nnode, item)) {
+ STAILQ_FOREACH_SAFE(item, &wq->items, wq, titem) {
assert(item && item->data);
/* dont run items which are past their allowed retries */
/* run error handler, if any */
if (wq->spec.errorfunc)
wq->spec.errorfunc(wq, item->data);
- work_queue_item_remove(wq, node);
+ work_queue_item_remove(wq, item);
continue;
}
}
case WQ_REQUEUE: {
item->ran--;
- work_queue_item_requeue(wq, node);
+ work_queue_item_requeue(wq, item);
/* If a single node is being used with a meta-queue
* (e.g., zebra),
* update the next node as we don't want to exit the
* will kick in
* to terminate the thread when time has exceeded.
*/
- if (nnode == NULL)
- nnode = node;
+ if (titem == NULL)
+ titem = item;
break;
}
case WQ_RETRY_NOW:
/* fallthru */
case WQ_SUCCESS:
default: {
- work_queue_item_remove(wq, node);
+ work_queue_item_remove(wq, item);
break;
}
}
#endif
/* Is the queue done yet? If it is, call the completion callback. */
- if (listcount(wq->items) > 0)
+ if (!work_queue_empty(wq))
work_queue_schedule(wq, 0);
else if (wq->spec.completion_func)
wq->spec.completion_func(wq);
#define _QUAGGA_WORK_QUEUE_H
#include "memory.h"
+#include "queue.h"
DECLARE_MTYPE(WORK_QUEUE)
/* Hold time for the initial schedule of a queue run, in millisec */
/* A single work queue item, unsurprisingly */
struct work_queue_item {
+ STAILQ_ENTRY(work_queue_item) wq;
void *data; /* opaque data */
unsigned short ran; /* # of times item has been run */
};
} spec;
/* remaining fields should be opaque to users */
- struct list *items; /* queue item list */
+ STAILQ_HEAD(work_queue_items, work_queue_item) items; /* queue item list */
+ int item_count; /* queued items */
unsigned long runs; /* runs count */
unsigned long yields; /* yields count */
/* User API */
+static inline int work_queue_item_count(struct work_queue *wq)
+{
+ return wq->item_count;
+}
+
+static inline bool work_queue_empty(struct work_queue *wq)
+{
+ return (wq->item_count == 0) ? true : false;
+}
+
+static inline struct work_queue_item *work_queue_last_item(struct work_queue *wq)
+{
+ return STAILQ_LAST(&wq->items, work_queue_item, wq);
+}
+
+static inline void work_queue_item_enqueue(struct work_queue *wq,
+ struct work_queue_item *item)
+{
+ STAILQ_INSERT_TAIL(&wq->items, item, wq);
+ wq->item_count++;
+}
+
+static inline void work_queue_item_dequeue(struct work_queue *wq,
+ struct work_queue_item *item)
+{
+ assert(wq->item_count > 0);
+
+ wq->item_count--;
+ STAILQ_REMOVE(&wq->items, item, work_queue_item, wq);
+}
+
/* create a new work queue, of given name.
* user must fill in the spec of the returned work queue before adding
* anything to it
int i;
afi_t afi;
- /* zclient is disabled. */
- if (!zclient->enable)
- return;
-
/* If not connected to the zebra yet. */
if (zclient->sock < 0)
return;
int i;
afi_t afi;
- /* zclient is disabled. */
- if (!zclient->enable)
- return;
-
/* If not connected to the zebra yet. */
if (zclient->sock < 0)
return;
{
struct stream *s;
- /* zclient is disabled. */
- if (!zclient->enable)
- return;
-
/* If not connected to the zebra yet. */
if (zclient->sock < 0)
return;
if (zclient_debug)
zlog_info("zclient_start is called");
- /* zclient is disabled. */
- if (!zclient->enable)
- return 0;
-
/* If already connected to the zebra. */
if (zclient->sock >= 0)
return 0;
{
int afi, i;
- /* Enable zebra client connection by default. */
- zclient->enable = 1;
-
/* Set -1 to the default socket value. */
zclient->sock = -1;
return zclient_send_message(zclient);
}
-int zapi_route(u_char cmd, struct zclient *zclient, struct prefix *p,
- struct prefix_ipv6 *src_p, struct zapi_route *api)
+int zclient_route_send(u_char cmd, struct zclient *zclient,
+ struct zapi_route *api)
{
+ if (zapi_route_encode(cmd, zclient->obuf, api) < 0)
+ return -1;
+ return zclient_send_message(zclient);
+}
+
+int zapi_route_encode(u_char cmd, struct stream *s, struct zapi_route *api)
+{
+ struct zapi_nexthop *api_nh;
int i;
int psize;
- struct stream *s;
- /* either we have !SRCPFX && src_p == NULL, or SRCPFX && src_p != NULL
- */
- assert(!(api->message & ZAPI_MESSAGE_SRCPFX) == !src_p);
-
- /* Reset stream. */
- s = zclient->obuf;
stream_reset(s);
-
zclient_create_header(s, cmd, api->vrf_id);
- /* Put type and nexthop. */
stream_putc(s, api->type);
stream_putw(s, api->instance);
stream_putl(s, api->flags);
stream_putw(s, api->safi);
/* Put prefix information. */
- psize = PSIZE(p->prefixlen);
- stream_putc(s, p->prefixlen);
- stream_write(s, (u_char *)&p->u.prefix, psize);
+ stream_putc(s, api->prefix.family);
+ psize = PSIZE(api->prefix.prefixlen);
+ stream_putc(s, api->prefix.prefixlen);
+ stream_write(s, (u_char *)&api->prefix.u.prefix, psize);
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_SRCPFX)) {
- psize = PSIZE(src_p->prefixlen);
- stream_putc(s, src_p->prefixlen);
- stream_write(s, (u_char *)&src_p->prefix, psize);
+ psize = PSIZE(api->src_prefix.prefixlen);
+ stream_putc(s, api->src_prefix.prefixlen);
+ stream_write(s, (u_char *)&api->src_prefix.prefix, psize);
}
- /* Nexthop, ifindex, distance and metric information. */
+ /* Nexthops. */
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
- stream_putc(s, api->nexthop_num);
+ /* limit the number of nexthops if necessary */
+ if (api->nexthop_num > MULTIPATH_NUM) {
+ char buf[PREFIX2STR_BUFFER];
+
+ prefix2str(&api->prefix, buf, sizeof(buf));
+ zlog_warn(
+ "%s: prefix %s: encoding %u nexthops out of %u",
+ __func__, buf, MULTIPATH_NUM, api->nexthop_num);
+ api->nexthop_num = MULTIPATH_NUM;
+ }
+
+ stream_putw(s, api->nexthop_num);
for (i = 0; i < api->nexthop_num; i++) {
- stream_putc(s, api->nexthop[i]->type);
- switch (api->nexthop[i]->type) {
+ api_nh = &api->nexthops[i];
+
+ stream_putc(s, api_nh->type);
+ switch (api_nh->type) {
case NEXTHOP_TYPE_BLACKHOLE:
break;
case NEXTHOP_TYPE_IPV4:
- stream_put_in_addr(s,
- &api->nexthop[i]->gate.ipv4);
-
- /* For labeled-unicast, each nexthop is followed
- * by label. */
- if (CHECK_FLAG(api->message,
- ZAPI_MESSAGE_LABEL))
- stream_putl(
- s,
- api->nexthop[i]
- ->nh_label->label[0]);
+ stream_put_in_addr(s, &api_nh->gate.ipv4);
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
- stream_put_in_addr(s,
- &api->nexthop[i]->gate.ipv4);
- stream_putl(s, api->nexthop[i]->ifindex);
+ stream_put_in_addr(s, &api_nh->gate.ipv4);
+ stream_putl(s, api_nh->ifindex);
break;
case NEXTHOP_TYPE_IFINDEX:
- stream_putl(s, api->nexthop[i]->ifindex);
+ stream_putl(s, api_nh->ifindex);
break;
case NEXTHOP_TYPE_IPV6:
- stream_write(
- s,
- (u_char *)&api->nexthop[i]->gate.ipv6,
- 16);
-
- /* For labeled-unicast, each nexthop is followed
- * by label. */
- if (CHECK_FLAG(api->message,
- ZAPI_MESSAGE_LABEL))
- stream_putl(
- s,
- api->nexthop[i]
- ->nh_label->label[0]);
+ stream_write(s, (u_char *)&api_nh->gate.ipv6,
+ 16);
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
- stream_write(
- s,
- (u_char *)&api->nexthop[i]->gate.ipv6,
- 16);
- stream_putl(s, api->nexthop[i]->ifindex);
+ stream_write(s, (u_char *)&api_nh->gate.ipv6,
+ 16);
+ stream_putl(s, api_nh->ifindex);
break;
}
+
+ /* MPLS labels for BGP-LU or Segment Routing */
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL)) {
+ if (api_nh->label_num > MPLS_MAX_LABELS) {
+ char buf[PREFIX2STR_BUFFER];
+ prefix2str(&api->prefix, buf,
+ sizeof(buf));
+ zlog_err(
+ "%s: prefix %s: can't encode "
+ "%u labels (maximum is %u)",
+ __func__, buf,
+ api_nh->label_num,
+ MPLS_MAX_LABELS);
+ return -1;
+ }
+
+ stream_putc(s, api_nh->label_num);
+ stream_put(s, &api_nh->labels[0],
+ api_nh->label_num
+ * sizeof(mpls_label_t));
+ }
}
}
+ /* Attributes. */
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE))
stream_putc(s, api->distance);
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_METRIC))
/* Put length at the first point of the stream. */
stream_putw_at(s, 0, stream_get_endp(s));
- return zclient_send_message(zclient);
+ return 0;
+}
+
+int zapi_route_decode(struct stream *s, struct zapi_route *api)
+{
+ struct zapi_nexthop *api_nh;
+ int i;
+
+ memset(api, 0, sizeof(*api));
+
+ /* Type, flags, message. */
+ api->type = stream_getc(s);
+ api->instance = stream_getw(s);
+ api->flags = stream_getl(s);
+ api->message = stream_getc(s);
+ api->safi = stream_getw(s);
+
+ /* Prefix. */
+ api->prefix.family = stream_getc(s);
+ switch (api->prefix.family) {
+ case AF_INET:
+ api->prefix.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc(s));
+ break;
+ case AF_INET6:
+ api->prefix.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc(s));
+ break;
+ }
+ stream_get(&api->prefix.u.prefix, s, PSIZE(api->prefix.prefixlen));
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_SRCPFX)) {
+ api->src_prefix.family = AF_INET6;
+ api->src_prefix.prefixlen = stream_getc(s);
+ stream_get(&api->src_prefix.prefix, s,
+ PSIZE(api->src_prefix.prefixlen));
+
+ if (api->prefix.family != AF_INET6
+ || api->src_prefix.prefixlen == 0)
+ UNSET_FLAG(api->message, ZAPI_MESSAGE_SRCPFX);
+ }
+
+ /* Nexthops. */
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_NEXTHOP)) {
+ api->nexthop_num = stream_getw(s);
+ if (api->nexthop_num > MULTIPATH_NUM) {
+ zlog_warn("%s: invalid number of nexthops (%u)",
+ __func__, api->nexthop_num);
+ return -1;
+ }
+
+ for (i = 0; i < api->nexthop_num; i++) {
+ api_nh = &api->nexthops[i];
+
+ api_nh->type = stream_getc(s);
+ switch (api_nh->type) {
+ case NEXTHOP_TYPE_BLACKHOLE:
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ api_nh->gate.ipv4.s_addr = stream_get_ipv4(s);
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ api_nh->gate.ipv4.s_addr = stream_get_ipv4(s);
+ api_nh->ifindex = stream_getl(s);
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ api_nh->ifindex = stream_getl(s);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ stream_get(&api_nh->gate.ipv6, s, 16);
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ stream_get(&api_nh->gate.ipv6, s, 16);
+ api_nh->ifindex = stream_getl(s);
+ break;
+ }
+
+ /* MPLS labels for BGP-LU or Segment Routing */
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_LABEL)) {
+ api_nh->label_num = stream_getc(s);
+
+ if (api_nh->label_num > MPLS_MAX_LABELS) {
+ zlog_warn(
+ "%s: invalid number of MPLS "
+ "labels (%u)",
+ __func__, api_nh->label_num);
+ return -1;
+ }
+
+ stream_get(&api_nh->labels[0], s,
+ api_nh->label_num
+ * sizeof(mpls_label_t));
+ }
+ }
+ }
+
+ /* Attributes. */
+ 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);
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_TAG))
+ api->tag = stream_getl(s);
+ if (CHECK_FLAG(api->message, ZAPI_MESSAGE_MTU))
+ api->mtu = stream_getl(s);
+
+ return 0;
}
/*
(*zclient->bfd_dest_replay)(command, zclient, length,
vrf_id);
break;
- case ZEBRA_REDISTRIBUTE_IPV4_ADD:
- if (zclient->redistribute_route_ipv4_add)
- (*zclient->redistribute_route_ipv4_add)(
- command, zclient, length, vrf_id);
+ case ZEBRA_REDISTRIBUTE_ROUTE_ADD:
+ if (zclient->redistribute_route_add)
+ (*zclient->redistribute_route_add)(command, zclient,
+ length, vrf_id);
break;
- case ZEBRA_REDISTRIBUTE_IPV4_DEL:
- if (zclient->redistribute_route_ipv4_del)
- (*zclient->redistribute_route_ipv4_del)(
- command, zclient, length, vrf_id);
- break;
- case ZEBRA_REDISTRIBUTE_IPV6_ADD:
- if (zclient->redistribute_route_ipv6_add)
- (*zclient->redistribute_route_ipv6_add)(
- command, zclient, length, vrf_id);
- break;
- case ZEBRA_REDISTRIBUTE_IPV6_DEL:
- if (zclient->redistribute_route_ipv6_del)
- (*zclient->redistribute_route_ipv6_del)(
- command, zclient, length, vrf_id);
+ case ZEBRA_REDISTRIBUTE_ROUTE_DEL:
+ if (zclient->redistribute_route_del)
+ (*zclient->redistribute_route_del)(command, zclient,
+ length, vrf_id);
break;
case ZEBRA_INTERFACE_LINK_PARAMS:
if (zclient->interface_link_params)
#ifndef _ZEBRA_ZCLIENT_H
#define _ZEBRA_ZCLIENT_H
-/* For struct zapi_ipv{4,6}. */
+/* For struct zapi_route. */
#include "prefix.h"
/* For struct interface and struct connected. */
ZEBRA_INTERFACE_UP,
ZEBRA_INTERFACE_DOWN,
ZEBRA_INTERFACE_SET_MASTER,
+ ZEBRA_ROUTE_ADD,
+ ZEBRA_ROUTE_DELETE,
ZEBRA_IPV4_ROUTE_ADD,
ZEBRA_IPV4_ROUTE_DELETE,
ZEBRA_IPV6_ROUTE_ADD,
ZEBRA_BFD_DEST_DEREGISTER,
ZEBRA_BFD_DEST_UPDATE,
ZEBRA_BFD_DEST_REPLAY,
- ZEBRA_REDISTRIBUTE_IPV4_ADD,
- ZEBRA_REDISTRIBUTE_IPV4_DEL,
- ZEBRA_REDISTRIBUTE_IPV6_ADD,
- ZEBRA_REDISTRIBUTE_IPV6_DEL,
+ ZEBRA_REDISTRIBUTE_ROUTE_ADD,
+ ZEBRA_REDISTRIBUTE_ROUTE_DEL,
ZEBRA_VRF_UNREGISTER,
ZEBRA_VRF_ADD,
ZEBRA_VRF_DELETE,
ZEBRA_INTERFACE_LINK_PARAMS,
ZEBRA_MPLS_LABELS_ADD,
ZEBRA_MPLS_LABELS_DELETE,
- ZEBRA_IPV4_NEXTHOP_ADD,
- ZEBRA_IPV4_NEXTHOP_DELETE,
- ZEBRA_IPV6_NEXTHOP_ADD,
- ZEBRA_IPV6_NEXTHOP_DELETE,
ZEBRA_IPMR_ROUTE_STATS,
ZEBRA_LABEL_MANAGER_CONNECT,
ZEBRA_GET_LABEL_CHUNK,
/* Socket to zebra daemon. */
int sock;
- /* Flag of communication to zebra is enabled or not. Default is on.
- This flag is disabled by `no router zebra' statement. */
- int enable;
-
/* Connection failure count. */
int fail;
int (*nexthop_update)(int, struct zclient *, uint16_t, vrf_id_t);
int (*import_check_update)(int, struct zclient *, uint16_t, vrf_id_t);
int (*bfd_dest_replay)(int, struct zclient *, uint16_t, vrf_id_t);
- int (*redistribute_route_ipv4_add)(int, struct zclient *, uint16_t,
- vrf_id_t);
- int (*redistribute_route_ipv4_del)(int, struct zclient *, uint16_t,
- vrf_id_t);
- int (*redistribute_route_ipv6_add)(int, struct zclient *, uint16_t,
- vrf_id_t);
- int (*redistribute_route_ipv6_del)(int, struct zclient *, uint16_t,
- vrf_id_t);
+ int (*redistribute_route_add)(int, struct zclient *, uint16_t,
+ vrf_id_t);
+ int (*redistribute_route_del)(int, struct zclient *, uint16_t,
+ vrf_id_t);
int (*fec_update)(int, struct zclient *, uint16_t);
int (*local_vni_add)(int, struct zclient *, uint16_t, vrf_id_t);
int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t);
/* Zebra API message flag. */
#define ZAPI_MESSAGE_NEXTHOP 0x01
-#define ZAPI_MESSAGE_IFINDEX 0x02
-#define ZAPI_MESSAGE_DISTANCE 0x04
-#define ZAPI_MESSAGE_METRIC 0x08
-#define ZAPI_MESSAGE_TAG 0x10
-#define ZAPI_MESSAGE_MTU 0x20
-#define ZAPI_MESSAGE_SRCPFX 0x40
-#define ZAPI_MESSAGE_LABEL 0x80
+#define ZAPI_MESSAGE_DISTANCE 0x02
+#define ZAPI_MESSAGE_METRIC 0x04
+#define ZAPI_MESSAGE_TAG 0x08
+#define ZAPI_MESSAGE_MTU 0x10
+#define ZAPI_MESSAGE_SRCPFX 0x20
+#define ZAPI_MESSAGE_LABEL 0x40
/* Zserv protocol message header */
struct zserv_header {
uint16_t command;
};
+struct zapi_nexthop {
+ enum nexthop_types_t type;
+ ifindex_t ifindex;
+ union g_addr gate;
+
+ /* MPLS labels for BGP-LU or Segment Routing */
+ uint8_t label_num;
+ mpls_label_t labels[MPLS_MAX_LABELS];
+};
+
struct zapi_route {
u_char type;
u_short instance;
safi_t safi;
- u_char nexthop_num;
- struct nexthop **nexthop;
+ struct prefix prefix;
+ struct prefix_ipv6 src_prefix;
+
+ u_int16_t nexthop_num;
+ struct zapi_nexthop nexthops[MULTIPATH_NUM];
u_char distance;
extern void zebra_interface_if_set_value(struct stream *, struct interface *);
extern void zebra_router_id_update_read(struct stream *s, struct prefix *rid);
extern int zapi_ipv4_route(u_char, struct zclient *, struct prefix_ipv4 *,
- struct zapi_ipv4 *);
+ struct zapi_ipv4 *) __attribute__((deprecated));
extern struct interface *zebra_interface_link_params_read(struct stream *);
extern size_t zebra_interface_link_params_write(struct stream *,
extern int zapi_ipv6_route(u_char cmd, struct zclient *zclient,
struct prefix_ipv6 *p, struct prefix_ipv6 *src_p,
- struct zapi_ipv6 *api);
+ struct zapi_ipv6 *api) __attribute__((deprecated));
extern int zapi_ipv4_route_ipv6_nexthop(u_char, struct zclient *,
struct prefix_ipv4 *,
- struct zapi_ipv6 *);
-extern int zapi_route(u_char cmd, struct zclient *zclient, struct prefix *p,
- struct prefix_ipv6 *src_p, struct zapi_route *api);
+ struct zapi_ipv6 *)
+ __attribute__((deprecated));
+extern int zclient_route_send(u_char, struct zclient *, struct zapi_route *);
+extern int zapi_route_encode(u_char, struct stream *, struct zapi_route *);
+extern int zapi_route_decode(struct stream *, struct zapi_route *);
#endif /* _ZEBRA_ZCLIENT_H */
void nhrp_interface_init(void)
{
- if_add_hook(IF_NEW_HOOK, nhrp_if_new_hook);
- if_add_hook(IF_DELETE_HOOK, nhrp_if_delete_hook);
+ hook_register_prio(if_add, 0, nhrp_if_new_hook);
+ hook_register_prio(if_del, 0, nhrp_if_delete_hook);
}
void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi)
static void nhrp_request_stop(void)
{
debugf(NHRP_DEBUG_COMMON, "Exiting...");
+ frr_early_fini();
nhrp_shortcut_terminate();
nhrp_nhs_terminate();
evmgr_terminate();
nhrp_vc_terminate();
vrf_terminate();
- /* memory_terminate(); */
- /* vty_terminate(); */
- cmd_terminate();
- /* signal_terminate(); */
- zprivs_terminate(&nhrpd_privs);
debugf(NHRP_DEBUG_COMMON, "Done.");
-
- closezlog();
+ frr_fini();
exit(0);
}
zb = zbuf_alloc(1400);
hdr = nhrp_packet_push(zb, NHRP_PACKET_REGISTRATION_REQUEST, &nifp->nbma, &if_ad->addr, dst_proto);
- hdr->hop_count = 0;
+ hdr->hop_count = 1;
if (!(if_ad->flags & NHRP_IFF_REG_NO_UNIQUE))
hdr->flags |= htons(NHRP_FLAG_REGISTRATION_UNIQUE);
void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix *p, struct interface *ifp, const union sockunion *nexthop, uint32_t mtu)
{
- int flags = 0;
+ struct zapi_route api;
+ struct zapi_nexthop *api_nh;
if (zclient->sock < 0)
return;
+ memset(&api, 0, sizeof(api));
+ api.type = ZEBRA_ROUTE_NHRP;
+ api.safi = SAFI_UNICAST;
+ api.prefix = *p;
+
switch (type) {
case NHRP_CACHE_NEGATIVE:
- SET_FLAG(flags, ZEBRA_FLAG_REJECT);
+ SET_FLAG(api.flags, ZEBRA_FLAG_REJECT);
break;
case NHRP_CACHE_DYNAMIC:
case NHRP_CACHE_NHS:
* to other routing daemons */
break;
default:
- SET_FLAG(flags, ZEBRA_FLAG_FIB_OVERRIDE);
+ SET_FLAG(api.flags, ZEBRA_FLAG_FIB_OVERRIDE);
break;
}
- SET_FLAG(flags, ZEBRA_FLAG_INTERNAL);
-
- if (p->family == AF_INET) {
- struct in_addr *nexthop_ipv4;
- struct zapi_ipv4 api;
+ SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
- memset(&api, 0, sizeof(api));
- api.flags = flags;
- api.type = ZEBRA_ROUTE_NHRP;
- api.safi = SAFI_UNICAST;
+ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+ api.nexthop_num = 1;
+ api_nh = &api.nexthops[0];
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+ switch (api.prefix.family) {
+ case AF_INET:
if (nexthop) {
- nexthop_ipv4 = (struct in_addr *) sockunion_get_addr(nexthop);
- api.nexthop_num = 1;
- api.nexthop = &nexthop_ipv4;
+ api_nh->gate.ipv4 = nexthop->sin.sin_addr;
+ api_nh->type = NEXTHOP_TYPE_IPV4;
}
if (ifp) {
- SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX);
- api.ifindex_num = 1;
- api.ifindex = &ifp->ifindex;
+ api_nh->ifindex = ifp->ifindex;
+ if (api_nh->type == NEXTHOP_TYPE_IPV4)
+ api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ else
+ api_nh->type = NEXTHOP_TYPE_IFINDEX;
}
- if (mtu) {
- SET_FLAG(api.message, ZAPI_MESSAGE_MTU);
- api.mtu = mtu;
- }
-
- if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) {
- char buf[2][INET_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv4 route %s %s/%d nexthop %s metric %u"
- " count %d dev %s",
- add ? "add" : "del",
- inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
- p->prefixlen,
- nexthop ? inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])) : "<onlink>",
- api.metric, api.nexthop_num, ifp->name);
- }
-
- zapi_ipv4_route(
- add ? ZEBRA_IPV4_ROUTE_ADD : ZEBRA_IPV4_ROUTE_DELETE,
- zclient, (struct prefix_ipv4 *) p, &api);
- } else if (p->family == AF_INET6) {
- struct in6_addr *nexthop_ipv6;
- struct zapi_ipv6 api;
-
- memset(&api, 0, sizeof(api));
- api.flags = flags;
- api.type = ZEBRA_ROUTE_NHRP;
- api.safi = SAFI_UNICAST;
-
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+ break;
+ case AF_INET6:
if (nexthop) {
- nexthop_ipv6 = (struct in6_addr *) sockunion_get_addr(nexthop);
- api.nexthop_num = 1;
- api.nexthop = &nexthop_ipv6;
+ api_nh->gate.ipv6 = nexthop->sin6.sin6_addr;
+ api_nh->type = NEXTHOP_TYPE_IPV6;
}
if (ifp) {
- SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX);
- api.ifindex_num = 1;
- api.ifindex = &ifp->ifindex;
- }
- if (mtu) {
- SET_FLAG(api.message, ZAPI_MESSAGE_MTU);
- api.mtu = mtu;
+ api_nh->ifindex = ifp->ifindex;
+ if (api_nh->type == NEXTHOP_TYPE_IPV6)
+ api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ else
+ api_nh->type = NEXTHOP_TYPE_IFINDEX;
}
+ break;
+ }
+ if (mtu) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_MTU);
+ api.mtu = mtu;
+ }
- if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) {
- char buf[2][INET6_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv6 route %s %s/%d nexthop %s metric %u"
- " count %d dev %s",
- add ? "add" : "del",
- inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
- p->prefixlen,
- nexthop ? inet_ntop(AF_INET6, api.nexthop[0], buf[1], sizeof(buf[1])) : "<onlink>",
- api.metric, api.nexthop_num, ifp->name);
- }
+ if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) {
+ char buf[2][PREFIX_STRLEN];
- zapi_ipv6_route(
- add ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE,
- zclient, (struct prefix_ipv6 *) p, NULL, &api);
+ prefix2str(&api.prefix, buf[0], sizeof(buf[0]));
+ zlog_debug("Zebra send: route %s %s nexthop %s metric %u"
+ " count %d dev %s",
+ add ? "add" : "del", buf[0],
+ nexthop ? inet_ntop(api.prefix.family, &api_nh->gate, buf[1], sizeof(buf[1])) : "<onlink>",
+ api.metric, api.nexthop_num, ifp->name);
}
+
+ zclient_route_send(add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, zclient,
+ &api);
}
int nhrp_route_read(int cmd, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id)
{
- struct stream *s;
+ struct zapi_route api;
+ struct zapi_nexthop *api_nh;
struct interface *ifp = NULL;
- struct prefix prefix;
union sockunion nexthop_addr;
- unsigned char message, nexthop_num, ifindex_num;
- unsigned ifindex;
char buf[2][PREFIX_STRLEN];
- int i, afaddrlen, added;
+ int added;
+
+ 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;
- s = zclient->ibuf;
- memset(&prefix, 0, sizeof(prefix));
sockunion_family(&nexthop_addr) = AF_UNSPEC;
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
+ api_nh = &api.nexthops[0];
- /* Type, flags, message. */
- /*type =*/ stream_getc(s);
- /*instance =*/ stream_getw(s);
- /*flags =*/ stream_getl(s);
- message = stream_getc(s);
-
- /* Prefix */
- switch (cmd) {
- case ZEBRA_REDISTRIBUTE_IPV4_ADD:
- case ZEBRA_REDISTRIBUTE_IPV4_DEL:
- prefix.family = AF_INET;
- break;
- case ZEBRA_REDISTRIBUTE_IPV6_ADD:
- case ZEBRA_REDISTRIBUTE_IPV6_DEL:
- prefix.family = AF_INET6;
- break;
- default:
- return -1;
- }
- afaddrlen = family2addrsize(prefix.family);
- prefix.prefixlen = stream_getc(s);
- stream_get(&prefix.u.val, s, PSIZE(prefix.prefixlen));
-
- /* Nexthop, ifindex, distance, metric. */
- if (CHECK_FLAG(message, ZAPI_MESSAGE_NEXTHOP|ZAPI_MESSAGE_IFINDEX)) {
- nexthop_num = stream_getc(s);
- for (i = 0; i < nexthop_num; i++) {
- stream_get(buf[0], s, afaddrlen);
- if (i == 0) sockunion_set(&nexthop_addr, prefix.family, (u_char*) buf[0], afaddrlen);
- }
- ifindex_num = stream_getc(s);
- for (i = 0; i < ifindex_num; i++) {
- ifindex = stream_getl(s);
- if (i == 0 && ifindex != IFINDEX_INTERNAL)
- ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
+ nexthop_addr.sa.sa_family = api.prefix.family;
+ switch (nexthop_addr.sa.sa_family) {
+ case AF_INET:
+ nexthop_addr.sin.sin_addr = api_nh->gate.ipv4;
+ break;
+ case AF_INET6:
+ nexthop_addr.sin6.sin6_addr = api_nh->gate.ipv6;
+ break;
}
+
+ if (api_nh->ifindex != IFINDEX_INTERNAL)
+ ifp = if_lookup_by_index(api_nh->ifindex, VRF_DEFAULT);
}
- if (CHECK_FLAG(message, ZAPI_MESSAGE_DISTANCE))
- /*distance =*/ stream_getc(s);
- if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC))
- /*metric =*/ stream_getl(s);
- added = (cmd == ZEBRA_REDISTRIBUTE_IPV4_ADD || cmd == ZEBRA_REDISTRIBUTE_IPV6_ADD);
+ added = (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD);
debugf(NHRP_DEBUG_ROUTE, "if-route-%s: %s via %s dev %s",
added ? "add" : "del",
- prefix2str(&prefix, buf[0], sizeof buf[0]),
+ prefix2str(&api.prefix, buf[0], sizeof buf[0]),
sockunion2str(&nexthop_addr, buf[1], sizeof buf[1]),
ifp ? ifp->name : "(none)");
- nhrp_route_update_zebra(&prefix, &nexthop_addr, ifp);
- nhrp_shortcut_prefix_change(&prefix, !added);
+ nhrp_route_update_zebra(&api.prefix, &nexthop_addr, ifp);
+ nhrp_shortcut_prefix_change(&api.prefix, !added);
return 0;
}
zclient->interface_down = nhrp_interface_down;
zclient->interface_address_add = nhrp_interface_address_add;
zclient->interface_address_delete = nhrp_interface_address_delete;
- zclient->redistribute_route_ipv4_add = nhrp_route_read;
- zclient->redistribute_route_ipv4_del = nhrp_route_read;
- zclient->redistribute_route_ipv6_add = nhrp_route_read;
- zclient->redistribute_route_ipv6_del = nhrp_route_read;
+ zclient->redistribute_route_add = nhrp_route_read;
+ zclient->redistribute_route_del = nhrp_route_read;
zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0);
}
route_table_finish(zebra_rib[AFI_IP]);
route_table_finish(zebra_rib[AFI_IP6]);
}
-
#ifndef NO_DEBUG
-DEFUN(show_debugging_nhrp, show_debugging_nhrp_cmd,
- "show debugging nhrp",
- SHOW_STR
- "Debugging information\n"
- "NHRP configuration\n")
+DEFUN_NOSH(show_debugging_nhrp, show_debugging_nhrp_cmd,
+ "show debugging [nhrp]",
+ SHOW_STR
+ "Debugging information\n"
+ "NHRP configuration\n")
{
int i;
}
/* Check filter-list */
- if (PREFIX_NAME_OUT(area)) {
- if (PREFIX_LIST_OUT(area) == NULL)
- PREFIX_LIST_OUT(area) = prefix_list_lookup(
- AFI_IP6, PREFIX_NAME_OUT(area));
-
- if (PREFIX_LIST_OUT(area))
- if (prefix_list_apply(PREFIX_LIST_OUT(area),
- &route->prefix)
- != PREFIX_PERMIT) {
- if (is_debug) {
- inet_ntop(AF_INET,
- &(ADV_ROUTER_IN_PREFIX(
- &route->prefix)),
- buf, sizeof(buf));
- zlog_debug(
- "prefix %s was denied by filter-list out",
- buf);
- }
- return 0;
+ if (PREFIX_LIST_OUT(area))
+ if (prefix_list_apply(PREFIX_LIST_OUT(area), &route->prefix)
+ != PREFIX_PERMIT) {
+ if (is_debug) {
+ inet_ntop(AF_INET,
+ &(ADV_ROUTER_IN_PREFIX(
+ &route->prefix)),
+ buf, sizeof(buf));
+ zlog_debug(
+ "prefix %s was denied by filter-list out",
+ buf);
}
- }
+ return 0;
+ }
/* the route is going to be originated. store it in area's summary_table
*/
}
/* Check input prefix-list */
- if (PREFIX_NAME_IN(oa)) {
- if (PREFIX_LIST_IN(oa) == NULL)
- PREFIX_LIST_IN(oa) =
- prefix_list_lookup(AFI_IP6, PREFIX_NAME_IN(oa));
-
- if (PREFIX_LIST_IN(oa))
- if (prefix_list_apply(PREFIX_LIST_IN(oa), &prefix)
- != PREFIX_PERMIT) {
- if (is_debug)
- zlog_debug(
- "Prefix was denied by prefix-list");
- if (old)
- ospf6_route_remove(old, table);
- return;
- }
- }
+ if (PREFIX_LIST_IN(oa))
+ if (prefix_list_apply(PREFIX_LIST_IN(oa), &prefix)
+ != PREFIX_PERMIT) {
+ if (is_debug)
+ zlog_debug(
+ "Prefix was denied by prefix-list");
+ if (old)
+ ospf6_route_remove(old, table);
+ return;
+ }
/* (5),(6): the path preference is handled by the sorting
in the routing table. Always install the path by substituting
#include "ospf6_asbr.h"
#include "ospf6d.h"
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name")
+
int ospf6_area_cmp(void *va, void *vb)
{
struct ospf6_area *oa = (struct ospf6_area *)va;
plist = prefix_list_lookup(AFI_IP6, plistname);
if (strmatch(inout, "in")) {
PREFIX_LIST_IN(area) = plist;
- if (PREFIX_NAME_IN(area))
- free(PREFIX_NAME_IN(area));
-
- PREFIX_NAME_IN(area) = strdup(plistname);
+ XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_IN(area));
+ PREFIX_NAME_IN(area) = XSTRDUP(MTYPE_OSPF6_PLISTNAME,
+ plistname);
ospf6_abr_reimport(area);
} else {
PREFIX_LIST_OUT(area) = plist;
- if (PREFIX_NAME_OUT(area))
- free(PREFIX_NAME_OUT(area));
-
- PREFIX_NAME_OUT(area) = strdup(plistname);
+ XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area));
+ PREFIX_NAME_OUT(area) = XSTRDUP(MTYPE_OSPF6_PLISTNAME,
+ plistname);
ospf6_abr_enable_area(area);
}
return CMD_SUCCESS;
PREFIX_LIST_IN(area) = NULL;
- if (PREFIX_NAME_IN(area))
- free(PREFIX_NAME_IN(area));
-
- PREFIX_NAME_IN(area) = NULL;
+ XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_IN(area));
ospf6_abr_reimport(area);
} else {
if (PREFIX_NAME_OUT(area))
if (!strmatch(PREFIX_NAME_OUT(area), plistname))
return CMD_SUCCESS;
- PREFIX_LIST_OUT(area) = NULL;
- if (PREFIX_NAME_OUT(area))
- free(PREFIX_NAME_OUT(area));
-
- PREFIX_NAME_OUT(area) = NULL;
+ XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area));
ospf6_abr_enable_area(area);
}
return CMD_SUCCESS;
}
+void ospf6_area_plist_update(struct prefix_list *plist, int add)
+{
+ struct ospf6_area *oa;
+ struct listnode *n;
+ const char *name = prefix_list_name(plist);
+
+ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) {
+ if (!strcmp(PREFIX_NAME_IN(oa), name))
+ PREFIX_LIST_IN(oa) = add ? plist : NULL;
+ if (!strcmp(PREFIX_NAME_OUT(oa), name))
+ PREFIX_LIST_OUT(oa) = add ? plist : NULL;
+ }
+}
+
DEFUN (area_import_list,
area_import_list_cmd,
"area A.B.C.D import-list NAME",
extern void ospf6_area_show(struct vty *, struct ospf6_area *);
+extern void ospf6_area_plist_update(struct prefix_list *plist, int add);
extern void ospf6_area_config_write(struct vty *vty);
extern void ospf6_area_init(void);
IP6_STR
OSPF6_STR
"Interface cost\n"
- "Outgoing metric of this interface\n"
- )
+ "Outgoing metric of this interface\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
DEFUN (no_ipv6_ospf6_cost,
no_ipv6_ospf6_cost_cmd,
- "no ipv6 ospf6 cost",
+ "no ipv6 ospf6 cost [(1-65535)]",
NO_STR
IP6_STR
OSPF6_STR
"Calculate interface cost from bandwidth\n"
- )
+ "Outgoing metric of this interface\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
IP6_STR
OSPF6_STR
"Time between HELLO packets\n"
- SECONDS_STR
- )
+ SECONDS_STR)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
oi = ospf6_interface_create(ifp);
assert(oi);
- oi->hello_interval = strtol(argv[idx_number]->arg, NULL, 10);
+ oi->hello_interval = strmatch(argv[0]->text, "no")
+ ? OSPF_HELLO_INTERVAL_DEFAULT
+ : strtoul(argv[idx_number]->arg, NULL, 10);
return CMD_SUCCESS;
}
+ALIAS (ipv6_ospf6_hellointerval,
+ no_ipv6_ospf6_hellointerval_cmd,
+ "no ipv6 ospf6 hello-interval [(1-65535)]",
+ NO_STR
+ IP6_STR
+ OSPF6_STR
+ "Time between HELLO packets\n"
+ SECONDS_STR)
+
/* interface variable set command */
DEFUN (ipv6_ospf6_deadinterval,
ipv6_ospf6_deadinterval_cmd,
IP6_STR
OSPF6_STR
"Interval time after which a neighbor is declared down\n"
- SECONDS_STR
- )
+ SECONDS_STR)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
oi = ospf6_interface_create(ifp);
assert(oi);
- oi->dead_interval = strtol(argv[idx_number]->arg, NULL, 10);
+ oi->dead_interval = strmatch(argv[0]->arg, "no")
+ ? OSPF_ROUTER_DEAD_INTERVAL_DEFAULT
+ : strtoul(argv[idx_number]->arg, NULL, 10);
return CMD_SUCCESS;
}
+ALIAS (ipv6_ospf6_deadinterval,
+ no_ipv6_ospf6_deadinterval_cmd,
+ "no ipv6 ospf6 dead-interval [(1-65535)]",
+ NO_STR
+ IP6_STR
+ OSPF6_STR
+ "Interval time after which a neighbor is declared down\n"
+ SECONDS_STR)
+
/* interface variable set command */
DEFUN (ipv6_ospf6_transmitdelay,
ipv6_ospf6_transmitdelay_cmd,
oi = ospf6_interface_create(ifp);
assert(oi);
- oi->transdelay = strtol(argv[idx_number]->arg, NULL, 10);
+ oi->transdelay = strmatch(argv[0]->text, "no")
+ ? OSPF6_INTERFACE_TRANSDELAY
+ : strtoul(argv[idx_number]->arg, NULL, 10);
return CMD_SUCCESS;
}
+ALIAS (ipv6_ospf6_transmitdelay,
+ no_ipv6_ospf6_transmitdelay_cmd,
+ "no ipv6 ospf6 transmit-delay [(1-3600)]",
+ NO_STR
+ IP6_STR
+ OSPF6_STR
+ "Link state transmit delay\n"
+ SECONDS_STR)
+
/* interface variable set command */
DEFUN (ipv6_ospf6_retransmitinterval,
ipv6_ospf6_retransmitinterval_cmd,
IP6_STR
OSPF6_STR
"Time between retransmitting lost link state advertisements\n"
- SECONDS_STR
- )
+ SECONDS_STR)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
oi = ospf6_interface_create(ifp);
assert(oi);
- oi->rxmt_interval = strtol(argv[idx_number]->arg, NULL, 10);
+ oi->rxmt_interval = strmatch(argv[0]->text, "no")
+ ? OSPF_RETRANSMIT_INTERVAL_DEFAULT
+ : strtoul(argv[idx_number]->arg, NULL, 10);
return CMD_SUCCESS;
}
+ALIAS (ipv6_ospf6_retransmitinterval,
+ no_ipv6_ospf6_retransmitinterval_cmd,
+ "no ipv6 ospf6 retransmit-interval [(1-65535)]",
+ NO_STR
+ IP6_STR
+ OSPF6_STR
+ "Time between retransmitting lost link state advertisements\n"
+ SECONDS_STR)
+
/* interface variable set command */
DEFUN (ipv6_ospf6_priority,
ipv6_ospf6_priority_cmd,
IP6_STR
OSPF6_STR
"Router priority\n"
- "Priority value\n"
- )
+ "Priority value\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
oi = ospf6_interface_create(ifp);
assert(oi);
- oi->priority = strtol(argv[idx_number]->arg, NULL, 10);
+ oi->priority = strmatch(argv[0]->text, "no")
+ ? OSPF6_INTERFACE_PRIORITY
+ : strtoul(argv[idx_number]->arg, NULL, 10);
if (oi->area && (oi->state == OSPF6_INTERFACE_DROTHER
|| oi->state == OSPF6_INTERFACE_BDR
return CMD_SUCCESS;
}
+ALIAS (ipv6_ospf6_priority,
+ no_ipv6_ospf6_priority_cmd,
+ "no ipv6 ospf6 priority [(0-255)]",
+ NO_STR
+ IP6_STR
+ OSPF6_STR
+ "Router priority\n"
+ "Priority value\n")
+
DEFUN (ipv6_ospf6_instance,
ipv6_ospf6_instance_cmd,
"ipv6 ospf6 instance-id (0-255)",
IP6_STR
OSPF6_STR
"Instance ID for this interface\n"
- "Instance ID value\n"
- )
+ "Instance ID value\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
int idx_number = 3;
oi = ospf6_interface_create(ifp);
assert(oi);
- oi->instance_id = strtol(argv[idx_number]->arg, NULL, 10);
+ oi->instance_id = strmatch(argv[0]->text, "no")
+ ? OSPF6_INTERFACE_INSTANCE_ID
+ : strtoul(argv[idx_number]->arg, NULL, 10);
return CMD_SUCCESS;
}
+ALIAS (ipv6_ospf6_instance,
+ no_ipv6_ospf6_instance_cmd,
+ "no ipv6 ospf6 instance-id [(0-255)]",
+ NO_STR
+ IP6_STR
+ OSPF6_STR
+ "Instance ID for this interface\n"
+ "Instance ID value\n")
+
DEFUN (ipv6_ospf6_passive,
ipv6_ospf6_passive_cmd,
"ipv6 ospf6 passive",
DEFUN (no_ipv6_ospf6_advertise_prefix_list,
no_ipv6_ospf6_advertise_prefix_list_cmd,
- "no ipv6 ospf6 advertise prefix-list",
+ "no ipv6 ospf6 advertise prefix-list [WORD]",
NO_STR
IP6_STR
OSPF6_STR
"Advertising options\n"
"Filter prefix using prefix-list\n"
- )
+ "Prefix list name\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
oi = ospf6_interface_create(ifp);
assert(oi);
- if (oi->plist_name) {
+ if (oi->plist_name)
XFREE(MTYPE_CFG_PLIST_NAME, oi->plist_name);
- oi->plist_name = NULL;
- }
ospf6_interface_connected_route_update(oi->interface);
DEFUN (no_ipv6_ospf6_network,
no_ipv6_ospf6_network_cmd,
- "no ipv6 ospf6 network",
+ "no ipv6 ospf6 network [<broadcast|point-to-point>]",
NO_STR
IP6_STR
OSPF6_STR
- "Set default network type\n")
+ "Set default network type\n"
+ "Specify OSPF6 broadcast network\n"
+ "Specify OSPF6 point-to-point network\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf6_interface *oi;
install_element(INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd);
install_element(INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd);
install_element(INTERFACE_NODE, &no_ipv6_ospf6_ifmtu_cmd);
+
install_element(INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd);
install_element(INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd);
install_element(INTERFACE_NODE, &ipv6_ospf6_priority_cmd);
install_element(INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd);
install_element(INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd);
install_element(INTERFACE_NODE, &ipv6_ospf6_instance_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_ospf6_deadinterval_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_ospf6_hellointerval_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_ospf6_priority_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_ospf6_retransmitinterval_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_ospf6_transmitdelay_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_ospf6_instance_cmd);
install_element(INTERFACE_NODE, &ipv6_ospf6_passive_cmd);
install_element(INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd);
struct listnode *node;
struct interface *ifp;
+ frr_early_fini();
+
if (ospf6)
ospf6_delete(ospf6);
ospf6_lsa_terminate();
vrf_terminate();
- vty_terminate();
- cmd_terminate();
if (zclient) {
zclient_stop(zclient);
zclient_free(zclient);
}
- if (master)
- thread_master_free(master);
-
- closezlog();
-
+ frr_fini();
exit(status);
}
}
void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
- ifindex_t *ifindexes,
- struct in6_addr **nexthop_addr,
+ struct zapi_nexthop nexthops[],
int entries)
{
struct ospf6_nexthop *nh;
zlog_debug(" nexthop: %s%%%.*s(%d)", buf,
IFNAMSIZ, ifname, nh->ifindex);
}
- if (i < entries) {
- nexthop_addr[i] = &nh->address;
- ifindexes[i] = nh->ifindex;
- i++;
- } else {
+ if (i >= entries)
return;
- }
+
+ nexthops[i].ifindex = nh->ifindex;
+ if (!IN6_IS_ADDR_UNSPECIFIED(&nh->address)) {
+ nexthops[i].gate.ipv6 = nh->address;
+ nexthops[i].type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ } else
+ nexthops[i].type = NEXTHOP_TYPE_IFINDEX;
+ i++;
}
}
}
#define OSPF6_ROUTE_H
#include "command.h"
+#include "zclient.h"
#define OSPF6_MULTI_PATH_LIMIT 4
extern int ospf6_route_cmp_nexthops(struct ospf6_route *a,
struct ospf6_route *b);
extern void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
- ifindex_t *ifindices,
- struct in6_addr **addr,
+ struct zapi_nexthop nexthops[],
int entries);
extern int ospf6_route_get_first_nh_index(struct ospf6_route *route);
/* change Router_ID commands. */
DEFUN (ospf6_router_id,
ospf6_router_id_cmd,
- "router-id A.B.C.D",
- "Configure OSPF Router-ID\n"
+ "ospf6 router-id A.B.C.D",
+ OSPF6_STR
+ "Configure OSPF6 Router-ID\n"
V4NOTATION_STR)
{
VTY_DECLVAR_CONTEXT(ospf6, o);
- int idx_ipv4 = 1;
+ int idx = 0;
int ret;
+ const char *router_id_str;
u_int32_t router_id;
- ret = inet_pton(AF_INET, argv[idx_ipv4]->arg, &router_id);
+ argv_find(argv, argc, "A.B.C.D", &idx);
+ router_id_str = argv[idx]->arg;
+
+ ret = inet_pton(AF_INET, router_id_str, &router_id);
if (ret == 0) {
vty_out(vty, "malformed OSPF Router-ID: %s\n",
- argv[idx_ipv4]->arg);
+ router_id_str);
return CMD_SUCCESS;
}
return CMD_SUCCESS;
}
+DEFUN (no_ospf6_router_id,
+ no_ospf6_router_id_cmd,
+ "no ospf6 router-id [A.B.C.D]",
+ NO_STR
+ OSPF6_STR
+ "Configure OSPF6 Router-ID\n"
+ V4NOTATION_STR)
+{
+ VTY_DECLVAR_CONTEXT(ospf6, o);
+ o->router_id_static = 0;
+ o->router_id = 0;
+
+ return CMD_SUCCESS;
+}
+
+#if CONFDATE > 20180828
+CPP_NOTICE("ospf6: `router-id A.B.C.D` deprecated 2017/08/28")
+#endif
+ALIAS_HIDDEN(ospf6_router_id,
+ ospf6_router_id_hdn_cmd,
+ "router-id A.B.C.D",
+ "Configure OSPF6 Router-ID\n"
+ V4NOTATION_STR)
+
+#if CONFDATE > 20180828
+CPP_NOTICE("ospf6: `no router-id A.B.C.D` deprecated 2017/08/28")
+#endif
+ALIAS_HIDDEN(no_ospf6_router_id,
+ no_ospf6_router_id_hdn_cmd,
+ "no router-id [A.B.C.D]",
+ NO_STR
+ "Configure OSPF6 Router-ID\n"
+ V4NOTATION_STR)
+
DEFUN (ospf6_log_adjacency_changes,
ospf6_log_adjacency_changes_cmd,
"log-adjacency-changes",
sizeof(router_id));
vty_out(vty, "router ospf6\n");
if (ospf6->router_id_static != 0)
- vty_out(vty, " router-id %s\n", router_id);
+ vty_out(vty, " ospf6 router-id %s\n", router_id);
/* log-adjacency-changes flag print. */
if (CHECK_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) {
install_default(OSPF6_NODE);
install_element(OSPF6_NODE, &ospf6_router_id_cmd);
+ install_element(OSPF6_NODE, &no_ospf6_router_id_cmd);
+ install_element(OSPF6_NODE, &ospf6_router_id_hdn_cmd);
+ install_element(OSPF6_NODE, &no_ospf6_router_id_hdn_cmd);
install_element(OSPF6_NODE, &ospf6_log_adjacency_changes_cmd);
install_element(OSPF6_NODE, &ospf6_log_adjacency_changes_detail_cmd);
install_element(OSPF6_NODE, &no_ospf6_log_adjacency_changes_cmd);
return 0;
}
-static int ospf6_zebra_read_ipv6(int command, struct zclient *zclient,
- zebra_size_t length, vrf_id_t vrf_id)
+static int ospf6_zebra_read_route(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
{
- struct stream *s;
- struct zapi_ipv6 api;
+ struct zapi_route api;
unsigned long ifindex;
- struct prefix p, src_p;
struct in6_addr *nexthop;
if (ospf6 == NULL)
return 0;
- s = zclient->ibuf;
- ifindex = 0;
- nexthop = NULL;
- memset(&api, 0, sizeof(api));
-
- /* 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));
- p.family = AF_INET6;
- p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc(s));
- stream_get(&p.u.prefix6, s, 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(s);
- stream_get(&src_p.u.prefix6, s, PSIZE(src_p.prefixlen));
- }
+ if (zapi_route_decode(zclient->ibuf, &api) < 0)
+ return -1;
- 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);
- nexthop = (struct in6_addr *)malloc(api.nexthop_num
- * sizeof(struct in6_addr));
- stream_get(nexthop, s,
- api.nexthop_num * sizeof(struct in6_addr));
- }
- 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 (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG))
- api.tag = stream_getl(s);
- else
- api.tag = 0;
+ ifindex = api.nexthops[0].ifindex;
+ nexthop = &api.nexthops[0].gate.ipv6;
if (IS_OSPF6_DEBUG_ZEBRA(RECV)) {
char prefixstr[PREFIX2STR_BUFFER], nexthopstr[128];
- prefix2str((struct prefix *)&p, prefixstr, sizeof(prefixstr));
+ prefix2str((struct prefix *)&api.prefix, prefixstr,
+ sizeof(prefixstr));
if (nexthop)
inet_ntop(AF_INET6, nexthop, nexthopstr,
sizeof(nexthopstr));
zlog_debug(
"Zebra Receive route %s: %s %s nexthop %s ifindex %ld tag %" ROUTE_TAG_PRI,
- (command == ZEBRA_REDISTRIBUTE_IPV6_ADD ? "add"
- : "delete"),
+ (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD ? "add"
+ : "delete"),
zebra_route_string(api.type), prefixstr, nexthopstr,
ifindex, api.tag);
}
- if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
- ospf6_asbr_redistribute_add(api.type, ifindex, &p,
+ if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
+ ospf6_asbr_redistribute_add(api.type, ifindex, &api.prefix,
api.nexthop_num, nexthop, api.tag);
else
- ospf6_asbr_redistribute_remove(api.type, ifindex, &p);
-
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP))
- free(nexthop);
+ ospf6_asbr_redistribute_remove(api.type, ifindex, &api.prefix);
return 0;
}
}
vty_out(vty, "Zebra Infomation\n");
- vty_out(vty, " enable: %d fail: %d\n", zclient->enable, zclient->fail);
+ vty_out(vty, " fail: %d\n", zclient->fail);
vty_out(vty, " redistribute default: %d\n",
vrf_bitmap_check(zclient->default_information, VRF_DEFAULT));
vty_out(vty, " redistribute:");
return CMD_SUCCESS;
}
-/* Zebra configuration write function. */
-static int config_write_ospf6_zebra(struct vty *vty)
-{
- if (!zclient->enable) {
- vty_out(vty, "no router zebra\n");
- vty_out(vty, "!\n");
- } else if (!vrf_bitmap_check(
- zclient->redist[AFI_IP6][ZEBRA_ROUTE_OSPF6],
- VRF_DEFAULT)) {
- vty_out(vty, "router zebra\n");
- vty_out(vty, " no redistribute ospf6\n");
- vty_out(vty, "!\n");
- }
- return 0;
-}
-
-/* Zebra node structure. */
-static struct cmd_node zebra_node = {
- ZEBRA_NODE, "%s(config-zebra)# ",
-};
-
#define ADD 0
#define REM 1
static void ospf6_zebra_route_update(int type, struct ospf6_route *request)
{
- struct zapi_ipv6 api;
+ struct zapi_route api;
char buf[PREFIX2STR_BUFFER];
int nhcount;
- struct in6_addr **nexthops;
- ifindex_t *ifindexes;
int ret = 0;
- struct prefix_ipv6 *dest;
+ struct prefix *dest;
if (IS_OSPF6_DEBUG_ZEBRA(SEND)) {
prefix2str(&request->prefix, buf, sizeof(buf));
return;
}
- /* allocate memory for nexthop_list */
- nexthops =
- XCALLOC(MTYPE_OSPF6_OTHER, nhcount * sizeof(struct in6_addr *));
- if (nexthops == NULL) {
- zlog_warn("Can't send route to zebra: malloc failed");
- return;
- }
-
- /* allocate memory for ifindex_list */
- ifindexes = XCALLOC(MTYPE_OSPF6_OTHER, nhcount * sizeof(ifindex_t));
- if (ifindexes == NULL) {
- zlog_warn("Can't send route to zebra: malloc failed");
- XFREE(MTYPE_OSPF6_OTHER, nexthops);
- return;
- }
-
- ospf6_route_zebra_copy_nexthops(request, ifindexes, nexthops, nhcount);
+ dest = &request->prefix;
+ memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_OSPF6;
- api.instance = 0;
- api.flags = 0;
- api.message = 0;
api.safi = SAFI_UNICAST;
+ api.prefix = *dest;
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = nhcount;
- api.nexthop = nexthops;
- SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX);
- api.ifindex_num = nhcount;
- api.ifindex = ifindexes;
+ ospf6_route_zebra_copy_nexthops(request, api.nexthops, nhcount);
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = (request->path.metric_type == 2 ? request->path.u.cost_e2
: request->path.cost);
api.tag = request->path.tag;
}
- dest = (struct prefix_ipv6 *)&request->prefix;
-
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
- api.distance = ospf6_distance_apply(dest, request);
+ api.distance =
+ ospf6_distance_apply((struct prefix_ipv6 *)dest, request);
if (type == REM)
- ret = zapi_ipv6_route(ZEBRA_IPV6_ROUTE_DELETE, zclient, dest,
- NULL, &api);
+ ret = zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
else
- ret = zapi_ipv6_route(ZEBRA_IPV6_ROUTE_ADD, zclient, dest, NULL,
- &api);
+ ret = zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
if (ret < 0)
- zlog_err("zapi_ipv6_route() %s failed: %s",
+ zlog_err("zclient_route_send() %s failed: %s",
(type == REM ? "delete" : "add"),
safe_strerror(errno));
- XFREE(MTYPE_OSPF6_OTHER, nexthops);
- XFREE(MTYPE_OSPF6_OTHER, ifindexes);
-
return;
}
void ospf6_zebra_route_update_add(struct ospf6_route *request)
{
- if (!vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_OSPF6],
- VRF_DEFAULT)) {
- ospf6->route_table->hook_add = NULL;
- ospf6->route_table->hook_remove = NULL;
- return;
- }
ospf6_zebra_route_update(ADD, request);
}
void ospf6_zebra_route_update_remove(struct ospf6_route *request)
{
- if (!vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_OSPF6],
- VRF_DEFAULT)) {
- ospf6->route_table->hook_add = NULL;
- ospf6->route_table->hook_remove = NULL;
- return;
- }
ospf6_zebra_route_update(REM, request);
}
void ospf6_zebra_add_discard(struct ospf6_route *request)
{
- struct zapi_ipv6 api;
- char buf[INET6_ADDRSTRLEN];
- struct prefix_ipv6 *dest;
-
- if (vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_OSPF6],
- VRF_DEFAULT)) {
- if (!CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
- api.vrf_id = VRF_DEFAULT;
- api.type = ZEBRA_ROUTE_OSPF6;
- api.flags = ZEBRA_FLAG_BLACKHOLE;
- api.instance = 0;
- api.message = 0;
- api.safi = SAFI_UNICAST;
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
- api.nexthop_num = 0;
- api.ifindex_num = 0;
-
- dest = (struct prefix_ipv6 *)&request->prefix;
-
- zapi_ipv6_route(ZEBRA_IPV6_ROUTE_ADD, zclient, dest,
- NULL, &api);
-
- if (IS_OSPF6_DEBUG_ZEBRA(SEND))
- zlog_debug("Zebra: Route add discard %s/%d",
- inet_ntop(AF_INET6, &dest->prefix,
- buf, INET6_ADDRSTRLEN),
- dest->prefixlen);
- SET_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED);
- } else {
- dest = (struct prefix_ipv6 *)&request->prefix;
-
- if (IS_OSPF6_DEBUG_ZEBRA(SEND))
- zlog_debug(
- "Zebra: Blackhole route present already %s/%d",
- inet_ntop(AF_INET6, &dest->prefix, buf,
- INET6_ADDRSTRLEN),
- dest->prefixlen);
- }
- }
-}
-
-void ospf6_zebra_delete_discard(struct ospf6_route *request)
-{
- struct zapi_ipv6 api;
+ struct zapi_route api;
char buf[INET6_ADDRSTRLEN];
- struct prefix_ipv6 *dest;
-
- if (vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_OSPF6],
- VRF_DEFAULT)) {
- if (CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
- api.vrf_id = VRF_DEFAULT;
- api.type = ZEBRA_ROUTE_OSPF6;
- api.flags = ZEBRA_FLAG_BLACKHOLE;
- api.instance = 0;
- api.message = 0;
- api.safi = SAFI_UNICAST;
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
- api.nexthop_num = 0;
- api.ifindex_num = 0;
-
- dest = (struct prefix_ipv6 *)&request->prefix;
-
- zapi_ipv6_route(ZEBRA_IPV6_ROUTE_DELETE, zclient, dest,
- NULL, &api);
-
- if (IS_OSPF6_DEBUG_ZEBRA(SEND))
- zlog_debug("Zebra: Route delete discard %s/%d",
- inet_ntop(AF_INET6, &dest->prefix,
- buf, INET6_ADDRSTRLEN),
- dest->prefixlen);
- UNSET_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED);
- } else {
- dest = (struct prefix_ipv6 *)&request->prefix;
- if (IS_OSPF6_DEBUG_ZEBRA(SEND))
- zlog_debug(
- "Zebra: Blackhole route already deleted %s/%d",
- inet_ntop(AF_INET6, &dest->prefix, buf,
- INET6_ADDRSTRLEN),
- dest->prefixlen);
- }
- }
-}
-
-DEFUN (redistribute_ospf6,
- redistribute_ospf6_cmd,
- "redistribute ospf6",
- "Redistribute control\n"
- "OSPF6 route\n")
-{
- struct ospf6_route *route;
-
- if (vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_OSPF6],
- VRF_DEFAULT))
- return CMD_SUCCESS;
-
- vrf_bitmap_set(zclient->redist[AFI_IP6][ZEBRA_ROUTE_OSPF6],
- VRF_DEFAULT);
+ struct prefix *dest = &request->prefix;
- if (ospf6 == NULL)
- return CMD_SUCCESS;
+ if (!CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = VRF_DEFAULT;
+ api.type = ZEBRA_ROUTE_OSPF6;
+ api.flags = ZEBRA_FLAG_BLACKHOLE;
+ api.safi = SAFI_UNICAST;
+ api.prefix = *dest;
- /* send ospf6 route to zebra route table */
- for (route = ospf6_route_head(ospf6->route_table); route;
- route = ospf6_route_next(route))
- ospf6_zebra_route_update_add(route);
+ zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
- ospf6->route_table->hook_add = ospf6_zebra_route_update_add;
- ospf6->route_table->hook_remove = ospf6_zebra_route_update_remove;
+ if (IS_OSPF6_DEBUG_ZEBRA(SEND))
+ zlog_debug("Zebra: Route add discard %s/%d",
+ inet_ntop(AF_INET6, &dest->u.prefix6, buf,
+ INET6_ADDRSTRLEN),
+ dest->prefixlen);
- return CMD_SUCCESS;
+ SET_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED);
+ } else {
+ if (IS_OSPF6_DEBUG_ZEBRA(SEND))
+ zlog_debug(
+ "Zebra: Blackhole route present already %s/%d",
+ inet_ntop(AF_INET6, &dest->u.prefix6, buf,
+ INET6_ADDRSTRLEN),
+ dest->prefixlen);
+ }
}
-DEFUN (no_redistribute_ospf6,
- no_redistribute_ospf6_cmd,
- "no redistribute ospf6",
- NO_STR
- "Redistribute control\n"
- "OSPF6 route\n")
+void ospf6_zebra_delete_discard(struct ospf6_route *request)
{
- struct ospf6_route *route;
+ struct zapi_route api;
+ char buf[INET6_ADDRSTRLEN];
+ struct prefix *dest = &request->prefix;
- if (!vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_OSPF6],
- VRF_DEFAULT))
- return CMD_SUCCESS;
+ if (CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = VRF_DEFAULT;
+ api.type = ZEBRA_ROUTE_OSPF6;
+ api.flags = ZEBRA_FLAG_BLACKHOLE;
+ api.safi = SAFI_UNICAST;
+ api.prefix = *dest;
- vrf_bitmap_unset(zclient->redist[AFI_IP6][ZEBRA_ROUTE_OSPF6],
- VRF_DEFAULT);
+ zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
- if (ospf6 == NULL)
- return CMD_SUCCESS;
-
- ospf6->route_table->hook_add = NULL;
- ospf6->route_table->hook_remove = NULL;
-
- /* withdraw ospf6 route from zebra route table */
- for (route = ospf6_route_head(ospf6->route_table); route;
- route = ospf6_route_next(route))
- ospf6_zebra_route_update_remove(route);
+ if (IS_OSPF6_DEBUG_ZEBRA(SEND))
+ zlog_debug("Zebra: Route delete discard %s/%d",
+ inet_ntop(AF_INET6, &dest->u.prefix6, buf,
+ INET6_ADDRSTRLEN),
+ dest->prefixlen);
- return CMD_SUCCESS;
+ UNSET_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED);
+ } else {
+ if (IS_OSPF6_DEBUG_ZEBRA(SEND))
+ zlog_debug(
+ "Zebra: Blackhole route already deleted %s/%d",
+ inet_ntop(AF_INET6, &dest->u.prefix6, buf,
+ INET6_ADDRSTRLEN),
+ dest->prefixlen);
+ }
}
static struct ospf6_distance *ospf6_distance_new(void)
zclient->interface_address_add = ospf6_zebra_if_address_update_add;
zclient->interface_address_delete =
ospf6_zebra_if_address_update_delete;
- zclient->redistribute_route_ipv4_add = NULL;
- zclient->redistribute_route_ipv4_del = NULL;
- zclient->redistribute_route_ipv6_add = ospf6_zebra_read_ipv6;
- zclient->redistribute_route_ipv6_del = ospf6_zebra_read_ipv6;
-
- /* redistribute connected route by default */
- /* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */
-
- /* Install zebra node. */
- install_node(&zebra_node, config_write_ospf6_zebra);
+ zclient->redistribute_route_add = ospf6_zebra_read_route;
+ zclient->redistribute_route_del = ospf6_zebra_read_route;
/* Install command element for zebra node. */
install_element(VIEW_NODE, &show_ospf6_zebra_cmd);
- install_default(ZEBRA_NODE);
- install_element(ZEBRA_NODE, &redistribute_ospf6_cmd);
- install_element(ZEBRA_NODE, &no_redistribute_ospf6_cmd);
-
- return;
}
/* Debug */
#include "linklist.h"
#include "vty.h"
#include "command.h"
+#include "plist.h"
#include "ospf6_proto.h"
#include "ospf6_network.h"
#include "ospf6d.h"
#include "ospf6_bfd.h"
-char ospf6_daemon_version[] = OSPF6_DAEMON_VERSION;
-
struct route_node *route_prev(struct route_node *node)
{
struct route_node *end;
return prev;
}
-
-/* show database functions */
-DEFUN (show_version_ospf6,
- show_version_ospf6_cmd,
- "show version ospf6",
- SHOW_STR
- "Display version\n"
- "Display ospf6d version\n"
- )
-{
- vty_out(vty, "Zebra OSPF6d Version: %s\n", ospf6_daemon_version);
-
- return CMD_SUCCESS;
-}
-
static struct cmd_node debug_node = {
DEBUG_NODE, "", 1 /* VTYSH */
};
config_write_ospf6_debug_asbr(vty);
config_write_ospf6_debug_abr(vty);
config_write_ospf6_debug_flood(vty);
- vty_out(vty, "!\n");
+
return 0;
}
+DEFUN_NOSH (show_debugging_ospf6,
+ show_debugging_ospf6_cmd,
+ "show debugging [ospf6]",
+ SHOW_STR
+ DEBUG_STR
+ OSPF6_STR)
+{
+ vty_out(vty, "OSPF6 debugging status:");
+
+ config_write_ospf6_debug(vty);
+
+ return CMD_SUCCESS;
+}
+
#define AREA_LSDB_TITLE_FORMAT \
"\n Area Scoped Link State Database (Area %s)\n\n"
#define IF_LSDB_TITLE_FORMAT \
return CMD_SUCCESS;
}
+static void ospf6_plist_add(struct prefix_list *plist)
+{
+ if (prefix_list_afi(plist) != AFI_IP6)
+ return;
+ ospf6_area_plist_update(plist, 1);
+}
+
+static void ospf6_plist_del(struct prefix_list *plist)
+{
+ if (prefix_list_afi(plist) != AFI_IP6)
+ return;
+ ospf6_area_plist_update(plist, 0);
+}
+
/* Install ospf related commands. */
void ospf6_init(void)
{
ospf6_asbr_init();
ospf6_abr_init();
+ prefix_list_add_hook(ospf6_plist_add);
+ prefix_list_delete_hook(ospf6_plist_del);
+
ospf6_bfd_init();
install_node(&debug_node, config_write_ospf6_debug);
install_element_ospf6_clear_interface();
- install_element(VIEW_NODE, &show_version_ospf6_cmd);
+ install_element(VIEW_NODE, &show_debugging_ospf6_cmd);
install_element(VIEW_NODE, &show_ipv6_ospf6_border_routers_cmd);
#ifndef OSPF6D_H
#define OSPF6D_H
-#define OSPF6_DAEMON_VERSION "0.9.7r"
-
#include "libospf.h"
#include "thread.h"
return CMD_SUCCESS;
}
-DEFUN (show_debugging_ospf,
- show_debugging_ospf_cmd,
- "show debugging ospf",
- SHOW_STR
- DEBUG_STR
- OSPF_STR)
+DEFUN_NOSH (show_debugging_ospf,
+ show_debugging_ospf_cmd,
+ "show debugging [ospf]",
+ SHOW_STR
+ DEBUG_STR
+ OSPF_STR)
{
struct ospf *ospf;
return show_debugging_ospf_common(vty, ospf);
}
-DEFUN (show_debugging_ospf_instance,
- show_debugging_ospf_instance_cmd,
- "show debugging ospf (1-65535)",
- SHOW_STR
- DEBUG_STR
- OSPF_STR
- "Instance ID\n")
+DEFUN_NOSH (show_debugging_ospf_instance,
+ show_debugging_ospf_instance_cmd,
+ "show debugging ospf (1-65535)",
+ SHOW_STR
+ DEBUG_STR
+ OSPF_STR
+ "Instance ID\n")
{
int idx_number = 3;
struct ospf *ospf;
{
/* Initialize Zebra interface data structure. */
om->iflist = vrf_iflist(VRF_DEFAULT);
- if_add_hook(IF_NEW_HOOK, ospf_if_new_hook);
- if_add_hook(IF_DELETE_HOOK, ospf_if_delete_hook);
+ hook_register_prio(if_add, 0, ospf_if_new_hook);
+ hook_register_prio(if_del, 0, ospf_if_delete_hook);
}
if (flag == OSPF_SEND_PACKET_INDIRECT)
zlog_warn(
"* LS-Update is directly sent on NBMA network.");
- if (IPV4_ADDR_SAME(&oi->address->u.prefix4, &p.prefix.s_addr))
+ if (IPV4_ADDR_SAME(&oi->address->u.prefix4, &p.prefix))
zlog_warn("* LS-Update is sent to myself.");
}
DEFUN (ospf_area_authentication_message_digest,
ospf_area_authentication_message_digest_cmd,
- "area <A.B.C.D|(0-4294967295)> authentication message-digest",
+ "[no] area <A.B.C.D|(0-4294967295)> authentication message-digest",
+ NO_STR
"OSPF area parameters\n"
"OSPF area ID in IP address format\n"
"OSPF area ID as a decimal value\n"
area = ospf_area_get(ospf, area_id);
ospf_area_display_format_set(ospf, area, format);
- area->auth_type = OSPF_AUTH_CRYPTOGRAPHIC;
+ area->auth_type = strmatch(argv[0]->text, "no") ? OSPF_AUTH_NULL : OSPF_AUTH_CRYPTOGRAPHIC;
return CMD_SUCCESS;
}
return CMD_SUCCESS;
}
-/* Deprecated: 08/07/2017 */
+#if CONFDATE > 20180708
+CPP_NOTICE("ospf: `timers lsa arrival (0-1000)` deprecated 2017/07/08")
+#endif
ALIAS_HIDDEN (ospf_timers_lsa_min_arrival,
ospf_timers_lsa_arrival_cmd,
"timers lsa arrival (0-1000)",
"ospf minimum arrival interval delay\n"
"delay (msec) between accepted lsas\n");
-/* Deprecated: 08/07/2017 */
+#if CONFDATE > 20180708
+CPP_NOTICE("ospf: `no timers lsa arrival (0-1000)` deprecated 2017/07/08")
+#endif
ALIAS_HIDDEN (no_ospf_timers_lsa_min_arrival,
no_ospf_timers_lsa_arrival_cmd,
"no timers lsa arrival (0-1000)",
JSON_STR)
{
struct ospf *ospf;
+ int idx_ifname = 4;
u_char uj = use_json(argc, argv);
if ((ospf = ospf_lookup()) == NULL || !ospf->oi_running)
return CMD_SUCCESS;
- return show_ip_ospf_neighbor_int_common(vty, ospf, 0, argv, uj);
+ return show_ip_ospf_neighbor_int_common(vty, ospf, idx_ifname, argv, uj);
}
DEFUN (show_ip_ospf_instance_neighbor_int,
JSON_STR)
{
int idx_number = 3;
+ int idx_ifname = 5;
struct ospf *ospf;
u_short instance = 0;
u_char uj = use_json(argc, argv);
if (!ospf->oi_running)
return CMD_SUCCESS;
- return show_ip_ospf_neighbor_int_common(vty, ospf, 1, argv, uj);
+ return show_ip_ospf_neighbor_int_common(vty, ospf, idx_ifname, argv, uj);
}
static void show_ip_ospf_nbr_nbma_detail_sub(struct vty *vty,
JSON_STR)
{
struct ospf *ospf;
+ int idx_router_id = 4;
u_char uj = use_json(argc, argv);
if ((ospf = ospf_lookup()) == NULL || !ospf->oi_running)
return CMD_SUCCESS;
- return show_ip_ospf_neighbor_id_common(vty, ospf, 0, argv, uj);
+ return show_ip_ospf_neighbor_id_common(vty, ospf, idx_router_id, argv, uj);
}
DEFUN (show_ip_ospf_instance_neighbor_id,
JSON_STR)
{
int idx_number = 3;
+ int idx_router_id = 5;
struct ospf *ospf;
u_short instance = 0;
u_char uj = use_json(argc, argv);
if (!ospf->oi_running)
return CMD_SUCCESS;
- return show_ip_ospf_neighbor_id_common(vty, ospf, 1, argv, uj);
+ return show_ip_ospf_neighbor_id_common(vty, ospf, idx_router_id, argv, uj);
}
static int show_ip_ospf_neighbor_detail_common(struct vty *vty,
JSON_STR)
{
struct ospf *ospf;
+ int idx_ifname = 4;
u_char uj = use_json(argc, argv);
if ((ospf = ospf_lookup()) == NULL || !ospf->oi_running)
return CMD_SUCCESS;
- return show_ip_ospf_neighbor_int_detail_common(vty, ospf, 0, argv, uj);
+ return show_ip_ospf_neighbor_int_detail_common(vty, ospf, idx_ifname, argv, uj);
}
DEFUN (show_ip_ospf_instance_neighbor_int_detail,
JSON_STR)
{
int idx_number = 3;
+ int idx_ifname = 5;
struct ospf *ospf;
u_short instance = 0;
u_char uj = use_json(argc, argv);
if (!ospf->oi_running)
return CMD_SUCCESS;
- return show_ip_ospf_neighbor_int_detail_common(vty, ospf, 1, argv, uj);
+ return show_ip_ospf_neighbor_int_detail_common(vty, ospf, idx_ifname, argv, uj);
}
/* Show functions */
DEFUN_HIDDEN (no_ospf_transmit_delay,
no_ospf_transmit_delay_cmd,
- "no ospf transmit-delay",
+ "no ospf transmit-delay [(1-65535) [A.B.C.D]]",
NO_STR
"OSPF interface commands\n"
- "Link state transmit delay\n")
+ "Link state transmit delay\n"
+ "Seconds\n"
+ "Address of interface")
{
return no_ip_ospf_transmit_delay(self, vty, argc, argv);
}
void ospf_zebra_add(struct prefix_ipv4 *p, struct ospf_route * or)
{
- u_char message;
+ struct zapi_route api;
+ struct zapi_nexthop *api_nh;
u_char distance;
- u_int32_t flags;
- int psize;
- struct stream *s;
struct ospf_path *path;
struct listnode *node;
struct ospf *ospf = ospf_lookup();
+ int count = 0;
+
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = VRF_DEFAULT;
+ api.type = ZEBRA_ROUTE_OSPF;
+ api.instance = ospf->instance;
+ api.safi = SAFI_UNICAST;
+
+ memcpy(&api.prefix, p, sizeof(*p));
+ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+ api.nexthop_num = or->paths->count;
+
+ /* Metric value. */
+ SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
+ if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL)
+ api.metric = or->cost + or->u.ext.type2_cost;
+ else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)
+ api.metric = or->u.ext.type2_cost;
+ else
+ api.metric = or->cost;
+
+ /* Check if path type is ASE */
+ if (((or->path_type == OSPF_PATH_TYPE1_EXTERNAL)
+ || (or->path_type == OSPF_PATH_TYPE2_EXTERNAL))
+ && (or->u.ext.tag > 0) && (or->u.ext.tag <= ROUTE_TAG_MAX)) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+ api.tag = or->u.ext.tag;
+ }
- if ((ospf->instance
- && redist_check_instance(
- &zclient->mi_redist[AFI_IP][ZEBRA_ROUTE_OSPF],
- ospf->instance))
- || vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_OSPF],
- VRF_DEFAULT)) {
- message = 0;
- flags = 0;
-
- /* OSPF pass nexthop and metric */
- SET_FLAG(message, ZAPI_MESSAGE_NEXTHOP);
- SET_FLAG(message, ZAPI_MESSAGE_METRIC);
-
- /* Distance value. */
- distance = ospf_distance_apply(p, or);
- if (distance)
- SET_FLAG(message, ZAPI_MESSAGE_DISTANCE);
-
- /* Check if path type is ASE */
- if (((or->path_type == OSPF_PATH_TYPE1_EXTERNAL)
- || (or->path_type == OSPF_PATH_TYPE2_EXTERNAL))
- && (or->u.ext.tag > 0) && (or->u.ext.tag <= ROUTE_TAG_MAX))
- SET_FLAG(message, ZAPI_MESSAGE_TAG);
-
- /* Make packet. */
- s = zclient->obuf;
- stream_reset(s);
-
- /* Put command, type, flags, message. */
- zclient_create_header(s, ZEBRA_IPV4_ROUTE_ADD, VRF_DEFAULT);
- stream_putc(s, ZEBRA_ROUTE_OSPF);
- stream_putw(s, ospf->instance);
- stream_putl(s, flags);
- stream_putc(s, message);
- stream_putw(s, SAFI_UNICAST);
-
- /* 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, or->paths->count);
-
- /* Nexthop, ifindex, distance and metric information. */
- for (ALL_LIST_ELEMENTS_RO(or->paths, node, path)) {
+ /* Distance value. */
+ distance = ospf_distance_apply(p, or);
+ if (distance) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
+ api.distance = distance;
+ }
+
+ /* Nexthop, ifindex, distance and metric information. */
+ for (ALL_LIST_ELEMENTS_RO(or->paths, node, path)) {
+ api_nh = &api.nexthops[count];
#ifdef HAVE_NETLINK
- if (path->unnumbered
- || (path->nexthop.s_addr != INADDR_ANY
- && path->ifindex != 0)) {
- stream_putc(s, NEXTHOP_TYPE_IPV4_IFINDEX);
- stream_put_in_addr(s, &path->nexthop);
- stream_putl(s, path->ifindex);
- } else if (path->nexthop.s_addr != INADDR_ANY) {
- stream_putc(s, NEXTHOP_TYPE_IPV4);
- stream_put_in_addr(s, &path->nexthop);
- } else {
- stream_putc(s, NEXTHOP_TYPE_IFINDEX);
- if (path->ifindex)
- stream_putl(s, path->ifindex);
- else
- stream_putl(s, 0);
- }
+ if (path->unnumbered || (path->nexthop.s_addr != INADDR_ANY
+ && path->ifindex != 0)) {
#else /* HAVE_NETLINK */
- if (path->nexthop.s_addr != INADDR_ANY
- && path->ifindex != 0) {
- stream_putc(s, NEXTHOP_TYPE_IPV4_IFINDEX);
- stream_put_in_addr(s, &path->nexthop);
- stream_putl(s, path->ifindex);
- } else if (path->nexthop.s_addr != INADDR_ANY) {
- stream_putc(s, NEXTHOP_TYPE_IPV4);
- stream_put_in_addr(s, &path->nexthop);
- } else {
- stream_putc(s, NEXTHOP_TYPE_IFINDEX);
- if (path->ifindex)
- stream_putl(s, path->ifindex);
- else
- stream_putl(s, 0);
- }
+ if (path->nexthop.s_addr != INADDR_ANY && path->ifindex != 0) {
#endif /* HAVE_NETLINK */
-
- if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) {
- char buf[2][INET_ADDRSTRLEN];
- zlog_debug(
- "Zebra: Route add %s/%d nexthop %s, ifindex=%d",
- inet_ntop(AF_INET, &p->prefix, buf[0],
- sizeof(buf[0])),
- p->prefixlen,
- inet_ntop(AF_INET, &path->nexthop,
- buf[1], sizeof(buf[1])),
- path->ifindex);
- }
+ api_nh->gate.ipv4 = path->nexthop;
+ api_nh->ifindex = path->ifindex;
+ api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ } else if (path->nexthop.s_addr != INADDR_ANY) {
+ api_nh->gate.ipv4 = path->nexthop;
+ api_nh->type = NEXTHOP_TYPE_IPV4;
+ } else {
+ api_nh->ifindex = path->ifindex;
+ api_nh->type = NEXTHOP_TYPE_IFINDEX;
}
+ count++;
- if (CHECK_FLAG(message, ZAPI_MESSAGE_DISTANCE))
- stream_putc(s, distance);
- if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC)) {
- if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL)
- stream_putl(s, or->cost + or->u.ext.type2_cost);
- else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)
- stream_putl(s, or->u.ext.type2_cost);
- else
- stream_putl(s, or->cost);
+ if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) {
+ char buf[2][INET_ADDRSTRLEN];
+ zlog_debug(
+ "Zebra: Route add %s/%d nexthop %s, ifindex=%d",
+ inet_ntop(AF_INET, &p->prefix, buf[0],
+ sizeof(buf[0])),
+ p->prefixlen, inet_ntop(AF_INET, &path->nexthop,
+ buf[1], sizeof(buf[1])),
+ path->ifindex);
}
-
- if (CHECK_FLAG(message, ZAPI_MESSAGE_TAG))
- stream_putl(s, or->u.ext.tag);
-
- stream_putw_at(s, 0, stream_get_endp(s));
-
- zclient_send_message(zclient);
}
+
+ zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
}
void ospf_zebra_delete(struct prefix_ipv4 *p, struct ospf_route * or)
{
- u_char message;
- u_char distance;
- u_int32_t flags;
- int psize;
- struct stream *s;
- struct ospf_path *path;
- struct listnode *node;
+ struct zapi_route api;
struct ospf *ospf = ospf_lookup();
- if ((ospf->instance
- && redist_check_instance(
- &zclient->mi_redist[AFI_IP][ZEBRA_ROUTE_OSPF],
- ospf->instance))
- || vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_OSPF],
- VRF_DEFAULT)) {
- message = 0;
- flags = 0;
- /* Distance value. */
- distance = ospf_distance_apply(p, or);
- /* Make packet. */
- s = zclient->obuf;
- stream_reset(s);
-
- /* Put command, type, flags, message. */
- zclient_create_header(s, ZEBRA_IPV4_ROUTE_DELETE, VRF_DEFAULT);
- stream_putc(s, ZEBRA_ROUTE_OSPF);
- stream_putw(s, ospf->instance);
- stream_putl(s, flags);
- stream_putc(s, message);
- stream_putw(s, SAFI_UNICAST);
-
- /* 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, or->paths->count);
-
- /* Nexthop, ifindex, distance and metric information. */
- for (ALL_LIST_ELEMENTS_RO(or->paths, node, path)) {
- if (path->nexthop.s_addr != INADDR_ANY
- && path->ifindex != 0) {
- stream_putc(s, NEXTHOP_TYPE_IPV4_IFINDEX);
- stream_put_in_addr(s, &path->nexthop);
- stream_putl(s, path->ifindex);
- } else if (path->nexthop.s_addr != INADDR_ANY) {
- stream_putc(s, NEXTHOP_TYPE_IPV4);
- stream_put_in_addr(s, &path->nexthop);
- } else {
- stream_putc(s, NEXTHOP_TYPE_IFINDEX);
- stream_putl(s, path->ifindex);
- }
-
- if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) {
- char buf[2][INET_ADDRSTRLEN];
- zlog_debug(
- "Zebra: Route delete %s/%d nexthop %s",
- inet_ntop(AF_INET, &p->prefix, buf[0],
- sizeof(buf[0])),
- p->prefixlen,
- inet_ntop(AF_INET, &path->nexthop,
- buf[1], sizeof(buf[1])));
- }
- }
-
- if (CHECK_FLAG(message, ZAPI_MESSAGE_DISTANCE))
- stream_putc(s, distance);
- if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC)) {
- if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL)
- stream_putl(s, or->cost + or->u.ext.type2_cost);
- else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL)
- stream_putl(s, or->u.ext.type2_cost);
- else
- stream_putl(s, or->cost);
- }
-
- stream_putw_at(s, 0, stream_get_endp(s));
-
- zclient_send_message(zclient);
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = VRF_DEFAULT;
+ api.type = ZEBRA_ROUTE_OSPF;
+ api.instance = ospf->instance;
+ api.safi = SAFI_UNICAST;
+ memcpy(&api.prefix, p, sizeof(*p));
+
+ if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE)) {
+ char buf[INET_ADDRSTRLEN];
+ zlog_debug("Zebra: Route delete %s/%d",
+ inet_ntop(AF_INET, &p->prefix, buf, sizeof(buf[0])),
+ p->prefixlen);
}
+
+ zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
}
void ospf_zebra_add_discard(struct prefix_ipv4 *p)
{
- struct zapi_ipv4 api;
+ struct zapi_route api;
struct ospf *ospf = ospf_lookup();
- if ((ospf->instance
- && redist_check_instance(
- &zclient->mi_redist[AFI_IP][ZEBRA_ROUTE_OSPF],
- ospf->instance))
- || vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_OSPF],
- VRF_DEFAULT)) {
- api.vrf_id = VRF_DEFAULT;
- api.type = ZEBRA_ROUTE_OSPF;
- api.instance = ospf->instance;
- api.flags = ZEBRA_FLAG_BLACKHOLE;
- api.message = 0;
- api.safi = SAFI_UNICAST;
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
- api.nexthop_num = 0;
- api.ifindex_num = 0;
- api.tag = 0;
-
- zapi_ipv4_route(ZEBRA_IPV4_ROUTE_ADD, zclient, p, &api);
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = VRF_DEFAULT;
+ api.type = ZEBRA_ROUTE_OSPF;
+ api.instance = ospf->instance;
+ api.flags = ZEBRA_FLAG_BLACKHOLE;
+ api.safi = SAFI_UNICAST;
+ memcpy(&api.prefix, p, sizeof(*p));
- if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug("Zebra: Route add discard %s/%d",
- inet_ntoa(p->prefix), p->prefixlen);
- }
+ zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
+
+ if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
+ zlog_debug("Zebra: Route add discard %s/%d",
+ inet_ntoa(p->prefix), p->prefixlen);
}
void ospf_zebra_delete_discard(struct prefix_ipv4 *p)
{
- struct zapi_ipv4 api;
+ struct zapi_route api;
struct ospf *ospf = ospf_lookup();
- if ((ospf->instance
- && redist_check_instance(
- &zclient->mi_redist[AFI_IP][ZEBRA_ROUTE_OSPF],
- ospf->instance))
- || vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_OSPF],
- VRF_DEFAULT)) {
- api.vrf_id = VRF_DEFAULT;
- api.type = ZEBRA_ROUTE_OSPF;
- api.instance = ospf->instance;
- api.flags = ZEBRA_FLAG_BLACKHOLE;
- api.message = 0;
- api.safi = SAFI_UNICAST;
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
- api.nexthop_num = 0;
- api.ifindex_num = 0;
- api.tag = 0;
-
- zapi_ipv4_route(ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api);
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = VRF_DEFAULT;
+ api.type = ZEBRA_ROUTE_OSPF;
+ api.instance = ospf->instance;
+ api.flags = ZEBRA_FLAG_BLACKHOLE;
+ api.safi = SAFI_UNICAST;
+ memcpy(&api.prefix, p, sizeof(*p));
- if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
- zlog_debug("Zebra: Route delete discard %s/%d",
- inet_ntoa(p->prefix), p->prefixlen);
- }
+ zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
+
+ if (IS_DEBUG_OSPF(zebra, ZEBRA_REDISTRIBUTE))
+ zlog_debug("Zebra: Route delete discard %s/%d",
+ inet_ntoa(p->prefix), p->prefixlen);
}
struct ospf_external *ospf_external_lookup(u_char type, u_short instance)
}
/* Zebra route add and delete treatment. */
-static int ospf_zebra_read_ipv4(int command, struct zclient *zclient,
- zebra_size_t length, vrf_id_t vrf_id)
+static int ospf_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 zapi_route api;
+ struct prefix_ipv4 p;
unsigned long ifindex;
struct in_addr nexthop;
- struct prefix_ipv4 p;
struct external_info *ei;
struct ospf *ospf;
int i;
- s = zclient->ibuf;
- ifindex = 0;
- nexthop.s_addr = 0;
+ ospf = ospf_lookup();
+ if (ospf == NULL)
+ return 0;
- /* Type, flags, message. */
- api.type = stream_getc(s);
- api.instance = stream_getw(s);
- api.flags = stream_getl(s);
- api.message = stream_getc(s);
+ if (zapi_route_decode(zclient->ibuf, &api) < 0)
+ return -1;
- /* 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));
+ ifindex = api.nexthops[0].ifindex;
+ nexthop = api.nexthops[0].gate.ipv4;
+ memcpy(&p, &api.prefix, sizeof(p));
if (IPV4_NET127(ntohl(p.prefix.s_addr)))
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);
- /* XXX assert(api.ifindex_num == 1); */
- ifindex = 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);
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG))
- api.tag = stream_getl(s);
- else
- api.tag = 0;
-
- ospf = ospf_lookup();
- if (ospf == NULL)
- return 0;
-
- if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD) {
+ if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) {
/* XXX|HACK|TODO|FIXME:
* Maybe we should ignore reject/blackhole routes? Testing shows
* that
* return 0;
*/
- /* Protocol tag overwrites all other tag value send by zebra */
+ /* Protocol tag overwrites all other tag value sent by zebra */
if (ospf->dtag[api.type] > 0)
api.tag = ospf->dtag[api.type];
zebra,
ZEBRA_REDISTRIBUTE))
zlog_debug(
- "ospf_zebra_read_ipv4() : %s refreshing LSA",
+ "ospf_zebra_read_route() : %s refreshing LSA",
inet_ntoa(
p.prefix));
ospf_external_lsa_refresh(
}
}
}
- } else /* if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL) */
+ } else /* if (command == ZEBRA_REDISTRIBUTE_ROUTE_DEL) */
{
ospf_external_info_delete(api.type, api.instance, p);
if (is_prefix_default(&p))
zclient->interface_address_delete = ospf_interface_address_delete;
zclient->interface_link_params = ospf_interface_link_params;
- zclient->redistribute_route_ipv4_add = ospf_zebra_read_ipv4;
- zclient->redistribute_route_ipv4_del = ospf_zebra_read_ipv4;
+ zclient->redistribute_route_add = ospf_zebra_read_route;
+ zclient->redistribute_route_del = ospf_zebra_read_route;
access_list_add_hook(ospf_filter_update);
access_list_delete_hook(ospf_filter_update);
json_row);
} else {
vty_out(vty,
- "%-9s %-15s %-15s %-15s %-6s %8s %-6s %5s\n",
+ "%-9s %-15s %-15s %-15s %-10s %8s %-6s %5s\n",
ch->interface->name, inet_ntoa(ifaddr),
ch_src_str, ch_grp_str,
pim_ifchannel_ifjoin_name(ch->ifjoin_state,
json = json_object_new_object();
else
vty_out(vty,
- "Interface Address Source Group State Uptime Expire Prune\n");
+ "Interface Address Source Group State Uptime Expire Prune\n");
for (ALL_LIST_ELEMENTS_RO(vrf_iflist(pim->vrf_id), if_node, ifp)) {
pim_ifp = ifp->info;
if (result == PIM_RP_NO_PATH) {
vty_out(vty, "%% No Path to RP address specified: %s\n", rp);
- return CMD_WARNING_CONFIG_FAILED;
+ return CMD_WARNING;
}
if (result == PIM_GROUP_OVERLAP) {
ALIAS(no_debug_msdp_packets, undebug_msdp_packets_cmd, "undebug msdp packets",
UNDEBUG_STR DEBUG_MSDP_STR DEBUG_MSDP_PACKETS_STR)
-DEFUN (show_debugging_pim,
- show_debugging_pim_cmd,
- "show debugging pim",
- SHOW_STR
- DEBUG_STR
- PIM_STR)
+DEFUN_NOSH (show_debugging_pim,
+ show_debugging_pim_cmd,
+ "show debugging [pim]",
+ SHOW_STR
+ DEBUG_STR
+ PIM_STR)
{
+ vty_out(vty, "PIM debugging status\n");
+
pim_debug_config_write(vty);
+
return CMD_SUCCESS;
}
#include "pim_oil.h"
#include "pim_upstream.h"
#include "pim_ssm.h"
+#include "pim_rp.h"
RB_GENERATE(pim_ifchannel_rb, pim_ifchannel,
pim_ifp_rb, pim_ifchannel_compare);
switch (ifjoin_state) {
case PIM_IFJOIN_NOINFO:
if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
- return "SGRpt";
+ return "SGRpt(NI)";
else
return "NOINFO";
break;
return "JOIN";
break;
case PIM_IFJOIN_PRUNE:
- return "PRUNE";
+ if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
+ return "SGRpt(P)";
+ else
+ return "PRUNE";
break;
case PIM_IFJOIN_PRUNE_PENDING:
- return "PRUNEP";
+ if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
+ return "SGRpt(PP)";
+ else
+ return "PRUNEP";
break;
case PIM_IFJOIN_PRUNE_TMP:
- return "PRUNET";
+ if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
+ return "SGRpt(P')";
+ else
+ return "PRUNET";
break;
case PIM_IFJOIN_PRUNE_PENDING_TMP:
- return "PRUNEPT";
+ if (PIM_IF_FLAG_TEST_S_G_RPT(flags))
+ return "SGRpt(PP')";
+ else
+ return "PRUNEPT";
break;
}
ch = THREAD_ARG(t);
if (ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING) {
- /* Send PruneEcho(S,G) ? */
ifp = ch->interface;
pim_ifp = ifp->info;
- send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1);
-
- if (send_prune_echo) {
- struct pim_rpf rpf;
+ if (!PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) {
+ /* Send PruneEcho(S,G) ? */
+ send_prune_echo =
+ (listcount(pim_ifp->pim_neighbor_list) > 1);
+
+ if (send_prune_echo) {
+ struct pim_rpf rpf;
+
+ rpf.source_nexthop.interface = ifp;
+ rpf.rpf_addr.u.prefix4 =
+ pim_ifp->primary_address;
+ pim_jp_agg_single_upstream_send(&rpf,
+ ch->upstream,
+ 0);
+ }
- rpf.source_nexthop.interface = ifp;
- rpf.rpf_addr.u.prefix4 = pim_ifp->primary_address;
- pim_jp_agg_single_upstream_send(&rpf, ch->upstream, 0);
- }
- /* If SGRpt flag is set on ifchannel, Trigger SGRpt
- message on RP path upon prune timer expiry.
- */
- if (PIM_IF_FLAG_TEST_S_G_RPT(ch->flags)) {
+ ifjoin_to_noinfo(ch, true);
+ } else {
+ /* If SGRpt flag is set on ifchannel, Trigger SGRpt
+ * message on RP path upon prune timer expiry.
+ */
+ ch->ifjoin_state = PIM_IFJOIN_PRUNE;
if (ch->upstream)
pim_upstream_update_join_desired(pim_ifp->pim,
ch->upstream);
- /*
- ch->ifjoin_state transition to NOINFO state
- ch_del is set to 0 for not deleteing from here.
- Holdtime expiry (ch_del set to 1) delete the entry.
- */
- ifjoin_to_noinfo(ch, false);
- } else
- ifjoin_to_noinfo(ch, true);
+ }
/* from here ch may have been deleted */
} else {
zlog_warn(
orig = ch = pim_ifchannel_find(ifp, sg);
if (!ch)
return;
-
ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO);
if (sg->src.s_addr == INADDR_ANY) {
* we get End of Message
*/
void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom,
- uint8_t source_flags, uint8_t join,
- uint8_t starg_alone)
+ uint8_t join)
{
struct pim_ifchannel *child;
struct listnode *ch_node;
+ struct pim_instance *pim =
+ ((struct pim_interface *)ch->interface->info)->pim;
if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
return;
for (ALL_LIST_ELEMENTS_RO(ch->sources, ch_node, child)) {
- /* Only *,G Join received and no (SG-RPT) prune.
- eom = 1, only (W,G) join_alone is true, WC and RPT are set.
- Scan all S,G associated to G and if any SG-RPT
- remove the SG-RPT flag.
- */
- if (eom && starg_alone && (source_flags & PIM_RPT_BIT_MASK)
- && (source_flags & PIM_WILDCARD_BIT_MASK)) {
- if (PIM_IF_FLAG_TEST_S_G_RPT(child->flags)) {
- struct pim_upstream *up = child->upstream;
-
- PIM_IF_FLAG_UNSET_S_G_RPT(child->flags);
- if (up) {
- if (PIM_DEBUG_TRACE)
- zlog_debug(
- "%s: SGRpt flag is cleared, add inherit oif to up %s",
- __PRETTY_FUNCTION__,
- up->sg_str);
- pim_channel_add_oif(
- up->channel_oil, ch->interface,
- PIM_OIF_FLAG_PROTO_STAR);
- pim_ifchannel_ifjoin_switch(
- __PRETTY_FUNCTION__, child,
- PIM_IFJOIN_JOIN);
- }
- }
- }
-
if (!PIM_IF_FLAG_TEST_S_G_RPT(child->flags))
continue;
break;
case PIM_IFJOIN_PRUNE_TMP:
case PIM_IFJOIN_PRUNE_PENDING_TMP:
- if (eom)
+ if (eom) {
+ struct pim_upstream *parent =
+ child->upstream->parent;
+
+ PIM_IF_FLAG_UNSET_S_G_RPT(child->flags);
child->ifjoin_state = PIM_IFJOIN_NOINFO;
+
+ if (I_am_RP(pim, child->sg.grp)) {
+ pim_channel_add_oif(
+ child->upstream->channel_oil,
+ ch->interface,
+ PIM_OIF_FLAG_PROTO_STAR);
+ pim_upstream_switch(
+ pim, child->upstream,
+ PIM_UPSTREAM_JOINED);
+ pim_jp_agg_single_upstream_send(
+ &child->upstream->rpf,
+ child->upstream, true);
+ }
+ if (parent)
+ pim_jp_agg_single_upstream_send(
+ &parent->rpf,
+ parent, true);
+ }
break;
}
}
void pim_ifchannel_scan_forward_start(struct interface *new_ifp);
void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom,
- uint8_t source_flags, uint8_t join,
- uint8_t starg_alone);
+ uint8_t join);
int pim_ifchannel_compare(const struct pim_ifchannel *ch1,
const struct pim_ifchannel *ch2);
uint16_t msg_num_pruned_sources;
int source;
struct pim_ifchannel *starg_ch = NULL, *sg_ch = NULL;
- uint8_t starg_alone = 0;
memset(&sg, 0, sizeof(struct prefix_sg));
addr_offset = pim_parse_addr_group(&sg, buf, pastend - buf);
msg_source_flags);
if (sg.src.s_addr == INADDR_ANY) {
- starg_alone = 1;
starg_ch = pim_ifchannel_find(ifp, &sg);
if (starg_ch)
pim_ifchannel_set_star_g_join_state(
- starg_ch, 0, msg_source_flags,
- 1, starg_alone);
+ starg_ch, 0, 1);
}
}
}
buf += addr_offset;
- starg_alone = 0;
recv_prune(ifp, neigh, msg_holdtime,
msg_upstream_addr.u.prefix4, &sg,
msg_source_flags);
}
}
if (starg_ch)
- pim_ifchannel_set_star_g_join_state(
- starg_ch, 1, msg_source_flags, 0, starg_alone);
+ pim_ifchannel_set_star_g_join_state(starg_ch, 1, 0);
starg_ch = NULL;
} /* scan groups */
struct pim_jp_agg_group *group;
struct pim_interface *pim_ifp = NULL;
struct pim_jp_groups *grp = NULL;
- struct pim_jp *msg;
+ struct pim_jp *msg = NULL;
struct listnode *node, *nnode;
uint8_t pim_msg[10000];
uint8_t *curr_ptr = pim_msg;
if (up->sources)
list_delete(up->sources);
+ list_delete(up->ifchannels);
+
hash_release(pim->upstream_hash, up);
XFREE(MTYPE_PIM_UPSTREAM, up);
return NULL;
// No packet can have arrived here if this is the case
if (!up->channel_oil->installed) {
if (PIM_DEBUG_TRACE)
- zlog_debug("%s: %s is not installed in mroute",
- __PRETTY_FUNCTION__, up->sg_str);
+ zlog_debug("%s: %s[%s] is not installed in mroute",
+ __PRETTY_FUNCTION__,
+ up->sg_str, pim->vrf->name);
return;
}
deref = ''
drop_str = False
+ canfail = True
class StringHandler(RenderHandler):
argtype = 'const char *'
decl = Template('const char *$varname = NULL;')
code = Template('$varname = argv[_i]->arg;')
drop_str = True
+ canfail = False
class LongHandler(RenderHandler):
argtype = 'long'
}
# core template invoked for each occurence of DEFPY.
+#
+# the "#if $..." bits are there to keep this template unified into one
+# common form, without requiring a more advanced template engine (e.g.
+# jinja2)
templ = Template('''/* $fnname => "$cmddef" */
DEFUN_CMD_FUNC_DECL($fnname)
#define funcdecl_$fnname static int ${fnname}_magic(\\
funcdecl_$fnname;
DEFUN_CMD_FUNC_TEXT($fnname)
{
+#if $nonempty /* anything to parse? */
int _i;
+#if $canfail /* anything that can fail? */
unsigned _fail = 0, _failcnt = 0;
+#endif
$argdecls
for (_i = 0; _i < argc; _i++) {
if (!argv[_i]->varname)
continue;
- _fail = 0;$argblocks
+#if $canfail /* anything that can fail? */
+ _fail = 0;
+#endif
+$argblocks
+#if $canfail /* anything that can fail? */
if (_fail)
vty_out (vty, "%% invalid input for %s: %s\\n",
argv[_i]->varname, argv[_i]->arg);
_failcnt += _fail;
+#endif
}
+#if $canfail /* anything that can fail? */
if (_failcnt)
return CMD_WARNING;
+#endif
+#endif
return ${fnname}_magic(self, vty, argc, argv$arglist);
}
arglist = []
argblocks = []
doc = []
+ canfail = 0
def do_add(handler, varname, attr = ''):
argdefs.append(',\\\n\t%s %s%s' % (handler.argtype, varname, attr))
if handler is None: continue
do_add(handler, varname)
code = handler.code.substitute({'varname': varname}).replace('\n', '\n\t\t\t')
+ if handler.canfail:
+ canfail = 1
strblock = ''
if not handler.drop_str:
do_add(StringHandler(None), '%s_str' % (varname), ' __attribute__ ((unused))')
params['argdecls'] = ''.join(argdecls)
params['arglist'] = ''.join(arglist)
params['argblocks'] = ''.join(argblocks)
+ params['canfail'] = canfail
+ params['nonempty'] = len(argblocks)
ofd.write(templ.substitute(params))
if __name__ == '__main__':
process_file(args.cfile, ofd, dumpfd, args.all_defun)
if args.o is not None:
- clippy.wrdiff(args.o, ofd)
+ clippy.wrdiff(args.o, ofd, [args.cfile, os.path.realpath(__file__)])
# 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
+import os, stat
import _clippy
from _clippy import parse, Graph, GraphNode
for i, depth in graph_iterate(graph):
print('\t%s%s %r' % (' ' * (depth * 2), i.type, i.text))
-def wrdiff(filename, buf):
+def wrdiff(filename, buf, reffiles = []):
'''write buffer to file if contents changed'''
expl = ''
try: old = open(filename, 'r').read()
except: pass
if old == buf:
+ for reffile in reffiles:
+ # ensure output timestamp is newer than inputs, for make
+ reftime = os.stat(reffile)[stat.ST_MTIME]
+ outtime = os.stat(filename)[stat.ST_MTIME]
+ if outtime <= reftime:
+ os.utime(filename, (reftime + 1, reftime + 1))
# sys.stderr.write('%s unchanged, not written\n' % (filename))
return
- with open('.new.' + filename, 'w') as out:
+
+ newname = '%s.new-%d' % (filename, os.getpid())
+ with open(newname, 'w') as out:
out.write(buf)
- os.rename('.new.' + filename, filename)
+ os.rename(newname, filename)
%{!?with_pam: %global with_pam 0 }
%{!?with_ospfclient: %global with_ospfclient 1 }
%{!?with_ospfapi: %global with_ospfapi 1 }
-%{!?with_irdp: %global with_irdp 1 }
%{!?with_rtadv: %global with_rtadv 1 }
%{!?with_ldpd: %global with_ldpd 1 }
%{!?with_nhrpd: %global with_nhrpd 1 }
--libexecdir=%{_libexecdir} \
--localstatedir=%{_localstatedir} \
--disable-werror \
+ --enable-irdp \
%if !%{with_shared}
--disable-shared \
%endif
%else
--enable-ospfapi=no \
%endif
-%if %{with_irdp}
- --enable-irdp=yes \
-%else
- --enable-irdp=no \
-%endif
%if %{with_rtadv}
--enable-rtadv=yes \
%else
# Remove debian init script if it was installed
rm -f %{buildroot}%{_sbindir}/frr
+# kill bogus libtool files for modules
+rm -f %{buildroot}%{_libdir}/frr/modules/*.la
+
# install /etc sources
%if "%{initsystem}" == "systemd"
mkdir -p %{buildroot}%{_unitdir}
%{_libdir}/lib*.so.0
%attr(755,root,root) %{_libdir}/lib*.so.0.*
%endif
+%attr(755,root,root) %{_libdir}/frr/modules/zebra_irdp.so
%{_bindir}/*
%config(noreplace) /etc/frr/[!v]*.conf*
%config(noreplace) %attr(750,%frr_user,%frr_user) /etc/frr/daemons
unsigned long rip_debug_packet = 0;
unsigned long rip_debug_zebra = 0;
-DEFUN (show_debugging_rip,
- show_debugging_rip_cmd,
- "show debugging rip",
- SHOW_STR
- DEBUG_STR
- RIP_STR)
+DEFUN_NOSH (show_debugging_rip,
+ show_debugging_rip_cmd,
+ "show debugging [rip]",
+ SHOW_STR
+ DEBUG_STR
+ RIP_STR)
{
vty_out(vty, "RIP debugging status:\n");
void rip_if_init(void)
{
/* Default initial size of interface vector. */
- if_add_hook(IF_NEW_HOOK, rip_interface_new_hook);
- if_add_hook(IF_DELETE_HOOK, rip_interface_delete_hook);
+ hook_register_prio(if_add, 0, rip_interface_new_hook);
+ hook_register_prio(if_del, 0, rip_interface_delete_hook);
/* RIP network init. */
rip_enable_interface = vector_init(1);
/* Send ECMP routes to zebra. */
static void rip_zebra_ipv4_send(struct route_node *rp, u_char cmd)
{
- static struct in_addr **nexthops = NULL;
- static unsigned int nexthops_len = 0;
-
struct list *list = (struct list *)rp->info;
- struct zapi_ipv4 api;
+ struct zapi_route api;
+ struct zapi_nexthop *api_nh;
struct listnode *listnode = NULL;
struct rip_info *rinfo = NULL;
int count = 0;
- if (vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_RIP],
- VRF_DEFAULT)) {
- api.vrf_id = VRF_DEFAULT;
- api.type = ZEBRA_ROUTE_RIP;
- api.instance = 0;
- api.flags = 0;
- api.message = 0;
- api.safi = SAFI_UNICAST;
-
- if (nexthops_len < listcount(list)) {
- nexthops_len = listcount(list);
- nexthops = XREALLOC(MTYPE_TMP, nexthops,
- nexthops_len
- * sizeof(struct in_addr *));
- }
-
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
- for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
- nexthops[count++] = &rinfo->nexthop;
- if (cmd == ZEBRA_IPV4_ROUTE_ADD)
- SET_FLAG(rinfo->flags, RIP_RTF_FIB);
- else
- UNSET_FLAG(rinfo->flags, RIP_RTF_FIB);
- }
-
- api.nexthop = nexthops;
- api.nexthop_num = count;
- api.ifindex_num = 0;
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = VRF_DEFAULT;
+ api.type = ZEBRA_ROUTE_RIP;
+ api.safi = SAFI_UNICAST;
+
+ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+ for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
+ api_nh = &api.nexthops[count];
+ api_nh->gate.ipv4 = rinfo->nexthop;
+ api_nh->type = NEXTHOP_TYPE_IPV4;
+ if (cmd == ZEBRA_ROUTE_ADD)
+ SET_FLAG(rinfo->flags, RIP_RTF_FIB);
+ else
+ UNSET_FLAG(rinfo->flags, RIP_RTF_FIB);
+ count++;
+ }
- rinfo = listgetdata(listhead(list));
+ api.prefix = rp->p;
+ api.nexthop_num = count;
- SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
- api.metric = rinfo->metric;
+ rinfo = listgetdata(listhead(list));
- if (rinfo->distance
- && rinfo->distance != ZEBRA_RIP_DISTANCE_DEFAULT) {
- SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
- api.distance = rinfo->distance;
- }
+ SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
+ api.metric = rinfo->metric;
- if (rinfo->tag) {
- SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
- api.tag = rinfo->tag;
- }
+ if (rinfo->distance && rinfo->distance != ZEBRA_RIP_DISTANCE_DEFAULT) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
+ api.distance = rinfo->distance;
+ }
- zapi_ipv4_route(cmd, zclient, (struct prefix_ipv4 *)&rp->p,
- &api);
-
- if (IS_RIP_DEBUG_ZEBRA) {
- if (rip->ecmp)
- zlog_debug("%s: %s/%d nexthops %d",
- (cmd == ZEBRA_IPV4_ROUTE_ADD)
- ? "Install into zebra"
- : "Delete from zebra",
- inet_ntoa(rp->p.u.prefix4),
- rp->p.prefixlen, count);
- else
- zlog_debug("%s: %s/%d",
- (cmd == ZEBRA_IPV4_ROUTE_ADD)
- ? "Install into zebra"
- : "Delete from zebra",
- inet_ntoa(rp->p.u.prefix4),
- rp->p.prefixlen);
- }
+ if (rinfo->tag) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+ api.tag = rinfo->tag;
+ }
- rip_global_route_changes++;
+ zclient_route_send(cmd, zclient, &api);
+
+ if (IS_RIP_DEBUG_ZEBRA) {
+ if (rip->ecmp)
+ zlog_debug("%s: %s/%d nexthops %d",
+ (cmd == ZEBRA_ROUTE_ADD)
+ ? "Install into zebra"
+ : "Delete from zebra",
+ inet_ntoa(rp->p.u.prefix4), rp->p.prefixlen,
+ count);
+ else
+ zlog_debug("%s: %s/%d",
+ (cmd == ZEBRA_ROUTE_ADD)
+ ? "Install into zebra"
+ : "Delete from zebra",
+ inet_ntoa(rp->p.u.prefix4), rp->p.prefixlen);
}
+
+ rip_global_route_changes++;
}
/* Add/update ECMP routes to zebra. */
void rip_zebra_ipv4_add(struct route_node *rp)
{
- rip_zebra_ipv4_send(rp, ZEBRA_IPV4_ROUTE_ADD);
+ rip_zebra_ipv4_send(rp, ZEBRA_ROUTE_ADD);
}
/* Delete ECMP routes from zebra. */
void rip_zebra_ipv4_delete(struct route_node *rp)
{
- rip_zebra_ipv4_send(rp, ZEBRA_IPV4_ROUTE_DELETE);
+ rip_zebra_ipv4_send(rp, ZEBRA_ROUTE_DELETE);
}
/* Zebra route add and delete treatment. */
-static int rip_zebra_read_ipv4(int command, struct zclient *zclient,
- zebra_size_t length, vrf_id_t vrf_id)
+static int rip_zebra_read_route(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
{
- struct stream *s;
- struct zapi_ipv4 api;
- unsigned long ifindex;
+ struct zapi_route api;
struct in_addr nexthop;
- struct prefix_ipv4 p;
+ unsigned long ifindex;
if (!rip)
return 0;
- s = zclient->ibuf;
- ifindex = 0;
- nexthop.s_addr = 0;
-
- /* Type, flags, message. */
- api.type = stream_getc(s);
- api.instance = stream_getw(s);
- api.flags = stream_getl(s);
- api.message = stream_getc(s);
-
- /* 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));
-
- /* 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);
- }
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
- api.distance = stream_getc(s);
- else
- api.distance = 255;
- 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 (zapi_route_decode(zclient->ibuf, &api) < 0)
+ return -1;
+
+ nexthop = api.nexthops[0].gate.ipv4;
+ ifindex = api.nexthops[0].ifindex;
/* Then fetch IPv4 prefixes. */
- if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD)
- rip_redistribute_add(api.type, RIP_ROUTE_REDISTRIBUTE, &p,
- ifindex, &nexthop, api.metric,
- api.distance, api.tag);
- else if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL)
- rip_redistribute_delete(api.type, RIP_ROUTE_REDISTRIBUTE, &p,
+ if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
+ rip_redistribute_add(api.type, RIP_ROUTE_REDISTRIBUTE,
+ (struct prefix_ipv4 *)&api.prefix, ifindex,
+ &nexthop, api.metric, api.distance,
+ api.tag);
+ else if (command == ZEBRA_REDISTRIBUTE_ROUTE_DEL)
+ rip_redistribute_delete(api.type, RIP_ROUTE_REDISTRIBUTE,
+ (struct prefix_ipv4 *)&api.prefix,
ifindex);
return 0;
}
}
-DEFUN (rip_redistribute_rip,
- rip_redistribute_rip_cmd,
- "redistribute rip",
- "Redistribute information from another routing protocol\n"
- "Routing Information Protocol (RIP)\n")
-{
- vrf_bitmap_set(zclient->redist[AFI_IP][ZEBRA_ROUTE_RIP], VRF_DEFAULT);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_rip_redistribute_rip,
- no_rip_redistribute_rip_cmd,
- "no redistribute rip",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "Routing Information Protocol (RIP)\n")
-{
- vrf_bitmap_unset(zclient->redist[AFI_IP][ZEBRA_ROUTE_RIP], VRF_DEFAULT);
- return CMD_SUCCESS;
-}
-
DEFUN (rip_redistribute_type,
rip_redistribute_type_cmd,
"redistribute " FRR_REDIST_STR_RIPD,
return CMD_SUCCESS;
}
-/* RIP configuration write function. */
-static int config_write_zebra(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_RIP],
- VRF_DEFAULT)) {
- vty_out(vty, "router zebra\n");
- vty_out(vty, " no redistribute rip\n");
- return 1;
- }
- return 0;
-}
-
int config_write_rip_redistribute(struct vty *vty, int config_mode)
{
int i;
- for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
- if (i != zclient->redist_default
- && vrf_bitmap_check(zclient->redist[AFI_IP][i],
- VRF_DEFAULT)) {
- if (config_mode) {
- if (rip->route_map[i].metric_config) {
- if (rip->route_map[i].name)
- vty_out(vty,
- " redistribute %s metric %d route-map %s\n",
- zebra_route_string(i),
- rip->route_map[i]
- .metric,
- rip->route_map[i].name);
- else
- vty_out(vty,
- " redistribute %s metric %d\n",
- zebra_route_string(i),
- rip->route_map[i]
- .metric);
- } else {
- if (rip->route_map[i].name)
- vty_out(vty,
- " redistribute %s route-map %s\n",
- zebra_route_string(i),
- rip->route_map[i].name);
- else
- vty_out(vty,
- " redistribute %s\n",
- zebra_route_string(i));
- }
- } else
- vty_out(vty, " %s", zebra_route_string(i));
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+ if (i == zclient->redist_default
+ || !vrf_bitmap_check(zclient->redist[AFI_IP][i],
+ VRF_DEFAULT))
+ continue;
+
+ if (!config_mode) {
+ vty_out(vty, " %s", zebra_route_string(i));
+ continue;
+ }
+
+ if (rip->route_map[i].metric_config) {
+ if (rip->route_map[i].name)
+ vty_out(vty,
+ " redistribute %s metric %d route-map %s\n",
+ zebra_route_string(i),
+ rip->route_map[i].metric,
+ rip->route_map[i].name);
+ else
+ vty_out(vty, " redistribute %s metric %d\n",
+ zebra_route_string(i),
+ rip->route_map[i].metric);
+ } else {
+ if (rip->route_map[i].name)
+ vty_out(vty, " redistribute %s route-map %s\n",
+ zebra_route_string(i),
+ rip->route_map[i].name);
+ else
+ vty_out(vty, " redistribute %s\n",
+ zebra_route_string(i));
}
+ }
+
return 0;
}
-/* Zebra node structure. */
-static struct cmd_node zebra_node = {
- ZEBRA_NODE, "%s(config-router)# ",
-};
-
static void rip_zebra_connected(struct zclient *zclient)
{
zclient_send_reg_requests(zclient, VRF_DEFAULT);
zclient->interface_address_delete = rip_interface_address_delete;
zclient->interface_up = rip_interface_up;
zclient->interface_down = rip_interface_down;
- zclient->redistribute_route_ipv4_add = rip_zebra_read_ipv4;
- zclient->redistribute_route_ipv4_del = rip_zebra_read_ipv4;
-
- /* Install zebra node. */
- install_node(&zebra_node, config_write_zebra);
-
- /* Install command elements to zebra node. */
- install_default(ZEBRA_NODE);
- install_element(ZEBRA_NODE, &rip_redistribute_rip_cmd);
- install_element(ZEBRA_NODE, &no_rip_redistribute_rip_cmd);
+ zclient->redistribute_route_add = rip_zebra_read_route;
+ zclient->redistribute_route_del = rip_zebra_read_route;
/* Install command elements to rip node. */
install_element(RIP_NODE, &rip_redistribute_type_cmd);
unsigned long ripng_debug_packet = 0;
unsigned long ripng_debug_zebra = 0;
-DEFUN (show_debugging_ripng,
- show_debugging_ripng_cmd,
- "show debugging ripng",
- SHOW_STR
- DEBUG_STR
- "RIPng configuration\n")
+DEFUN_NOSH (show_debugging_ripng,
+ show_debugging_ripng_cmd,
+ "show debugging [ripng]",
+ SHOW_STR
+ DEBUG_STR
+ "RIPng configuration\n")
{
vty_out(vty, "RIPng debugging status:\n");
void ripng_if_init()
{
/* Interface initialize. */
- if_add_hook(IF_NEW_HOOK, ripng_if_new_hook);
- if_add_hook(IF_DELETE_HOOK, ripng_if_delete_hook);
+ hook_register_prio(if_add, 0, ripng_if_new_hook);
+ hook_register_prio(if_del, 0, ripng_if_delete_hook);
/* RIPng enable network init. */
ripng_enable_network = route_table_init();
/* Send ECMP routes to zebra. */
static void ripng_zebra_ipv6_send(struct route_node *rp, u_char cmd)
{
- static struct in6_addr **nexthops = NULL;
- static ifindex_t *ifindexes = NULL;
- static unsigned int nexthops_len = 0;
-
struct list *list = (struct list *)rp->info;
- struct zapi_ipv6 api;
+ struct zapi_route api;
+ struct zapi_nexthop *api_nh;
struct listnode *listnode = NULL;
struct ripng_info *rinfo = NULL;
int count = 0;
- if (vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_RIPNG],
- VRF_DEFAULT)) {
- api.vrf_id = VRF_DEFAULT;
- api.type = ZEBRA_ROUTE_RIPNG;
- api.instance = 0;
- api.flags = 0;
- api.message = 0;
- api.safi = SAFI_UNICAST;
-
- if (nexthops_len < listcount(list)) {
- nexthops_len = listcount(list);
- nexthops = XREALLOC(
- MTYPE_TMP, nexthops,
- nexthops_len * sizeof(struct in6_addr *));
- ifindexes =
- XREALLOC(MTYPE_TMP, ifindexes,
- nexthops_len * sizeof(unsigned int));
- }
-
- SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
- SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX);
- for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
- nexthops[count] = &rinfo->nexthop;
- ifindexes[count] = rinfo->ifindex;
- count++;
- if (cmd == ZEBRA_IPV6_ROUTE_ADD)
- SET_FLAG(rinfo->flags, RIPNG_RTF_FIB);
- else
- UNSET_FLAG(rinfo->flags, RIPNG_RTF_FIB);
- }
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = VRF_DEFAULT;
+ api.type = ZEBRA_ROUTE_RIPNG;
+ api.safi = SAFI_UNICAST;
+ api.prefix = rp->p;
+
+ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+ for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
+ api_nh = &api.nexthops[count];
+ api_nh->gate.ipv6 = rinfo->nexthop;
+ api_nh->ifindex = rinfo->ifindex;
+ api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ count++;
+ if (cmd == ZEBRA_ROUTE_ADD)
+ SET_FLAG(rinfo->flags, RIPNG_RTF_FIB);
+ else
+ UNSET_FLAG(rinfo->flags, RIPNG_RTF_FIB);
+ }
- api.nexthop = nexthops;
- api.nexthop_num = count;
- api.ifindex = ifindexes;
- api.ifindex_num = count;
+ api.nexthop_num = count;
- rinfo = listgetdata(listhead(list));
+ rinfo = listgetdata(listhead(list));
- SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
- api.metric = rinfo->metric;
+ SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
+ api.metric = rinfo->metric;
- if (rinfo->tag) {
- SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
- api.tag = rinfo->tag;
- }
+ if (rinfo->tag) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+ api.tag = rinfo->tag;
+ }
- zapi_ipv6_route(cmd, zclient, (struct prefix_ipv6 *)&rp->p,
- NULL, &api);
-
- if (IS_RIPNG_DEBUG_ZEBRA) {
- if (ripng->ecmp)
- zlog_debug("%s: %s/%d nexthops %d",
- (cmd == ZEBRA_IPV6_ROUTE_ADD)
- ? "Install into zebra"
- : "Delete from zebra",
- inet6_ntoa(rp->p.u.prefix6),
- rp->p.prefixlen, count);
- else
- zlog_debug("%s: %s/%d",
- (cmd == ZEBRA_IPV6_ROUTE_ADD)
- ? "Install into zebra"
- : "Delete from zebra",
- inet6_ntoa(rp->p.u.prefix6),
- rp->p.prefixlen);
- }
+ zclient_route_send(cmd, zclient, &api);
+
+ if (IS_RIPNG_DEBUG_ZEBRA) {
+ if (ripng->ecmp)
+ zlog_debug("%s: %s/%d nexthops %d",
+ (cmd == ZEBRA_ROUTE_ADD)
+ ? "Install into zebra"
+ : "Delete from zebra",
+ inet6_ntoa(rp->p.u.prefix6), rp->p.prefixlen,
+ count);
+ else
+ zlog_debug(
+ "%s: %s/%d",
+ (cmd == ZEBRA_ROUTE_ADD) ? "Install into zebra"
+ : "Delete from zebra",
+ inet6_ntoa(rp->p.u.prefix6), rp->p.prefixlen);
}
}
/* Add/update ECMP routes to zebra. */
void ripng_zebra_ipv6_add(struct route_node *rp)
{
- ripng_zebra_ipv6_send(rp, ZEBRA_IPV6_ROUTE_ADD);
+ ripng_zebra_ipv6_send(rp, ZEBRA_ROUTE_ADD);
}
/* Delete ECMP routes from zebra. */
void ripng_zebra_ipv6_delete(struct route_node *rp)
{
- ripng_zebra_ipv6_send(rp, ZEBRA_IPV6_ROUTE_DELETE);
+ ripng_zebra_ipv6_send(rp, ZEBRA_ROUTE_DELETE);
}
/* Zebra route add and delete treatment. */
-static int ripng_zebra_read_ipv6(int command, struct zclient *zclient,
- zebra_size_t length, vrf_id_t vrf_id)
+static int ripng_zebra_read_route(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
{
- struct stream *s;
- struct zapi_ipv6 api;
- unsigned long ifindex;
+ struct zapi_route api;
struct in6_addr nexthop;
- struct prefix_ipv6 p, src_p;
-
- s = zclient->ibuf;
- ifindex = 0;
- 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));
- }
+ unsigned long ifindex;
- if (src_p.prefixlen)
- /* we completely ignore srcdest routes for now. */
- return 0;
+ if (zapi_route_decode(zclient->ibuf, &api) < 0)
+ return -1;
- /* 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);
- }
- 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;
+ /* we completely ignore srcdest routes for now. */
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
+ return 0;
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG))
- api.tag = stream_getl(s);
- else
- api.tag = 0;
+ nexthop = api.nexthops[0].gate.ipv6;
+ ifindex = api.nexthops[0].ifindex;
- if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
- ripng_redistribute_add(api.type, RIPNG_ROUTE_REDISTRIBUTE, &p,
+ if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
+ ripng_redistribute_add(api.type, RIPNG_ROUTE_REDISTRIBUTE,
+ (struct prefix_ipv6 *)&api.prefix,
ifindex, &nexthop, api.tag);
else
ripng_redistribute_delete(api.type, RIPNG_ROUTE_REDISTRIBUTE,
- &p, ifindex);
+ (struct prefix_ipv6 *)&api.prefix,
+ ifindex);
return 0;
}
}
}
-DEFUN (ripng_redistribute_ripng,
- ripng_redistribute_ripng_cmd,
- "redistribute ripng",
- "Redistribute information from another routing protocol\n"
- "RIPng route\n")
-{
- vrf_bitmap_set(zclient->redist[AFI_IP6][ZEBRA_ROUTE_RIPNG],
- VRF_DEFAULT);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_ripng_redistribute_ripng,
- no_ripng_redistribute_ripng_cmd,
- "no redistribute ripng",
- NO_STR
- "Redistribute information from another routing protocol\n"
- "RIPng route\n")
-{
- vrf_bitmap_unset(zclient->redist[AFI_IP6][ZEBRA_ROUTE_RIPNG],
- VRF_DEFAULT);
- return CMD_SUCCESS;
-}
-
DEFUN (ripng_redistribute_type,
ripng_redistribute_type_cmd,
"redistribute " FRR_REDIST_STR_RIPNGD,
{
int i;
- for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
- if (i != zclient->redist_default
- && vrf_bitmap_check(zclient->redist[AFI_IP6][i],
- VRF_DEFAULT)) {
- if (config_mode) {
- if (ripng->route_map[i].metric_config) {
- if (ripng->route_map[i].name)
- vty_out(vty,
- " redistribute %s metric %d route-map %s\n",
- zebra_route_string(i),
- ripng->route_map[i]
- .metric,
- ripng->route_map[i]
- .name);
- else
- vty_out(vty,
- " redistribute %s metric %d\n",
- zebra_route_string(i),
- ripng->route_map[i]
- .metric);
- } else {
- if (ripng->route_map[i].name)
- vty_out(vty,
- " redistribute %s route-map %s\n",
- zebra_route_string(i),
- ripng->route_map[i]
- .name);
- else
- vty_out(vty,
- " redistribute %s\n",
- zebra_route_string(i));
- }
- } else
- vty_out(vty, " %s", zebra_route_string(i));
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+ if (i == zclient->redist_default
+ || !vrf_bitmap_check(zclient->redist[AFI_IP6][i],
+ VRF_DEFAULT))
+ continue;
+
+ if (!config_mode) {
+ vty_out(vty, " %s", zebra_route_string(i));
+ continue;
}
-}
-/* RIPng configuration write function. */
-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_IP6][ZEBRA_ROUTE_RIPNG],
- VRF_DEFAULT)) {
- vty_out(vty, "router zebra\n");
- vty_out(vty, " no redistribute ripng\n");
- return 1;
+ if (ripng->route_map[i].metric_config) {
+ if (ripng->route_map[i].name)
+ vty_out(vty,
+ " redistribute %s metric %d route-map %s\n",
+ zebra_route_string(i),
+ ripng->route_map[i].metric,
+ ripng->route_map[i].name);
+ else
+ vty_out(vty, " redistribute %s metric %d\n",
+ zebra_route_string(i),
+ ripng->route_map[i].metric);
+ } else {
+ if (ripng->route_map[i].name)
+ vty_out(vty, " redistribute %s route-map %s\n",
+ zebra_route_string(i),
+ ripng->route_map[i].name);
+ else
+ vty_out(vty, " redistribute %s\n",
+ zebra_route_string(i));
+ }
}
- return 0;
}
-/* Zebra node structure. */
-static struct cmd_node zebra_node = {
- ZEBRA_NODE, "%s(config-router)# ",
-};
-
static void ripng_zebra_connected(struct zclient *zclient)
{
zclient_send_reg_requests(zclient, VRF_DEFAULT);
zclient->interface_delete = ripng_interface_delete;
zclient->interface_address_add = ripng_interface_address_add;
zclient->interface_address_delete = ripng_interface_address_delete;
- zclient->redistribute_route_ipv6_add = ripng_zebra_read_ipv6;
- zclient->redistribute_route_ipv6_del = ripng_zebra_read_ipv6;
-
- /* Install zebra node. */
- install_node(&zebra_node, zebra_config_write);
-
- /* Install command element for zebra node. */
- install_default(ZEBRA_NODE);
- install_element(ZEBRA_NODE, &ripng_redistribute_ripng_cmd);
- install_element(ZEBRA_NODE, &no_ripng_redistribute_ripng_cmd);
+ zclient->redistribute_route_add = ripng_zebra_read_route;
+ zclient->redistribute_route_del = ripng_zebra_read_route;
/* Install command elements to ripng node */
install_element(RIPNG_NODE, &ripng_redistribute_type_cmd);
/lib/test_timer_correctness
/lib/test_timer_performance
/lib/test_ttable
+/lib/test_zmq
/ospf6d/test_lsdb
$(TESTS_OSPF6D) \
# end
+if ZEROMQ
+check_PROGRAMS += \
+ lib/test_zmq \
+ # end
+endif
+
../vtysh/vtysh_cmd.c:
$(MAKE) -C ../vtysh vtysh_cmd.c
lib_test_timer_performance_SOURCES = lib/test_timer_performance.c \
helpers/c/prng.c
lib_test_ttable_SOURCES = lib/test_ttable.c
+lib_test_zmq_SOURCES = lib/test_zmq.c
+lib_test_zmq_CFLAGS = $(AM_CFLAGS) $(ZEROMQ_CFLAGS)
lib_cli_test_cli_SOURCES = lib/cli/test_cli.c lib/cli/common_cli.c
lib_cli_test_commands_SOURCES = lib/cli/test_commands_defun.c \
lib/cli/test_commands.c \
lib_test_timer_correctness_LDADD = $(ALL_TESTS_LDADD)
lib_test_timer_performance_LDADD = $(ALL_TESTS_LDADD)
lib_test_ttable_LDADD = $(ALL_TESTS_LDADD)
+lib_test_zmq_LDADD = ../lib/libfrrzmq.la $(ALL_TESTS_LDADD) $(ZEROMQ_LIBS)
lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD)
lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD)
bgpd_test_aspath_LDADD = $(BGP_TEST_LDADD)
static void show_meminfo_at_exit(void)
{
- log_memstats_stderr("isis fuzztest");
+ log_memstats(stderr, "isis fuzztest");
}
static int comp_line(const void *p1, const void *p2)
thread_master_free(master);
closezlog();
- log_memstats_stderr("testcli");
+ log_memstats(stderr, "testcli");
if (!isexit)
exit(0);
}
@pytest.mark.skipif('QUAGGA_TEST_COMMANDS' not in os.environ,
reason='QUAGGA_TEST_COMMANDS not set')
def test_refout(self):
- return super(TestCommands, self).test_refout(self)
+ return super(TestCommands, self).test_refout()
--- /dev/null
+/*
+ * ZeroMQ event test
+ * Copyright (C) 2017 David Lamparter, for NetDEF, Inc.
+ *
+ * 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 "memory.h"
+#include "sigevent.h"
+#include "frr_zmq.h"
+
+DEFINE_MTYPE_STATIC(LIB, TESTBUF, "zmq test buffer")
+
+static struct thread_master *master;
+
+static void msg_buf_free(void *data, void *hint)
+{
+ XFREE(MTYPE_TESTBUF, data);
+}
+
+static void run_client(int syncfd)
+{
+ int i, j;
+ char buf[32];
+ char dummy;
+ void *zmqctx = NULL;
+ void *zmqsock;
+
+ read(syncfd, &dummy, 1);
+
+ zmqctx = zmq_ctx_new();
+ zmq_ctx_set(zmqctx, ZMQ_IPV6, 1);
+
+ zmqsock = zmq_socket(zmqctx, ZMQ_REQ);
+ if (zmq_connect(zmqsock, "tcp://127.0.0.1:17171")) {
+ perror("zmq_connect");
+ exit(1);
+ }
+
+ /* single-part */
+ for (i = 0; i < 8; i++) {
+ snprintf(buf, sizeof(buf), "msg #%d %c%c%c",
+ i, 'a' + i, 'b' + i, 'c' + i);
+ printf("client send: %s\n", buf);
+ fflush(stdout);
+ zmq_send(zmqsock, buf, strlen(buf) + 1, 0);
+ zmq_recv(zmqsock, buf, sizeof(buf), 0);
+ printf("client recv: %s\n", buf);
+ }
+
+ /* multipart */
+ for (i = 2; i < 5; i++) {
+ int more;
+
+ printf("---\n");
+ for (j = 1; j <= i; j++) {
+ zmq_msg_t part;
+ char *dyn = XMALLOC(MTYPE_TESTBUF, 32);
+
+ snprintf(dyn, 32, "part %d/%d", j, i);
+ printf("client send: %s\n", dyn);
+ fflush(stdout);
+
+ zmq_msg_init_data(&part, dyn, strlen(dyn) + 1,
+ msg_buf_free, NULL);
+ zmq_msg_send(&part, zmqsock, j < i ? ZMQ_SNDMORE : 0);
+ }
+
+ zmq_msg_t part;
+ do {
+ char *data;
+
+ zmq_msg_recv(&part, zmqsock, 0);
+ data = zmq_msg_data(&part);
+ more = zmq_msg_more(&part);
+ printf("client recv (more: %d): %s\n", more, data);
+ } while (more);
+ zmq_msg_close(&part);
+ }
+ zmq_close(zmqsock);
+ zmq_ctx_term(zmqctx);
+}
+
+static struct frrzmq_cb *cb;
+
+static void serverpartfn(void *arg, void *zmqsock, zmq_msg_t *msg,
+ unsigned partnum)
+{
+ int more = zmq_msg_more(msg);
+ char *in = zmq_msg_data(msg);
+ size_t i;
+ zmq_msg_t reply;
+ char *out;
+
+ printf("server recv part %u (more: %d): %s\n", partnum, more, in);
+ fflush(stdout);
+ /* REQ-REP doesn't allow sending a reply here */
+ if (more)
+ return;
+
+ out = XMALLOC(MTYPE_TESTBUF, strlen(in) + 1);
+ for (i = 0; i < strlen(in); i++)
+ out[i] = toupper(in[i]);
+ out[i] = '\0';
+ zmq_msg_init_data(&reply, out, strlen(out) + 1, msg_buf_free, NULL);
+ zmq_msg_send(&reply, zmqsock, ZMQ_SNDMORE);
+
+ out = XMALLOC(MTYPE_TESTBUF, 32);
+ snprintf(out, 32, "msg# was %u", partnum);
+ zmq_msg_init_data(&reply, out, strlen(out) + 1, msg_buf_free, NULL);
+ zmq_msg_send(&reply, zmqsock, 0);
+}
+
+static void serverfn(void *arg, void *zmqsock)
+{
+ static int num = 0;
+
+ char buf[32];
+ size_t i;
+ zmq_recv(zmqsock, buf, sizeof(buf), 0);
+
+ printf("server recv: %s\n", buf);
+ fflush(stdout);
+ for (i = 0; i < strlen(buf); i++)
+ buf[i] = toupper(buf[i]);
+ zmq_send(zmqsock, buf, strlen(buf) + 1, 0);
+
+ if (++num < 4)
+ return;
+
+ /* change to multipart callback */
+ frrzmq_thread_cancel(cb);
+
+ cb = frrzmq_thread_add_read_part(master, serverpartfn, NULL, zmqsock);
+}
+
+static void sigchld(void)
+{
+ printf("child exited.\n");
+ frrzmq_thread_cancel(cb);
+}
+
+static struct quagga_signal_t sigs[] = {
+ {
+ .signal = SIGCHLD,
+ .handler = sigchld,
+ },
+};
+
+static void run_server(int syncfd)
+{
+ void *zmqsock;
+ char dummy = 0;
+ struct thread t;
+
+ master = thread_master_create(NULL);
+ signal_init(master, array_size(sigs), sigs);
+ frrzmq_init();
+
+ zmqsock = zmq_socket(frrzmq_context, ZMQ_REP);
+ if (zmq_bind(zmqsock, "tcp://*:17171")) {
+ perror("zmq_bind");
+ exit(1);
+ }
+
+ cb = frrzmq_thread_add_read_msg(master, serverfn, NULL, zmqsock);
+
+ write(syncfd, &dummy, sizeof(dummy));
+ while (thread_fetch(master, &t))
+ thread_call(&t);
+
+ zmq_close(zmqsock);
+ frrzmq_finish();
+ thread_master_free(master);
+ log_memstats_stderr("test");
+}
+
+int main(void)
+{
+ int syncpipe[2];
+ pid_t child;
+
+ if (pipe(syncpipe)) {
+ perror("pipe");
+ exit(1);
+ }
+
+ child = fork();
+ if (child < 0) {
+ perror("fork");
+ exit(1);
+ } else if (child == 0) {
+ run_client(syncpipe[0]);
+ exit(0);
+ }
+
+ run_server(syncpipe[1]);
+ exit(0);
+}
--- /dev/null
+import frrtest
+import pytest
+import os
+
+class TestZMQ(frrtest.TestRefOut):
+ program = './test_zmq'
+
+ @pytest.mark.skipif('S["ZEROMQ_TRUE"]=""\n' not in open('../config.status').readlines(),
+ reason='ZEROMQ not enabled')
+ def test_refout(self):
+ return super(TestZMQ, self).test_refout()
--- /dev/null
+client send: msg #0 abc
+server recv: msg #0 abc
+client recv: MSG #0 ABC
+client send: msg #1 bcd
+server recv: msg #1 bcd
+client recv: MSG #1 BCD
+client send: msg #2 cde
+server recv: msg #2 cde
+client recv: MSG #2 CDE
+client send: msg #3 def
+server recv: msg #3 def
+client recv: MSG #3 DEF
+client send: msg #4 efg
+server recv part 0 (more: 0): msg #4 efg
+client recv: MSG #4 EFG
+client send: msg #5 fgh
+client recv: msg# was 0
+client send: msg #6 ghi
+server recv part 0 (more: 0): msg #6 ghi
+client recv: MSG #6 GHI
+client send: msg #7 hij
+client recv: msg# was 0
+---
+client send: part 1/2
+client send: part 2/2
+server recv part 0 (more: 1): part 1/2
+server recv part 1 (more: 0): part 2/2
+client recv (more: 1): PART 2/2
+client recv (more: 0): msg# was 1
+---
+client send: part 1/3
+client send: part 2/3
+client send: part 3/3
+server recv part 0 (more: 1): part 1/3
+server recv part 1 (more: 1): part 2/3
+server recv part 2 (more: 0): part 3/3
+client recv (more: 1): PART 3/3
+client recv (more: 0): msg# was 2
+---
+client send: part 1/4
+client send: part 2/4
+client send: part 3/4
+client send: part 4/4
+server recv part 0 (more: 1): part 1/4
+server recv part 1 (more: 1): part 2/4
+server recv part 2 (more: 1): part 3/4
+server recv part 3 (more: 0): part 4/4
+client recv (more: 1): PART 4/4
+client recv (more: 0): msg# was 3
+child exited.
# returns: 0=ok, 1=error
check_daemon()
{
+ if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then
+ # check for daemon binary
+ if [ ! -x "$D_PATH/$1" ]; then return 1; fi
+ fi
+
# If the integrated config file is used the others are not checked.
if [ -r "$C_PATH/frr.conf" ]; then
return 0
# vtysh_enable has no config file nor binary so skip check.
# (Not sure why vtysh_enable is in this list but does not hurt)
if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then
- # check for daemon binary
- if [ ! -x "$D_PATH/$1" ]; then return 1; fi
-
# check for config file
if [ -n "$2" ]; then
if [ ! -r "$C_PATH/$1-$2.conf" ]; then
for line in lines_to_configure:
fh.write(line + '\n')
- output = subprocess.check_output(['/usr/bin/vtysh', '-f', filename])
-
- # exit non-zero if we see these errors
- for x in ('BGP instance name and AS number mismatch',
- 'BGP instance is already running',
- '% not a local address'):
- for line in output.splitlines():
- if x in line:
- msg = "ERROR: %s" % x
- log.error(msg)
- print msg
- reload_ok = False
-
+ try:
+ subprocess.check_output(['/usr/bin/vtysh', '-f', filename])
+ except subprocess.CalledProcessError as e:
+ log.warning("frr-reload.py failed due to\n%s" % e.output)
+ reload_ok = False
os.unlink(filename)
# Make these changes persistent
lineno, cmd_stat,
vtysh_client[i].name,
vty->buf);
+ retcode = cmd_stat;
break;
}
}
return ret;
}
+DEFUN (vtysh_show_debugging,
+ vtysh_show_debugging_cmd,
+ "show debugging",
+ SHOW_STR
+ DEBUG_STR)
+{
+ return show_per_daemon("do show debugging\n",
+ "Debugging Information for %s:\n");
+}
+
+DEFUN (vtysh_show_debugging_hashtable,
+ vtysh_show_debugging_hashtable_cmd,
+ "show debugging hashtable [statistics]",
+ SHOW_STR
+ DEBUG_STR
+ "Statistics about hash tables\n"
+ "Statistics about hash tables\n")
+{
+ return show_per_daemon("do show debugging hashtable\n",
+ "Hashtable statistics for %s:\n");
+}
+
/* Memory */
DEFUN (vtysh_show_memory,
vtysh_show_memory_cmd,
SHOW_STR
"Memory statistics\n")
{
- return show_per_daemon("show memory\n", "Memory statistics for %s:\n");
+ return show_per_daemon("show memory\n",
+ "Memory statistics for %s:\n");
}
DEFUN (vtysh_show_modules,
SHOW_STR
"Show current logging configuration\n")
{
- unsigned int i;
- int ret = CMD_SUCCESS;
- char line[] = "do show logging\n";
-
- for (i = 0; i < array_size(vtysh_client); i++)
- if (vtysh_client[i].fd >= 0) {
- fprintf(stdout, "Logging configuration for %s:\n",
- vtysh_client[i].name);
- ret = vtysh_client_execute(&vtysh_client[i], line,
- stdout);
- fprintf(stdout, "\n");
- }
-
- return ret;
+ return show_per_daemon("do show logging\n",
+ "Logging configuration for %s:\n");
}
DEFUNSH(VTYSH_ALL, vtysh_log_stdout, vtysh_log_stdout_cmd, "log stdout",
install_element(ENABLE_NODE, &vtysh_start_zsh_cmd);
#endif
+ install_element(VIEW_NODE, &vtysh_show_debugging_cmd);
+ install_element(VIEW_NODE, &vtysh_show_debugging_hashtable_cmd);
install_element(VIEW_NODE, &vtysh_show_memory_cmd);
install_element(VIEW_NODE, &vtysh_show_modules_cmd);
== 0
|| strncmp(line, "ip extcommunity-list",
strlen("ip extcommunity-list"))
- == 0)
+ == 0
+ || strncmp(line, "ip large-community-list",
+ strlen("ip large-community-list"))
+ == 0)
config = config_get(COMMUNITY_LIST_NODE, line);
else if (strncmp(line, "ip route", strlen("ip route")) == 0)
config = config_get(IP_NODE, line);
unsigned long zebra_debug_vxlan;
unsigned long zebra_debug_pw;
-DEFUN (show_debugging_zebra,
- show_debugging_zebra_cmd,
- "show debugging zebra",
- SHOW_STR
- "Debugging information\n"
- "Zebra configuration\n")
+DEFUN_NOSH (show_debugging_zebra,
+ show_debugging_zebra_cmd,
+ "show debugging [zebra]",
+ SHOW_STR
+ "Debugging information\n"
+ "Zebra configuration\n")
{
vty_out(vty, "Zebra debugging status:\n");
#define ZEBRA_PTM_SUPPORT
-#if defined(HAVE_RTADV)
-/* Order is intentional. Matches RFC4191. This array is also used for
- command matching, so only modify with care. */
-const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0};
-#endif /* HAVE_RTADV */
+DEFINE_HOOK(zebra_if_extra_info, (struct vty *vty, struct interface *ifp),
+ (vty, ifp))
+DEFINE_HOOK(zebra_if_config_wr, (struct vty *vty, struct interface *ifp),
+ (vty, ifp))
static void if_down_del_nbr_connected(struct interface *ifp);
vty_out(vty, "\n");
}
-#if defined(HAVE_RTADV)
-/* Dump interface ND information to vty. */
-static void nd_dump_vty(struct vty *vty, struct interface *ifp)
-{
- struct zebra_if *zif;
- struct rtadvconf *rtadv;
- int interval;
-
- zif = (struct zebra_if *)ifp->info;
- rtadv = &zif->rtadv;
-
- if (rtadv->AdvSendAdvertisements) {
- vty_out(vty,
- " ND advertised reachable time is %d milliseconds\n",
- rtadv->AdvReachableTime);
- vty_out(vty,
- " ND advertised retransmit interval is %d milliseconds\n",
- rtadv->AdvRetransTimer);
- vty_out(vty, " ND router advertisements sent: %d rcvd: %d\n",
- zif->ra_sent, zif->ra_rcvd);
- interval = rtadv->MaxRtrAdvInterval;
- if (interval % 1000)
- vty_out(vty,
- " ND router advertisements are sent every "
- "%d milliseconds\n",
- interval);
- else
- vty_out(vty,
- " ND router advertisements are sent every "
- "%d seconds\n",
- interval / 1000);
- if (rtadv->AdvDefaultLifetime != -1)
- vty_out(vty,
- " ND router advertisements live for %d seconds\n",
- rtadv->AdvDefaultLifetime);
- else
- vty_out(vty,
- " ND router advertisements lifetime tracks ra-interval\n");
- vty_out(vty,
- " ND router advertisement default router preference is "
- "%s\n",
- rtadv_pref_strs[rtadv->DefaultPreference]);
- if (rtadv->AdvManagedFlag)
- vty_out(vty,
- " Hosts use DHCP to obtain routable addresses.\n");
- else
- vty_out(vty,
- " Hosts use stateless autoconfig for addresses.\n");
- if (rtadv->AdvHomeAgentFlag) {
- vty_out(vty,
- " ND router advertisements with Home Agent flag bit set.\n");
- if (rtadv->HomeAgentLifetime != -1)
- vty_out(vty,
- " Home Agent lifetime is %u seconds\n",
- rtadv->HomeAgentLifetime);
- else
- vty_out(vty,
- " Home Agent lifetime tracks ra-lifetime\n");
- vty_out(vty, " Home Agent preference is %u\n",
- rtadv->HomeAgentPreference);
- }
- if (rtadv->AdvIntervalOption)
- vty_out(vty,
- " ND router advertisements with Adv. Interval option.\n");
- }
-}
-#endif /* HAVE_RTADV */
-
static const char *zebra_ziftype_2str(zebra_iftype_t zif_type)
{
switch (zif_type) {
inet_ntoa(iflp->rmt_ip), iflp->rmt_as);
}
-#ifdef RTADV
- nd_dump_vty(vty, ifp);
-#endif /* RTADV */
-#if defined(HAVE_RTADV)
- nd_dump_vty(vty, ifp);
-#endif /* HAVE_RTADV */
+ hook_call(zebra_if_extra_info, vty, ifp);
+
if (listhead(ifp->nbr_connected))
vty_out(vty, " Neighbor address(s):\n");
for (ALL_LIST_ELEMENTS_RO(ifp->nbr_connected, node, nbr_connected))
: "no ");
}
-#if defined(HAVE_RTADV)
- rtadv_config_write(vty, ifp);
-#endif /* HAVE_RTADV */
-
-#ifdef HAVE_IRDP
- irdp_config_write(vty, ifp);
-#endif /* IRDP */
+ hook_call(zebra_if_config_wr, vty, ifp);
link_params_config_write(vty, ifp);
void zebra_if_init(void)
{
/* Initialize interface and new hook. */
- if_add_hook(IF_NEW_HOOK, if_zebra_new_hook);
- if_add_hook(IF_DELETE_HOOK, if_zebra_delete_hook);
+ hook_register_prio(if_add, 0, if_zebra_new_hook);
+ hook_register_prio(if_del, 0, if_zebra_delete_hook);
/* Install configuration write function. */
install_node(&interface_node, if_config_write);
#include "redistribute.h"
#include "vrf.h"
-
-#ifdef HAVE_IRDP
-#include "zebra/irdp.h"
-#endif
+#include "hook.h"
#include "zebra/zebra_l2.h"
ZEBRA_IF_SLAVE_OTHER, /* Something else - e.g., bond slave */
} zebra_slave_iftype_t;
+struct irdp_interface;
+
/* `zebra' daemon local interface structure. */
struct zebra_if {
/* Shutdown configuration. */
unsigned int ra_sent, ra_rcvd;
#endif /* HAVE_RTADV */
-#ifdef HAVE_IRDP
- struct irdp_interface irdp;
-#endif
+ struct irdp_interface *irdp;
#ifdef HAVE_STRUCT_SOCKADDR_DL
union {
struct interface *link;
};
+DECLARE_HOOK(zebra_if_extra_info, (struct vty *vty, struct interface *ifp),
+ (vty, ifp))
+DECLARE_HOOK(zebra_if_config_wr, (struct vty *vty, struct interface *ifp),
+ (vty, ifp))
+
static inline void zebra_if_set_ziftype(struct interface *ifp,
zebra_iftype_t zif_type,
zebra_slave_iftype_t zif_slave_type)
int pref;
};
-extern void irdp_init(void);
+extern void irdp_if_init(void);
extern int irdp_sock_init(void);
-extern void irdp_finish(void);
-extern void irdp_config_write(struct vty *, struct interface *);
+extern int irdp_config_write(struct vty *, struct interface *);
extern int irdp_send_thread(struct thread *t_advert);
extern void irdp_advert_off(struct interface *ifp);
extern void process_solicit(struct interface *ifp);
#include <zebra.h>
-#ifdef HAVE_IRDP
-
#include "if.h"
#include "vty.h"
#include "sockunion.h"
extern int irdp_sock;
+DEFINE_MTYPE_STATIC(ZEBRA, IRDP_IF, "IRDP interface data")
+
+static struct irdp_interface *irdp_if_get(struct interface *ifp)
+{
+ struct zebra_if *zi = ifp->info;
+ if (!zi->irdp)
+ zi->irdp = XCALLOC(MTYPE_IRDP_IF, sizeof(*zi->irdp));
+ return zi->irdp;
+}
+
+static int irdp_if_delete(struct interface *ifp)
+{
+ struct zebra_if *zi = ifp->info;
+ if (!zi)
+ return 0;
+ XFREE(MTYPE_IRDP_IF, zi->irdp);
+ return 0;
+}
+
static const char *inet_2a(u_int32_t a, char *b)
{
sprintf(b, "%u.%u.%u.%u", (a)&0xFF, (a >> 8) & 0xFF, (a >> 16) & 0xFF,
static int if_add_group(struct interface *ifp)
{
struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
+ struct irdp_interface *irdp = zi->irdp;
int ret;
char b1[INET_ADDRSTRLEN];
+ if (!irdp)
+ return -1;
+
ret = if_group(ifp, irdp_sock, INADDR_ALLRTRS_GROUP, IP_ADD_MEMBERSHIP);
if (ret < 0) {
return ret;
static int if_drop_group(struct interface *ifp)
{
struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
+ struct irdp_interface *irdp = zi->irdp;
int ret;
char b1[INET_ADDRSTRLEN];
+ if (!irdp)
+ return -1;
+
ret = if_group(ifp, irdp_sock, INADDR_ALLRTRS_GROUP,
IP_DROP_MEMBERSHIP);
if (ret < 0)
return 0;
}
-static void if_set_defaults(struct interface *ifp)
+static void if_set_defaults(struct irdp_interface *irdp)
{
- struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
-
irdp->MaxAdvertInterval = IRDP_MAXADVERTINTERVAL;
irdp->MinAdvertInterval = IRDP_MINADVERTINTERVAL;
irdp->Preference = IRDP_PREFERENCE;
int set_defaults)
{
struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
+ struct irdp_interface *irdp = zi->irdp;
struct listnode *node;
struct connected *ifc;
u_int32_t timer, seed;
+ assert(irdp);
+
if (irdp->flags & IF_ACTIVE) {
zlog_warn("IRDP: Interface is already active %s", ifp->name);
return;
}
if (set_defaults)
- if_set_defaults(ifp);
+ if_set_defaults(irdp);
irdp->irdp_sent = 0;
static void irdp_if_stop(struct interface *ifp)
{
struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
+ struct irdp_interface *irdp = zi->irdp;
if (irdp == NULL) {
zlog_warn("Interface %s structure is NULL", ifp->name);
static void irdp_if_shutdown(struct interface *ifp)
{
struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
+ struct irdp_interface *irdp = zi->irdp;
+ if (!irdp)
+ return;
if (irdp->flags & IF_SHUTDOWN) {
zlog_warn("IRDP: Interface is already shutdown %s", ifp->name);
return;
static void irdp_if_no_shutdown(struct interface *ifp)
{
- struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
+ struct irdp_interface *irdp = irdp_if_get(ifp);
if (!(irdp->flags & IF_SHUTDOWN)) {
zlog_warn("IRDP: Interface is not shutdown %s", ifp->name);
/* Write configuration to user */
-void irdp_config_write(struct vty *vty, struct interface *ifp)
+int irdp_config_write(struct vty *vty, struct interface *ifp)
{
struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
+ struct irdp_interface *irdp = zi->irdp;
struct Adv *adv;
struct listnode *node;
char b1[INET_ADDRSTRLEN];
+ if (!irdp)
+ return 0;
+
if (irdp->flags & IF_ACTIVE || irdp->flags & IF_SHUTDOWN) {
if (irdp->flags & IF_SHUTDOWN)
vty_out(vty, " ip irdp maxadvertinterval %ld\n",
irdp->MaxAdvertInterval);
}
+ return 0;
}
"Use multicast mode\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
+ irdp_if_get(ifp);
irdp_if_start(ifp, TRUE, TRUE);
return CMD_SUCCESS;
"Use broadcast mode\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
+ irdp_if_get(ifp);
irdp_if_start(ifp, FALSE, TRUE);
return CMD_SUCCESS;
{
int idx_number = 3;
VTY_DECLVAR_CONTEXT(interface, ifp);
- struct zebra_if *zi;
- struct irdp_interface *irdp;
-
- zi = ifp->info;
- irdp = &zi->irdp;
+ struct irdp_interface *irdp = irdp_if_get(ifp);
irdp->Lifetime = atoi(argv[idx_number]->arg);
return CMD_SUCCESS;
{
int idx_number = 3;
VTY_DECLVAR_CONTEXT(interface, ifp);
- struct zebra_if *zi;
- struct irdp_interface *irdp;
-
- zi = ifp->info;
- irdp = &zi->irdp;
+ struct irdp_interface *irdp = irdp_if_get(ifp);
if ((unsigned)atoi(argv[idx_number]->arg) <= irdp->MaxAdvertInterval) {
irdp->MinAdvertInterval = atoi(argv[idx_number]->arg);
{
int idx_number = 3;
VTY_DECLVAR_CONTEXT(interface, ifp);
- struct zebra_if *zi;
- struct irdp_interface *irdp;
-
- zi = ifp->info;
- irdp = &zi->irdp;
+ struct irdp_interface *irdp = irdp_if_get(ifp);
if (irdp->MinAdvertInterval <= (unsigned)atoi(argv[idx_number]->arg)) {
irdp->MaxAdvertInterval = atoi(argv[idx_number]->arg);
{
int idx_number = 3;
VTY_DECLVAR_CONTEXT(interface, ifp);
- struct zebra_if *zi;
- struct irdp_interface *irdp;
-
- zi = ifp->info;
- irdp = &zi->irdp;
+ struct irdp_interface *irdp = irdp_if_get(ifp);
irdp->Preference = atoi(argv[idx_number]->arg);
return CMD_SUCCESS;
int idx_ipv4 = 3;
int idx_number = 5;
VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct irdp_interface *irdp = irdp_if_get(ifp);
struct listnode *node;
struct in_addr ip;
int pref;
int ret;
- struct zebra_if *zi;
- struct irdp_interface *irdp;
struct Adv *adv;
- zi = ifp->info;
- irdp = &zi->irdp;
-
ret = inet_aton(argv[idx_ipv4]->arg, &ip);
if (!ret)
return CMD_WARNING_CONFIG_FAILED;
{
int idx_ipv4 = 4;
VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct irdp_interface *irdp = irdp_if_get(ifp);
struct listnode *node, *nnode;
struct in_addr ip;
int ret;
- struct zebra_if *zi;
- struct irdp_interface *irdp;
struct Adv *adv;
- zi = ifp->info;
- irdp = &zi->irdp;
-
ret = inet_aton(argv[idx_ipv4]->arg, &ip);
if (!ret)
return CMD_WARNING_CONFIG_FAILED;
"Enable debugging for IRDP messages\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
- struct zebra_if *zi;
- struct irdp_interface *irdp;
-
- zi = ifp->info;
- irdp = &zi->irdp;
+ struct irdp_interface *irdp = irdp_if_get(ifp);
irdp->flags |= IF_DEBUG_MESSAGES;
"Enable debugging for miscellaneous IRDP events\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
- struct zebra_if *zi;
- struct irdp_interface *irdp;
-
- zi = ifp->info;
- irdp = &zi->irdp;
+ struct irdp_interface *irdp = irdp_if_get(ifp);
irdp->flags |= IF_DEBUG_MISC;
"Enable debugging for IRDP packets\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
- struct zebra_if *zi;
- struct irdp_interface *irdp;
-
- zi = ifp->info;
- irdp = &zi->irdp;
+ struct irdp_interface *irdp = irdp_if_get(ifp);
irdp->flags |= IF_DEBUG_PACKET;
"Disable debugging for all IRDP events\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
- struct zebra_if *zi;
- struct irdp_interface *irdp;
-
- zi = ifp->info;
- irdp = &zi->irdp;
+ struct irdp_interface *irdp = irdp_if_get(ifp);
irdp->flags &= ~IF_DEBUG_PACKET;
irdp->flags &= ~IF_DEBUG_MESSAGES;
return CMD_SUCCESS;
}
-void irdp_init()
+void irdp_if_init()
{
+ hook_register(zebra_if_config_wr, irdp_config_write);
+ hook_register(if_del, irdp_if_delete);
+
install_element(INTERFACE_NODE, &ip_irdp_broadcast_cmd);
install_element(INTERFACE_NODE, &ip_irdp_multicast_cmd);
install_element(INTERFACE_NODE, &no_ip_irdp_cmd);
install_element(INTERFACE_NODE, &ip_irdp_debug_packet_cmd);
install_element(INTERFACE_NODE, &ip_irdp_debug_disable_cmd);
}
-
-#endif /* HAVE_IRDP */
#include <zebra.h>
-#ifdef HAVE_IRDP
-
#include "if.h"
#include "vty.h"
#include "sockunion.h"
#include "zclient.h"
#include "thread.h"
#include "privs.h"
+#include "libfrr.h"
+#include "version.h"
#include "zebra/interface.h"
#include "zebra/rtadv.h"
#include "zebra/rib.h"
struct stream *s)
{
struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
+ struct irdp_interface *irdp = zi->irdp;
int size;
int pref;
u_int16_t checksum;
static void irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
{
struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
+ struct irdp_interface *irdp = zi->irdp;
char buf[PREFIX_STRLEN];
u_int32_t dst;
u_int32_t ttl = 1;
+ if (!irdp)
+ return;
if (!(ifp->flags & IFF_UP))
return;
u_int32_t timer, tmp;
struct interface *ifp = THREAD_ARG(t_advert);
struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
+ struct irdp_interface *irdp = zi->irdp;
struct prefix *p;
struct listnode *node, *nnode;
struct connected *ifc;
+ if (!irdp)
+ return 0;
+
irdp->flags &= ~IF_SOLICIT;
if (ifp->connected)
void irdp_advert_off(struct interface *ifp)
{
struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
+ struct irdp_interface *irdp = zi->irdp;
struct listnode *node, *nnode;
int i;
struct connected *ifc;
struct prefix *p;
+ if (!irdp)
+ return;
+
if (irdp->t_advertise)
thread_cancel(irdp->t_advertise);
irdp->t_advertise = NULL;
void process_solicit(struct interface *ifp)
{
struct zebra_if *zi = ifp->info;
- struct irdp_interface *irdp = &zi->irdp;
+ struct irdp_interface *irdp = zi->irdp;
u_int32_t timer;
+ if (!irdp)
+ return;
+
/* When SOLICIT is active we reject further incoming solicits
this keeps down the answering rate so we don't have think
about DoS attacks here. */
&irdp->t_advertise);
}
-void irdp_finish()
+static int irdp_finish(void)
{
struct vrf *vrf;
struct listnode *node, *nnode;
if (!zi)
continue;
- irdp = &zi->irdp;
+ irdp = zi->irdp;
if (!irdp)
continue;
irdp_advert_off(ifp);
}
}
+ return 0;
+}
+
+static int irdp_init(struct thread_master *master)
+{
+ irdp_if_init();
+
+ hook_register(frr_early_fini, irdp_finish);
+ return 0;
+}
+
+static int irdp_module_init(void)
+{
+ hook_register(frr_late_init, irdp_init);
+ return 0;
}
-#endif /* HAVE_IRDP */
+FRR_MODULE_SETUP(
+ .name = "zebra_irdp",
+ .version = FRR_VERSION,
+ .description = "zebra IRDP module",
+ .init = irdp_module_init,
+)
#include <zebra.h>
-#ifdef HAVE_IRDP
-
#include "if.h"
#include "vty.h"
#include "sockunion.h"
if (!zi)
return;
- irdp = &zi->irdp;
+ irdp = zi->irdp;
if (!irdp)
return;
if (!zi)
return ret;
- irdp = &zi->irdp;
+ irdp = zi->irdp;
if (!irdp)
return ret;
}
/* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */
}
-
-
-#endif /* HAVE_IRDP */
#if !defined(ROUNDUP)
/*
- * It's a bug for a platform not to define rounding/alignment for
- * sockaddrs on the routing socket. This warning really is
- * intentional, to provoke filing bug reports with operating systems
- * that don't define RT_ROUNDUP or equivalent.
+ * If you're porting to a platform that changed RT_ROUNDUP but doesn't
+ * have it in its headers, this will break rather obviously and you'll
+ * have to fix it here.
*/
-#warning \
- "net/route.h does not define RT_ROUNDUP; making unwarranted assumptions!"
/* OS X (Xcode as of 2014-12) is known not to define RT_ROUNDUP */
#ifdef __APPLE__
zlog_notice("Terminating on signal");
-#ifdef HAVE_IRDP
- irdp_finish();
-#endif
+ frr_early_fini();
zebra_ptm_finish();
list_delete_all_node(zebrad.client_list);
access_list_reset();
prefix_list_reset();
route_map_finish();
- cmd_terminate();
- vty_terminate();
- zprivs_terminate(&zserv_privs);
+
list_delete(zebrad.client_list);
work_queue_free(zebrad.ribq);
if (zebrad.lsp_process_q)
work_queue_free(zebrad.lsp_process_q);
meta_queue_free(zebrad.mq);
- thread_master_free(zebrad.master);
- closezlog();
+ frr_fini();
exit(0);
}
#if defined(HAVE_RTADV)
rtadv_cmd_init();
#endif
-#ifdef HAVE_IRDP
- irdp_init();
-#endif
/* PTM socket */
#ifdef ZEBRA_PTM_SUPPORT
zebra_ptm_init();
RNODE_FOREACH_RE(rn, newre)
if (CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED)
&& newre->distance != DISTANCE_INFINITY)
- zsend_redistribute_route(1, client, &rn->p, NULL,
- newre);
+ zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
+ client, &rn->p, NULL, newre);
route_unlock_node(rn);
}
if (!table)
return;
- for (rn = route_top(table); rn; rn = route_next(rn))
+ for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
RNODE_FOREACH_RE(rn, newre)
{
struct prefix *dst_p, *src_p;
if (!zebra_check_addr(dst_p))
continue;
- zsend_redistribute_route(1, client, dst_p, src_p,
- newre);
+ zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
+ client, dst_p, src_p, newre);
}
}
send_redistribute = 1;
if (send_redistribute) {
- zsend_redistribute_route(1, client, p, src_p, re);
+ zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
+ client, p, src_p, re);
} else if (prev_re
&& ((re->instance
&& redist_check_instance(
|| vrf_bitmap_check(
client->redist[afi][prev_re->type],
re->vrf_id))) {
- zsend_redistribute_route(0, client, p, src_p, prev_re);
+ zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL,
+ client, p, src_p, prev_re);
}
}
}
re->instance))
|| vrf_bitmap_check(client->redist[afi][re->type],
re->vrf_id)) {
- zsend_redistribute_route(0, client, p, src_p, re);
+ zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL,
+ client, p, src_p, re);
}
}
}
}
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
+#ifdef __OpenBSD__
+static int kernel_rtm_add_labels(struct nexthop_label *nh_label,
+ struct sockaddr_mpls *smpls)
+{
+ if (nh_label->num_labels > 1) {
+ zlog_warn(
+ "%s: can't push %u labels at "
+ "once (maximum is 1)",
+ __func__, nh_label->num_labels);
+ return -1;
+ }
+
+ memset(smpls, 0, sizeof(*smpls));
+ smpls->smpls_len = sizeof(*smpls);
+ smpls->smpls_family = AF_MPLS;
+ smpls->smpls_label = htonl(nh_label->label[0] << MPLS_LABEL_OFFSET);
+
+ return 0;
+}
+#endif
+
/* Interface between zebra message and rtm message. */
static int kernel_rtm_ipv4(int cmd, struct prefix *p, struct route_entry *re)
}
#ifdef __OpenBSD__
- if (nexthop->nh_label) {
- memset(&smpls, 0, sizeof(smpls));
- smpls.smpls_len = sizeof(smpls);
- smpls.smpls_family = AF_MPLS;
- smpls.smpls_label =
- htonl(nexthop->nh_label->label[0]
- << MPLS_LABEL_OFFSET);
- smplsp = (union sockunion *)&smpls;
- }
+ if (nexthop->nh_label
+ && !kernel_rtm_add_labels(nexthop->nh_label,
+ &smpls))
+ continue;
+ smplsp = (union sockunion *)&smpls;
#endif
error = rtm_write(
{
struct sockaddr_in6 *mask;
struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
+#ifdef __OpenBSD__
+ struct sockaddr_mpls smpls;
+#endif
+ union sockunion *smplsp = NULL;
struct nexthop *nexthop;
int nexthop_num = 0;
ifindex_t ifindex = 0;
mask = &sin_mask;
}
+#ifdef __OpenBSD__
+ if (nexthop->nh_label
+ && !kernel_rtm_add_labels(nexthop->nh_label, &smpls))
+ continue;
+ smplsp = (union sockunion *)&smpls;
+#endif
+
error = rtm_write(cmd, (union sockunion *)&sin_dest,
(union sockunion *)mask,
gate ? (union sockunion *)&sin_gate : NULL,
- NULL, ifindex, re->flags, re->metric);
+ smplsp, ifindex, re->flags, re->metric);
#if 0
if (error)
#define ALLNODE "ff02::1"
#define ALLROUTER "ff02::2"
+/* Order is intentional. Matches RFC4191. This array is also used for
+ command matching, so only modify with care. */
+const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0};
+
enum rtadv_event {
RTADV_START,
RTADV_STOP,
return CMD_SUCCESS;
}
+/* Dump interface ND information to vty. */
+static int nd_dump_vty(struct vty *vty, struct interface *ifp)
+{
+ struct zebra_if *zif;
+ struct rtadvconf *rtadv;
+ int interval;
+
+ zif = (struct zebra_if *)ifp->info;
+ rtadv = &zif->rtadv;
+
+ if (rtadv->AdvSendAdvertisements) {
+ vty_out(vty,
+ " ND advertised reachable time is %d milliseconds\n",
+ rtadv->AdvReachableTime);
+ vty_out(vty,
+ " ND advertised retransmit interval is %d milliseconds\n",
+ rtadv->AdvRetransTimer);
+ vty_out(vty, " ND router advertisements sent: %d rcvd: %d\n",
+ zif->ra_sent, zif->ra_rcvd);
+ interval = rtadv->MaxRtrAdvInterval;
+ if (interval % 1000)
+ vty_out(vty,
+ " ND router advertisements are sent every "
+ "%d milliseconds\n",
+ interval);
+ else
+ vty_out(vty,
+ " ND router advertisements are sent every "
+ "%d seconds\n",
+ interval / 1000);
+ if (rtadv->AdvDefaultLifetime != -1)
+ vty_out(vty,
+ " ND router advertisements live for %d seconds\n",
+ rtadv->AdvDefaultLifetime);
+ else
+ vty_out(vty,
+ " ND router advertisements lifetime tracks ra-interval\n");
+ vty_out(vty,
+ " ND router advertisement default router preference is "
+ "%s\n",
+ rtadv_pref_strs[rtadv->DefaultPreference]);
+ if (rtadv->AdvManagedFlag)
+ vty_out(vty,
+ " Hosts use DHCP to obtain routable addresses.\n");
+ else
+ vty_out(vty,
+ " Hosts use stateless autoconfig for addresses.\n");
+ if (rtadv->AdvHomeAgentFlag) {
+ vty_out(vty,
+ " ND router advertisements with Home Agent flag bit set.\n");
+ if (rtadv->HomeAgentLifetime != -1)
+ vty_out(vty,
+ " Home Agent lifetime is %u seconds\n",
+ rtadv->HomeAgentLifetime);
+ else
+ vty_out(vty,
+ " Home Agent lifetime tracks ra-lifetime\n");
+ vty_out(vty, " Home Agent preference is %u\n",
+ rtadv->HomeAgentPreference);
+ }
+ if (rtadv->AdvIntervalOption)
+ vty_out(vty,
+ " ND router advertisements with Adv. Interval option.\n");
+ }
+ return 0;
+}
+
/* Write configuration about router advertisement. */
-void rtadv_config_write(struct vty *vty, struct interface *ifp)
+static int rtadv_config_write(struct vty *vty, struct interface *ifp)
{
struct zebra_if *zif;
struct listnode *node;
vty_out(vty, " router-address");
vty_out(vty, "\n");
}
+ return 0;
}
void rtadv_cmd_init(void)
{
+ hook_register(zebra_if_extra_info, nd_dump_vty);
+ hook_register(zebra_if_config_wr, rtadv_config_write);
+
install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
#endif
};
-extern void rtadv_config_write(struct vty *, struct interface *);
-
/* RFC4584 Extension to Sockets API for Mobile IPv6 */
#ifndef ND_OPT_ADV_INTERVAL
sbin_PROGRAMS += zebra/zebra
dist_examples_DATA += zebra/zebra.conf.sample
+if IRDP
+module_LTLIBRARIES += zebra/zebra_irdp.la
+endif
if SNMP
module_LTLIBRARIES += zebra/zebra_snmp.la
endif
zebra/ipforward_proc.c \
zebra/ipforward_solaris.c \
zebra/ipforward_sysctl.c \
- zebra/irdp_interface.c \
- zebra/irdp_main.c \
- zebra/irdp_packet.c \
zebra/kernel_netlink.c \
zebra/kernel_socket.c \
zebra/label_manager.c \
zebra/zserv.h \
# end
+zebra_zebra_irdp_la_SOURCES = \
+ zebra/irdp_interface.c \
+ zebra/irdp_main.c \
+ zebra/irdp_packet.c \
+ # end
+zebra_zebra_irdp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+
zebra_zebra_snmp_la_SOURCES = zebra/zebra_snmp.c
zebra_zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
zebra_zebra_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
in.s_addr = zfpm_g->fpm_server;
- if (zfpm_g->fpm_server != FPM_DEFAULT_IP
- || zfpm_g->fpm_port != FPM_DEFAULT_PORT)
+ if ((zfpm_g->fpm_server != FPM_DEFAULT_IP
+ && zfpm_g->fpm_server != INADDR_ANY)
+ || (zfpm_g->fpm_port != FPM_DEFAULT_PORT
+ && zfpm_g->fpm_port != 0))
vty_out(vty, "fpm connection ip %s port %d\n", inet_ntoa(in),
zfpm_g->fpm_port);
char *mpls_label2str(u_int8_t num_labels, mpls_label_t *labels, char *buf,
int len, int pretty)
{
- char *buf_ptr = buf;
- buf[0] = '\0';
-
- if (pretty) {
- if (num_labels == 1) {
- label2str(labels[0], buf, len);
- } else if (num_labels == 2) {
- label2str(labels[0], buf, len);
- buf_ptr += strlen(buf);
+ char label_buf[BUFSIZ];
+ int i;
- snprintf(buf_ptr, len, "/");
- buf_ptr++;
-
- label2str(labels[1], buf_ptr, len);
- }
- } else {
- if (num_labels == 1)
- snprintf(buf, len, "%u", labels[0]);
- else if (num_labels == 2)
- snprintf(buf, len, "%u/%u", labels[0], labels[1]);
+ buf[0] = '\0';
+ for (i = 0; i < num_labels; i++) {
+ if (i != 0)
+ strlcat(buf, "/", len);
+ if (pretty)
+ label2str(labels[i], label_buf, sizeof(label_buf));
+ else
+ snprintf(label_buf, sizeof(label_buf), "%u", labels[i]);
+ strlcat(buf, label_buf, len);
}
+
return buf;
}
/* Definitions and macros. */
-#define MPLS_MAX_LABELS 2 /* Maximum # labels that can be pushed. */
-
#define NHLFE_FAMILY(nhlfe) \
(((nhlfe)->nexthop->type == NEXTHOP_TYPE_IPV6 \
|| (nhlfe)->nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) \
|| (action == RTM_DELETE
&& (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)
&& CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)))) {
+ if (nhlfe->nexthop->nh_label->num_labels > 1) {
+ zlog_warn(
+ "%s: can't push %u labels at once "
+ "(maximum is 1)",
+ __func__,
+ nhlfe->nexthop->nh_label->num_labels);
+ continue;
+ }
+
nexthop_num++;
switch (NHLFE_FAMILY(nhlfe)) {
DEFUN (show_pseudowires,
show_pseudowires_cmd,
- "show pseudowires",
+ "show mpls pseudowires",
SHOW_STR
+ MPLS_STR
"Pseudowires")
{
struct zebra_vrf *zvrf;
* holder, if necessary, then push the work into it in any case.
* This semantics was introduced after 0.99.9 release.
*/
- if (!zebrad.ribq->items->count)
+ if (work_queue_empty(zebrad.ribq))
work_queue_add(zebrad.ribq, zebrad.mq);
rib_meta_queue_add(zebrad.mq, rn);
break;
}
for (ALL_NEXTHOPS(re->nexthop, nexthop))
- if (IPV4_ADDR_SAME(&nexthop->gate.ipv4, gate)
+ if (IPV4_ADDR_SAME(&nexthop->gate.ipv4, &gate->ipv4)
|| IPV6_ADDR_SAME(&nexthop->gate.ipv6,
gate)) {
same = re;
for (si = rn->info; si; si = si->next) {
if (type == si->type
&& (!gate || ((afi == AFI_IP
- && IPV4_ADDR_SAME(gate, &si->addr.ipv4))
+ && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
|| (afi == AFI_IP6
&& IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
&& (!strcmp (ifname ? ifname : "", si->ifname))) {
for (si = rn->info; si; si = si->next)
if (type == si->type
&& (!gate || ((afi == AFI_IP
- && IPV4_ADDR_SAME(gate, &si->addr.ipv4))
+ && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
|| (afi == AFI_IP6
&& IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
&& (!strcmp(ifname ? ifname : "", si->ifname))
#ifndef __ZEBRA_STATIC_H__
#define __ZEBRA_STATIC_H__
+#include "zebra/zebra_mpls.h"
+
/* Static route label information */
struct static_nh_label {
u_int8_t num_labels;
u_int8_t reserved[3];
- mpls_label_t label[2];
+ mpls_label_t label[MPLS_MAX_LABELS];
};
typedef enum {
inet_ntop(AF_INET,
&si->addr.ipv4, buf,
sizeof buf),
- ifindex2ifname(si->ifindex,
- si->vrf_id));
+ si->ifname);
break;
case STATIC_IPV6_GATEWAY_IFNAME:
vty_out(vty, " %s %s",
inet_ntop(AF_INET6,
&si->addr.ipv6, buf,
sizeof buf),
- ifindex2ifname(si->ifindex,
- si->vrf_id));
+ si->ifname);
break;
}
return zebra_server_send_message(client);
}
-/*
- * This is the new function to announce and withdraw redistributed routes, used
- * by Zebra. This is the old zsend_route_multipath() function. That function
- * was duplicating code to send a lot of information that was essentially thrown
- * away or ignored by the receiver. This is the leaner function that is not a
- * duplicate of the zapi_ipv4_route_add/del.
- *
- * The primary difference is that this function merely sends a single NH instead
- * of
- * all the nexthops.
- */
-int zsend_redistribute_route(int add, struct zserv *client, struct prefix *p,
+int zsend_redistribute_route(int cmd, struct zserv *client, struct prefix *p,
struct prefix *src_p, struct route_entry *re)
{
- afi_t afi;
- int cmd;
- int psize;
- struct stream *s;
+ struct zapi_route api;
+ struct zapi_nexthop *api_nh;
struct nexthop *nexthop;
- unsigned long nhnummark = 0, messmark = 0;
- int nhnum = 0;
- u_char zapi_flags = 0;
- struct nexthop dummy_nh;
-
- afi = family2afi(p->family);
- if (add) {
- switch (afi) {
- case AFI_IP:
- cmd = ZEBRA_REDISTRIBUTE_IPV4_ADD;
- client->redist_v4_add_cnt++;
- break;
- case AFI_IP6:
- cmd = ZEBRA_REDISTRIBUTE_IPV6_ADD;
- client->redist_v6_add_cnt++;
- break;
- default:
- return -1;
- }
- } else {
- switch (afi) {
- case AFI_IP:
- cmd = ZEBRA_REDISTRIBUTE_IPV4_DEL;
- client->redist_v4_del_cnt++;
- break;
- case AFI_IP6:
- cmd = ZEBRA_REDISTRIBUTE_IPV6_DEL;
- client->redist_v6_del_cnt++;
- break;
- default:
- return -1;
- }
- }
-
- s = client->obuf;
- stream_reset(s);
- memset(&dummy_nh, 0, sizeof(struct nexthop));
+ int count = 0;
- zserv_create_header(s, cmd, re->vrf_id);
-
- /* Put type and nexthop. */
- stream_putc(s, re->type);
- stream_putw(s, re->instance);
- stream_putl(s, re->flags);
-
- /* marker for message flags field */
- messmark = stream_get_endp(s);
- stream_putc(s, 0);
+ memset(&api, 0, sizeof(api));
+ api.vrf_id = VRF_DEFAULT;
+ api.type = re->type;
+ api.instance = re->instance;
+ api.flags = re->flags;
/* Prefix. */
- psize = PSIZE(p->prefixlen);
- stream_putc(s, p->prefixlen);
- stream_write(s, (u_char *)&p->u.prefix, psize);
-
+ api.prefix = *p;
if (src_p) {
- SET_FLAG(zapi_flags, ZAPI_MESSAGE_SRCPFX);
- psize = PSIZE(src_p->prefixlen);
- stream_putc(s, src_p->prefixlen);
- stream_write(s, (u_char *)&src_p->u.prefix, psize);
+ SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
+ memcpy(&api.src_prefix, src_p, sizeof(api.src_prefix));
}
+ /* Nexthops. */
+ if (re->nexthop_active_num) {
+ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+ api.nexthop_num = re->nexthop_active_num;
+ }
for (nexthop = re->nexthop; nexthop; nexthop = nexthop->next) {
- /* We don't send any nexthops when there's a multipath */
- if (re->nexthop_active_num > 1
- && client->proto != ZEBRA_ROUTE_LDP) {
- SET_FLAG(zapi_flags, ZAPI_MESSAGE_NEXTHOP);
- SET_FLAG(zapi_flags, ZAPI_MESSAGE_IFINDEX);
-
- stream_putc(s, 1);
- if (p->family == AF_INET) {
- stream_put_in_addr(s, &dummy_nh.gate.ipv4);
- } else if (p->family == AF_INET6) {
- stream_write(s, (u_char *)&dummy_nh.gate.ipv6,
- 16);
- } else {
- /* We don't handle anything else now, abort */
- zlog_err(
- "%s: Unable to redistribute route of unknown family, %d\n",
- __func__, p->family);
- return -1;
- }
- stream_putc(s, 1);
- stream_putl(s, 0); /* dummy ifindex */
- break;
- }
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
- SET_FLAG(zapi_flags, ZAPI_MESSAGE_NEXTHOP);
- SET_FLAG(zapi_flags, ZAPI_MESSAGE_IFINDEX);
- if (nhnummark == 0) {
- nhnummark = stream_get_endp(s);
- stream_putc(s, 1); /* placeholder */
- }
- nhnum++;
-
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- stream_put_in_addr(s, &nexthop->gate.ipv4);
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- /* Only BGP supports IPv4 prefix with IPv6 NH,
- * so kill this */
- if (p->family == AF_INET)
- stream_put_in_addr(s,
- &dummy_nh.gate.ipv4);
- else
- stream_write(
- s,
- (u_char *)&nexthop->gate.ipv6,
- 16);
- break;
- default:
- if (cmd == ZEBRA_REDISTRIBUTE_IPV4_ADD
- || cmd == ZEBRA_REDISTRIBUTE_IPV4_DEL) {
- struct in_addr empty;
- memset(&empty, 0,
- sizeof(struct in_addr));
- stream_write(s, (u_char *)&empty,
- IPV4_MAX_BYTELEN);
- } else {
- struct in6_addr empty;
- memset(&empty, 0,
- sizeof(struct in6_addr));
- stream_write(s, (u_char *)&empty,
- IPV6_MAX_BYTELEN);
- }
- }
-
- /* Interface index. */
- stream_putc(s, 1);
- stream_putl(s, nexthop->ifindex);
+ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ continue;
- /* ldpd needs all nexthops */
- if (client->proto != ZEBRA_ROUTE_LDP)
- break;
+ api_nh = &api.nexthops[count];
+ api_nh->type = nexthop->type;
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_BLACKHOLE:
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ api_nh->gate.ipv4 = nexthop->gate.ipv4;
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ api_nh->gate.ipv4 = nexthop->gate.ipv4;
+ api_nh->ifindex = nexthop->ifindex;
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ api_nh->ifindex = nexthop->ifindex;
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ api_nh->gate.ipv6 = nexthop->gate.ipv6;
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ api_nh->gate.ipv6 = nexthop->gate.ipv6;
+ api_nh->ifindex = nexthop->ifindex;
}
+ count++;
}
- /* Distance */
- SET_FLAG(zapi_flags, ZAPI_MESSAGE_DISTANCE);
- stream_putc(s, re->distance);
-
- /* Metric */
- SET_FLAG(zapi_flags, ZAPI_MESSAGE_METRIC);
- stream_putl(s, re->metric);
-
- /* Tag */
+ /* Attributes. */
+ SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
+ api.distance = re->distance;
+ SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
+ api.metric = re->metric;
if (re->tag) {
- SET_FLAG(zapi_flags, ZAPI_MESSAGE_TAG);
- stream_putl(s, re->tag);
+ SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
+ api.tag = re->tag;
}
+ SET_FLAG(api.message, ZAPI_MESSAGE_MTU);
+ api.mtu = re->mtu;
- /* MTU */
- SET_FLAG(zapi_flags, ZAPI_MESSAGE_MTU);
- stream_putl(s, re->mtu);
-
- /* write real message flags value */
- stream_putc_at(s, messmark, zapi_flags);
-
- /* Write next-hop number */
- if (nhnummark)
- stream_putc_at(s, nhnummark, nhnum);
-
- /* Write packet size. */
- stream_putw_at(s, 0, stream_get_endp(s));
-
+ /* Encode route and send. */
+ if (zapi_route_encode(cmd, client->obuf, &api) < 0)
+ return -1;
return zebra_server_send_message(client);
}
}
}
+static int zread_route_add(struct zserv *client, u_short length,
+ struct zebra_vrf *zvrf)
+{
+ struct stream *s;
+ struct zapi_route api;
+ struct zapi_nexthop *api_nh;
+ afi_t afi;
+ struct prefix_ipv6 *src_p = NULL;
+ struct route_entry *re;
+ struct nexthop *nexthop = NULL;
+ int i, ret;
+
+ s = client->ibuf;
+ if (zapi_route_decode(s, &api) < 0)
+ return -1;
+
+ /* Allocate new route. */
+ re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
+ re->type = api.type;
+ re->instance = api.instance;
+ re->flags = api.flags;
+ re->uptime = time(NULL);
+ re->vrf_id = zvrf_id(zvrf);
+ re->table = zvrf->table_id;
+
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
+ for (i = 0; i < api.nexthop_num; i++) {
+ api_nh = &api.nexthops[i];
+
+ switch (api_nh->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ route_entry_nexthop_ifindex_add(
+ re, api_nh->ifindex);
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ nexthop = route_entry_nexthop_ipv4_add(
+ re, &api_nh->gate.ipv4, NULL);
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ nexthop = route_entry_nexthop_ipv4_ifindex_add(
+ re, &api_nh->gate.ipv4, NULL,
+ api_nh->ifindex);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ nexthop = route_entry_nexthop_ipv6_add(
+ re, &api_nh->gate.ipv6);
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ nexthop = route_entry_nexthop_ipv6_ifindex_add(
+ re, &api_nh->gate.ipv6,
+ api_nh->ifindex);
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ route_entry_nexthop_blackhole_add(re);
+ break;
+ }
+
+ /* MPLS labels for BGP-LU or Segment Routing */
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_LABEL)
+ && api_nh->type != NEXTHOP_TYPE_IFINDEX
+ && api_nh->type != NEXTHOP_TYPE_BLACKHOLE) {
+ enum lsp_types_t label_type;
+
+ label_type =
+ lsp_type_from_re_type(client->proto);
+ nexthop_add_labels(nexthop, label_type,
+ api_nh->label_num,
+ &api_nh->labels[0]);
+ }
+ }
+ }
+
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
+ re->distance = api.distance;
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
+ re->metric = api.metric;
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG))
+ re->tag = api.tag;
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_MTU))
+ re->mtu = api.mtu;
+
+ afi = family2afi(api.prefix.family);
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
+ src_p = &api.src_prefix;
+
+ ret = rib_add_multipath(afi, api.safi, &api.prefix, src_p, re);
+
+ /* Stats */
+ switch (api.prefix.family) {
+ case AF_INET:
+ if (ret > 0)
+ client->v4_route_add_cnt++;
+ else if (ret < 0)
+ client->v4_route_upd8_cnt++;
+ break;
+ case AF_INET6:
+ if (ret > 0)
+ client->v6_route_add_cnt++;
+ else if (ret < 0)
+ client->v6_route_upd8_cnt++;
+ break;
+ }
+
+ return 0;
+}
+
+static int zread_route_del(struct zserv *client, u_short length,
+ struct zebra_vrf *zvrf)
+{
+ struct stream *s;
+ struct zapi_route api;
+ afi_t afi;
+ struct prefix_ipv6 *src_p = NULL;
+
+ s = client->ibuf;
+ if (zapi_route_decode(s, &api) < 0)
+ return -1;
+
+ afi = family2afi(api.prefix.family);
+ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
+ src_p = &api.src_prefix;
+
+ rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance,
+ api.flags, &api.prefix, src_p, NULL, 0, zvrf->table_id,
+ api.metric);
+
+ /* Stats */
+ switch (api.prefix.family) {
+ case AF_INET:
+ client->v4_route_del_cnt++;
+ break;
+ case AF_INET6:
+ client->v6_route_del_cnt++;
+ break;
+ }
+
+ return 0;
+}
+
/* This function support multiple nexthop. */
/*
* Parse the ZEBRA_IPV4_ROUTE_ADD sent from client. Update re and
ifindex_t ifindex;
safi_t safi;
int ret;
+ enum lsp_types_t label_type = ZEBRA_LSP_NONE;
mpls_label_t label;
struct nexthop *nexthop;
zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
nexthop_num);
+ if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL))
+ label_type = lsp_type_from_re_type(client->proto);
+
for (i = 0; i < nexthop_num; i++) {
nexthop_type = stream_getc(s);
* by label. */
if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL)) {
label = (mpls_label_t)stream_getl(s);
- nexthop_add_labels(
- nexthop, nexthop->nh_label_type,
- 1, &label);
+ nexthop_add_labels(nexthop, label_type,
+ 1, &label);
}
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
static int zread_ipv4_delete(struct zserv *client, u_short length,
struct zebra_vrf *zvrf)
{
- int i;
struct stream *s;
struct zapi_ipv4 api;
- struct in_addr nexthop;
- union g_addr *nexthop_p;
- unsigned long ifindex;
struct prefix p;
- u_char nexthop_num;
- u_char nexthop_type;
u_int32_t table_id;
s = client->ibuf;
- ifindex = 0;
- nexthop.s_addr = 0;
- nexthop_p = NULL;
/* Type, flags, message. */
api.type = stream_getc(s);
p.prefixlen = stream_getc(s);
stream_get(&p.u.prefix4, s, PSIZE(p.prefixlen));
- /* Nexthop, ifindex, distance, metric. */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
- nexthop_num = stream_getc(s);
-
- for (i = 0; i < nexthop_num; i++) {
- nexthop_type = stream_getc(s);
-
- switch (nexthop_type) {
- case NEXTHOP_TYPE_IFINDEX:
- ifindex = stream_getl(s);
- break;
- case NEXTHOP_TYPE_IPV4:
- nexthop.s_addr = stream_get_ipv4(s);
- /* For labeled-unicast, each nexthop is followed
- * by label, but
- * we don't care for delete.
- */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_LABEL))
- stream_forward_getp(s,
- sizeof(u_int32_t));
- nexthop_p = (union g_addr *)&nexthop;
- break;
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- nexthop.s_addr = stream_get_ipv4(s);
- nexthop_p = (union g_addr *)&nexthop;
- ifindex = stream_getl(s);
- break;
- case NEXTHOP_TYPE_IPV6:
- stream_forward_getp(s, IPV6_MAX_BYTELEN);
- break;
- }
- }
- }
-
- /* Distance. */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
- api.distance = stream_getc(s);
- else
- api.distance = 0;
-
- /* Metric. */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
- api.metric = stream_getl(s);
- else
- api.metric = 0;
-
- /* tag */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG))
- api.tag = stream_getl(s);
- else
- api.tag = 0;
-
table_id = zvrf->table_id;
rib_delete(AFI_IP, api.safi, zvrf_id(zvrf), api.type, api.instance,
- api.flags, &p, NULL, nexthop_p, ifindex, table_id,
- api.metric);
+ api.flags, &p, NULL, NULL, 0, table_id, 0);
client->v4_route_del_cnt++;
return 0;
}
static unsigned int ifindices[MULTIPATH_NUM];
int ret;
static mpls_label_t labels[MULTIPATH_NUM];
+ enum lsp_types_t label_type = ZEBRA_LSP_NONE;
mpls_label_t label;
struct nexthop *nexthop;
nexthop_num = stream_getc(s);
zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
nexthop_num);
+
+ if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL))
+ label_type = lsp_type_from_re_type(client->proto);
+
for (i = 0; i < nexthop_num; i++) {
nexthop_type = stream_getc(s);
re, &nexthops[i]);
if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL))
- nexthop_add_labels(
- nexthop, nexthop->nh_label_type,
- 1, &labels[i]);
+ nexthop_add_labels(nexthop, label_type,
+ 1, &labels[i]);
} else {
if ((i < if_count) && ifindices[i])
route_entry_nexthop_ifindex_add(
unsigned int i;
struct stream *s;
struct in6_addr nhop_addr;
+ ifindex_t ifindex;
struct route_entry *re;
u_char message;
u_char nexthop_num;
static unsigned int ifindices[MULTIPATH_NUM];
int ret;
static mpls_label_t labels[MULTIPATH_NUM];
+ enum lsp_types_t label_type = ZEBRA_LSP_NONE;
mpls_label_t label;
struct nexthop *nexthop;
nexthop_num = stream_getc(s);
zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
nexthop_num);
+
+ if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL))
+ label_type = lsp_type_from_re_type(client->proto);
+
for (i = 0; i < nexthop_num; i++) {
nexthop_type = stream_getc(s);
nexthops[nh_count++] = nhop_addr;
}
break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ stream_get(&nhop_addr, s, 16);
+ ifindex = stream_getl(s);
+ route_entry_nexthop_ipv6_ifindex_add(
+ re, &nhop_addr, ifindex);
+ break;
case NEXTHOP_TYPE_IFINDEX:
if (if_count < multipath_num) {
ifindices[if_count++] = stream_getl(s);
nexthop = route_entry_nexthop_ipv6_add(
re, &nexthops[i]);
if (CHECK_FLAG(message, ZAPI_MESSAGE_LABEL))
- nexthop_add_labels(
- nexthop, nexthop->nh_label_type,
- 1, &labels[i]);
+ nexthop_add_labels(nexthop, label_type,
+ 1, &labels[i]);
} else {
if ((i < if_count) && ifindices[i])
route_entry_nexthop_ifindex_add(
static int zread_ipv6_delete(struct zserv *client, u_short length,
struct zebra_vrf *zvrf)
{
- int i;
struct stream *s;
struct zapi_ipv6 api;
- struct in6_addr nexthop;
- union g_addr *pnexthop = NULL;
- unsigned long ifindex;
struct prefix p;
struct prefix_ipv6 src_p, *src_pp;
s = client->ibuf;
- ifindex = 0;
- memset(&nexthop, 0, sizeof(struct in6_addr));
/* Type, flags, message. */
api.type = stream_getc(s);
} else
src_pp = NULL;
- /* Nexthop, ifindex, distance, metric. */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
- u_char nexthop_type;
-
- api.nexthop_num = stream_getc(s);
- for (i = 0; i < api.nexthop_num; i++) {
- nexthop_type = stream_getc(s);
-
- switch (nexthop_type) {
- case NEXTHOP_TYPE_IPV6:
- stream_get(&nexthop, s, 16);
- /* For labeled-unicast, each nexthop is followed
- * by label, but
- * we don't care for delete.
- */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_LABEL))
- stream_forward_getp(s,
- sizeof(u_int32_t));
- pnexthop = (union g_addr *)&nexthop;
- break;
- case NEXTHOP_TYPE_IFINDEX:
- ifindex = stream_getl(s);
- break;
- }
- }
- }
-
- /* Distance. */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
- api.distance = stream_getc(s);
- else
- api.distance = 0;
-
- /* Metric. */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
- api.metric = stream_getl(s);
- else
- api.metric = 0;
-
- /* tag */
- if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG))
- api.tag = stream_getl(s);
- else
- api.tag = 0;
-
- if (IN6_IS_ADDR_UNSPECIFIED(&nexthop))
- rib_delete(AFI_IP6, api.safi, zvrf_id(zvrf), api.type,
- api.instance, api.flags, &p, src_pp, NULL, ifindex,
- client->rtm_table, api.metric);
- else
- rib_delete(AFI_IP6, api.safi, zvrf_id(zvrf), api.type,
- api.instance, api.flags, &p, src_pp, pnexthop,
- ifindex, client->rtm_table, api.metric);
+ rib_delete(AFI_IP6, api.safi, zvrf_id(zvrf), api.type, api.instance,
+ api.flags, &p, src_pp, NULL, 0, client->rtm_table, 0);
client->v6_route_del_cnt++;
return 0;
case ZEBRA_INTERFACE_DELETE:
zread_interface_delete(client, length, zvrf);
break;
+ case ZEBRA_ROUTE_ADD:
+ zread_route_add(client, length, zvrf);
+ break;
+ case ZEBRA_ROUTE_DELETE:
+ zread_route_del(client, length, zvrf);
+ break;
case ZEBRA_IPV4_ROUTE_ADD:
zread_ipv4_add(client, length, zvrf);
break;
case ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD:
zread_ipv4_route_ipv6_nexthop_add(client, length, zvrf);
break;
- case ZEBRA_IPV4_NEXTHOP_ADD:
- zread_ipv4_add(client, length,
- zvrf); /* LB: r1.0 merge - id was 1 */
- break;
- case ZEBRA_IPV4_NEXTHOP_DELETE:
- zread_ipv4_delete(client, length,
- zvrf); /* LB: r1.0 merge - id was 1 */
- break;
case ZEBRA_IPV6_ROUTE_ADD:
zread_ipv6_add(client, length, zvrf);
break;