diff --git a/Makefile.am b/Makefile.am index 494fcd4d56..f204f8a724 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ include common.am AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir) -I$(top_builddir)/lib AM_CFLAGS = $(WERROR) -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE) LIBCAP = @LIBCAP@ EXTRA_DIST = @@ -25,6 +25,14 @@ pkginclude_HEADERS = nodist_pkginclude_HEADERS = dist_examples_DATA = +## libtool, the self-made GNU scourge +## ... this should fix relinking +## ... and AUTOMAKE_DUMMY is needed to prevent automake from treating this +## as overriding the normal targets... +$(AUTOMAKE_DUMMY)install-moduleLTLIBRARIES: install-libLTLIBRARIES +$(AUTOMAKE_DUMMY)install-binPROGRAMS: install-libLTLIBRARIES +$(AUTOMAKE_DUMMY)install-sbinPROGRAMS: install-libLTLIBRARIES + include lib/subdir.am include zebra/subdir.am include qpb/subdir.am diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 1ae33b3a27..9fa32ee6fa 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -1256,8 +1256,8 @@ void babel_if_init () { /* initialize interface list */ - if_add_hook (IF_NEW_HOOK, babel_if_new_hook); - if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook); + hook_register_prio(if_add, 0, babel_if_new_hook); + hook_register_prio(if_del, 0, babel_if_delete_hook); babel_enable_if = vector_init (1); diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c index 11b9c5956c..337b7b3927 100644 --- a/babeld/babel_zebra.c +++ b/babeld/babel_zebra.c @@ -37,7 +37,6 @@ void babelz_zebra_init(void); /* we must use a pointer because of zclient.c's functions (new, free). */ struct zclient *zclient; -static int zebra_config_write (struct vty *vty); /* Debug types */ static struct { @@ -55,118 +54,24 @@ static struct { {0, 0, NULL} }; -/* Zebra node structure. */ -struct cmd_node zebra_node = -{ - ZEBRA_NODE, - "%s(config-router)# ", - 1 /* vtysh? yes */ -}; - - -/* Zebra route add and delete treatment (ipv6). */ +/* Zebra route add and delete treatment. */ static int -babel_zebra_read_ipv6 (int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf) +babel_zebra_read_route (int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf) { - struct stream *s; - struct zapi_ipv6 api; - unsigned long ifindex = -1; - struct in6_addr nexthop; - struct prefix_ipv6 prefix; + struct zapi_route api; - s = zclient->ibuf; - ifindex = 0; - memset (&nexthop, 0, sizeof (struct in6_addr)); - memset (&api, 0, sizeof(struct zapi_ipv6)); - memset (&prefix, 0, sizeof (struct prefix_ipv6)); + if (zapi_route_decode(zclient->ibuf, &api) < 0) + return -1; - /* Type, flags, message. */ - api.type = stream_getc (s); - api.instance = stream_getw (s); - api.flags = stream_getl (s); - api.message = stream_getc (s); + /* we completely ignore srcdest routes for now. */ + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) + return 0; - /* IPv6 prefix. */ - prefix.family = AF_INET6; - prefix.prefixlen = stream_getc (s); - stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen)); - - /* Nexthop, ifindex, distance, metric. */ - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { - api.nexthop_num = stream_getc (s); - stream_get (&nexthop, s, sizeof(nexthop)); - } - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { - api.ifindex_num = stream_getc (s); - ifindex = stream_getl (s); - } - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc (s); - else - api.distance = 0; - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl (s); - else - api.metric = 0; - - if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD) - babel_ipv6_route_add(&api, &prefix, ifindex, &nexthop); - else - babel_ipv6_route_delete(&api, &prefix, ifindex); - - return 0; -} - -static int -babel_zebra_read_ipv4 (int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf) -{ - struct stream *s; - struct zapi_ipv4 api; - unsigned long ifindex = -1; - struct in_addr nexthop; - struct prefix_ipv4 prefix; - - s = zclient->ibuf; - ifindex = 0; - memset (&nexthop, 0, sizeof (struct in_addr)); - memset (&api, 0, sizeof(struct zapi_ipv4)); - memset (&prefix, 0, sizeof (struct prefix_ipv4)); - - /* Type, flags, message. */ - api.type = stream_getc (s); - api.instance = stream_getw (s); - api.flags = stream_getl (s); - api.message = stream_getc (s); - - /* IPv6 prefix. */ - prefix.family = AF_INET; - prefix.prefixlen = stream_getc (s); - stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen)); - - /* Nexthop, ifindex, distance, metric. */ - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { - api.nexthop_num = stream_getc (s); - stream_get (&nexthop, s, sizeof(nexthop)); - } - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { - api.ifindex_num = stream_getc (s); - ifindex = stream_getl (s); - } - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc (s); - else - api.distance = 0; - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl (s); - else - api.metric = 0; - - if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD) { - babel_ipv4_route_add(&api, &prefix, ifindex, &nexthop); + if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) { + babel_route_add(&api); } else { - babel_ipv4_route_delete(&api, &prefix, ifindex); + babel_route_delete(&api); } return 0; @@ -310,6 +215,20 @@ debug_babel_config_write (struct vty * vty) #endif /* NO_DEBUG */ } +DEFUN_NOSH (show_debugging_babel, + show_debugging_babel_cmd, + "show debugging [babel]", + SHOW_STR + DEBUG_STR + "Babel") +{ + vty_out(vty, "BABEL debugging status\n"); + + debug_babel_config_write(vty); + + return CMD_SUCCESS; +} + static void babel_zebra_connected (struct zclient *zclient) { @@ -328,34 +247,16 @@ void babelz_zebra_init(void) zclient->interface_down = babel_interface_down; zclient->interface_address_add = babel_interface_address_add; zclient->interface_address_delete = babel_interface_address_delete; - zclient->redistribute_route_ipv4_add = babel_zebra_read_ipv4; - zclient->redistribute_route_ipv4_del = babel_zebra_read_ipv4; - zclient->redistribute_route_ipv6_add = babel_zebra_read_ipv6; - zclient->redistribute_route_ipv6_del = babel_zebra_read_ipv6; + zclient->redistribute_route_add = babel_zebra_read_route; + zclient->redistribute_route_del = babel_zebra_read_route; - install_node (&zebra_node, zebra_config_write); install_element(BABEL_NODE, &babel_redistribute_type_cmd); install_element(ENABLE_NODE, &debug_babel_cmd); install_element(ENABLE_NODE, &no_debug_babel_cmd); install_element(CONFIG_NODE, &debug_babel_cmd); install_element(CONFIG_NODE, &no_debug_babel_cmd); -} -static int -zebra_config_write (struct vty *vty) -{ - if (! zclient->enable) - { - vty_out (vty, "no router zebra\n"); - return 1; - } - else if (! vrf_bitmap_check (zclient->redist[AFI_IP][ZEBRA_ROUTE_BABEL], VRF_DEFAULT)) - { - vty_out (vty, "router zebra\n"); - vty_out (vty, " no redistribute babel\n"); - return 1; - } - return 0; + install_element(VIEW_NODE, &show_debugging_babel_cmd); } void diff --git a/babeld/babeld.c b/babeld/babeld.c index f995745e41..207c37d9b1 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -331,8 +331,8 @@ babel_main_loop(struct thread *thread) /* if there is no timeout, we must wait. */ if(timeval_compare(&tv, &babel_now) > 0) { timeval_minus(&tv, &tv, &babel_now); - debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %ld msecs", - tv.tv_sec * 1000 + tv.tv_usec / 1000); + debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %lld msecs", + (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000); /* it happens often to have less than 1 ms, it's bad. */ timeval_add_msec(&tv, &tv, 300); babel_set_timer(&tv); diff --git a/babeld/kernel.c b/babeld/kernel.c index 26860f3bae..394d7b1e81 100644 --- a/babeld/kernel.c +++ b/babeld/kernel.c @@ -51,13 +51,8 @@ THE SOFTWARE. static int -kernel_route_v4(int add, const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, - unsigned int metric); -static int -kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, - unsigned int metric); +zebra_route(int add, int familt, const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric); int kernel_interface_operational(struct interface *interface) @@ -84,7 +79,7 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen, unsigned int newmetric) { int rc; - int ipv4; + int family; /* Check that the protocol family is consistent. */ if(plen >= 96 && v4mapped(pref)) { @@ -92,46 +87,37 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen, errno = EINVAL; return -1; } - ipv4 = 1; + family = AF_INET; } else { if(v4mapped(gate)) { errno = EINVAL; return -1; } - ipv4 = 0; + family = AF_INET6; } switch (operation) { case ROUTE_ADD: - return ipv4 ? - kernel_route_v4(1, pref, plen, gate, ifindex, metric): - kernel_route_v6(1, pref, plen, gate, ifindex, metric); + return zebra_route(1, family, pref, plen, gate, ifindex, metric); break; case ROUTE_FLUSH: - return ipv4 ? - kernel_route_v4(0, pref, plen, gate, ifindex, metric): - kernel_route_v6(0, pref, plen, gate, ifindex, metric); + return zebra_route(0, family, pref, plen, gate, ifindex, metric); break; case ROUTE_MODIFY: if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && newifindex == ifindex) return 0; debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new."); - rc = ipv4 ? - kernel_route_v4(0, pref, plen, gate, ifindex, metric): - kernel_route_v6(0, pref, plen, gate, ifindex, metric); - + rc = zebra_route(0, family, pref, plen, gate, ifindex, metric); if (rc < 0) return -1; - rc = ipv4 ? - kernel_route_v4(1, pref, plen, newgate, newifindex, newmetric): - kernel_route_v6(1, pref, plen, newgate, newifindex, newmetric); - + rc = zebra_route(1, family, pref, plen, newgate, newifindex, + newmetric); return rc; break; default: - zlog_err("this should never appens (false value - kernel_route)"); + zlog_err("this should never happen (false value - kernel_route)"); assert(0); exit(1); break; @@ -139,110 +125,81 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen, } static int -kernel_route_v4(int add, - const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric) +zebra_route(int add, int family, const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric) { struct zapi_route api; /* quagga's communication system */ struct prefix quagga_prefix; /* quagga's prefix */ - struct in_addr babel_prefix_addr; /* babeld's prefix addr */ - struct nexthop nexthop; /* next router to go */ - struct nexthop *nexthop_pointer = &nexthop; /* it's an array! */ + union g_addr babel_prefix_addr; /* babeld's prefix addr */ + struct zapi_nexthop *api_nh; /* next router to go - no ECMP */ + + api_nh = &api.nexthops[0]; /* convert to be understandable by quagga */ /* convert given addresses */ - uchar_to_inaddr(&babel_prefix_addr, pref); - uchar_to_inaddr(&nexthop.gate.ipv4, gate); + switch (family) { + case AF_INET: + uchar_to_inaddr(&babel_prefix_addr.ipv4, pref); + break; + case AF_INET6: + uchar_to_in6addr(&babel_prefix_addr.ipv6, pref); + break; + } /* make prefix structure */ memset (&quagga_prefix, 0, sizeof(quagga_prefix)); - quagga_prefix.family = AF_INET; - IPV4_ADDR_COPY (&quagga_prefix.u.prefix4, &babel_prefix_addr); - quagga_prefix.prefixlen = plen - 96; /* our plen is for v4mapped's addr */ + quagga_prefix.family = family; + switch (family) { + case AF_INET: + IPV4_ADDR_COPY (&quagga_prefix.u.prefix4, &babel_prefix_addr.ipv4); + /* our plen is for v4mapped's addr */ + quagga_prefix.prefixlen = plen - 96; + break; + case AF_INET6: + IPV6_ADDR_COPY (&quagga_prefix.u.prefix6, &babel_prefix_addr.ipv6); + quagga_prefix.prefixlen = plen; + break; + } apply_mask(&quagga_prefix); memset(&api, 0, sizeof(api)); api.type = ZEBRA_ROUTE_BABEL; - api.flags = 0; - api.message = 0; - api.instance = 0; api.safi = SAFI_UNICAST; api.vrf_id = VRF_DEFAULT; + api.prefix = quagga_prefix; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); if(metric >= KERNEL_INFINITY) { api.flags = ZEBRA_FLAG_REJECT; - api.nexthop_num = 0; } else { + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; - api.nexthop = &nexthop_pointer; - nexthop.ifindex = ifindex; - if (IPV4_ADDR_SAME (&nexthop.gate.ipv4, &quagga_prefix.u.prefix4) && - quagga_prefix.prefixlen == 32) { - nexthop.type = NEXTHOP_TYPE_IFINDEX; - } else { - nexthop.type = NEXTHOP_TYPE_IPV4_IFINDEX; + api_nh->ifindex = ifindex; + + switch (family) { + case AF_INET: + uchar_to_inaddr(&api_nh->gate.ipv4, gate); + if (IPV4_ADDR_SAME (&api_nh->gate.ipv4, &quagga_prefix.u.prefix4) && + quagga_prefix.prefixlen == 32) { + api_nh->type = NEXTHOP_TYPE_IFINDEX; + } else { + api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; + } + break; + case AF_INET6: + uchar_to_in6addr(&api_nh->gate.ipv6, gate); + /* difference to IPv4: always leave the linklocal as nexthop */ + api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; + break; } SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; } - debugf(BABEL_DEBUG_ROUTE, "%s route (ipv4) to zebra", - add ? "adding" : "removing" ); - return zapi_route (add ? ZEBRA_IPV4_ROUTE_ADD : - ZEBRA_IPV4_ROUTE_DELETE, - zclient, &quagga_prefix, NULL, &api); -} - -static int -kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric) -{ - struct zapi_route api; /* quagga's communication system */ - struct prefix quagga_prefix; /* quagga's prefix */ - struct in6_addr babel_prefix_addr; /* babeld's prefix addr */ - struct nexthop nexthop; /* next router to go */ - struct nexthop *nexthop_pointer = &nexthop; - - /* convert to be understandable by quagga */ - /* convert given addresses */ - uchar_to_in6addr(&babel_prefix_addr, pref); - uchar_to_in6addr(&nexthop.gate.ipv6, gate); - - /* make prefix structure */ - memset (&quagga_prefix, 0, sizeof(quagga_prefix)); - quagga_prefix.family = AF_INET6; - IPV6_ADDR_COPY (&quagga_prefix.u.prefix6, &babel_prefix_addr); - quagga_prefix.prefixlen = plen; - apply_mask(&quagga_prefix); - - memset(&api, 0, sizeof(api)); - api.type = ZEBRA_ROUTE_BABEL; - api.flags = 0; - api.message = 0; - api.instance = 0; - api.safi = SAFI_UNICAST; - api.vrf_id = VRF_DEFAULT; - - if(metric >= KERNEL_INFINITY) { - api.flags = ZEBRA_FLAG_REJECT; - api.nexthop_num = 0; - } else { - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop_pointer; - nexthop.ifindex = ifindex; - /* difference to IPv4: always leave the linklocal as nexthop */ - nexthop.type = NEXTHOP_TYPE_IPV6_IFINDEX; - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; - } - - debugf(BABEL_DEBUG_ROUTE, "%s route (ipv6) to zebra", - add ? "adding" : "removing" ); - return zapi_route (add ? ZEBRA_IPV6_ROUTE_ADD : - ZEBRA_IPV6_ROUTE_DELETE, - zclient, &quagga_prefix, NULL, &api); + debugf(BABEL_DEBUG_ROUTE, "%s route (%s) to zebra", + add ? "adding" : "removing", + (family == AF_INET) ? "ipv4" : "ipv6"); + return zclient_route_send (add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, + zclient, &api); } int diff --git a/babeld/message.c b/babeld/message.c index 5990373b69..e31d5de5df 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -391,7 +391,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, } else if(type == MESSAGE_HELLO) { unsigned short seqno, interval; int changed; - unsigned int timestamp; + unsigned int timestamp = 0; DO_NTOHS(seqno, message + 4); DO_NTOHS(interval, message + 6); debugf(BABEL_DEBUG_COMMON,"Received hello %d (%d) from %s on %s.", diff --git a/babeld/xroute.c b/babeld/xroute.c index 2e123564ea..88e9479e4b 100644 --- a/babeld/xroute.c +++ b/babeld/xroute.c @@ -43,63 +43,54 @@ static int numxroutes = 0, maxxroutes = 0; /* Add redistributed route to Babel table. */ int -babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, - unsigned int ifindex, struct in_addr *nexthop) +babel_route_add (struct zapi_route *api) { unsigned char uchar_prefix[16]; - inaddr_to_uchar(uchar_prefix, &prefix->prefix); - debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route coming from Zebra."); - xroute_add_new_route(uchar_prefix, prefix->prefixlen + 96, - api->metric, ifindex, 0, 1); + switch (api->prefix.family) { + case AF_INET: + inaddr_to_uchar(uchar_prefix, &api->prefix.u.prefix4); + debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route coming from Zebra."); + xroute_add_new_route(uchar_prefix, api->prefix.prefixlen + 96, + api->metric, api->nexthops[0].ifindex, 0, 1); + break; + case AF_INET6: + in6addr_to_uchar(uchar_prefix, &api->prefix.u.prefix6); + debugf(BABEL_DEBUG_ROUTE, "Adding new ipv6 route coming from Zebra."); + xroute_add_new_route(uchar_prefix, api->prefix.prefixlen, + api->metric, api->nexthops[0].ifindex, 0, 1); + break; + } + return 0; } /* Remove redistributed route from Babel table. */ int -babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, - unsigned int ifindex) +babel_route_delete (struct zapi_route *api) { unsigned char uchar_prefix[16]; struct xroute *xroute = NULL; - inaddr_to_uchar(uchar_prefix, &prefix->prefix); - xroute = find_xroute(uchar_prefix, prefix->prefixlen + 96); - if (xroute != NULL) { - debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra)."); - flush_xroute(xroute); + switch (api->prefix.family) { + case AF_INET: + inaddr_to_uchar(uchar_prefix, &api->prefix.u.prefix4); + xroute = find_xroute(uchar_prefix, api->prefix.prefixlen + 96); + if (xroute != NULL) { + debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra)."); + flush_xroute(xroute); + } + break; + case AF_INET6: + in6addr_to_uchar(uchar_prefix, &api->prefix.u.prefix6); + xroute = find_xroute(uchar_prefix, api->prefix.prefixlen); + if (xroute != NULL) { + debugf(BABEL_DEBUG_ROUTE, "Removing ipv6 route (from zebra)."); + flush_xroute(xroute); + } + break; } - return 0; -} -/* Add redistributed route to Babel table. */ -int -babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, - unsigned int ifindex, struct in6_addr *nexthop) -{ - unsigned char uchar_prefix[16]; - - in6addr_to_uchar(uchar_prefix, &prefix->prefix); - debugf(BABEL_DEBUG_ROUTE, "Adding new route coming from Zebra."); - xroute_add_new_route(uchar_prefix, prefix->prefixlen, api->metric, ifindex, - 0, 1); - return 0; -} - -/* Remove redistributed route from Babel table. */ -int -babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, - unsigned int ifindex) -{ - unsigned char uchar_prefix[16]; - struct xroute *xroute = NULL; - - in6addr_to_uchar(uchar_prefix, &prefix->prefix); - xroute = find_xroute(uchar_prefix, prefix->prefixlen); - if (xroute != NULL) { - debugf(BABEL_DEBUG_ROUTE, "Removing route (from zebra)."); - flush_xroute(xroute); - } return 0; } diff --git a/babeld/xroute.h b/babeld/xroute.h index 27899e62a1..59afccb590 100644 --- a/babeld/xroute.h +++ b/babeld/xroute.h @@ -36,14 +36,8 @@ struct xroute_stream; struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen); void flush_xroute(struct xroute *xroute); -int babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, - unsigned int ifindex, struct in_addr *nexthop); -int babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, - unsigned int ifindex); -int babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, - unsigned int ifindex, struct in6_addr *nexthop); -int babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, - unsigned int ifindex); +int babel_route_add (struct zapi_route *api); +int babel_route_delete (struct zapi_route *api); int xroutes_estimate(void); struct xroute_stream *xroute_stream(void); struct xroute *xroute_stream_next(struct xroute_stream *stream); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 324813c085..4dd38459f8 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -72,7 +72,7 @@ struct bgp_attr_encap_subtlv { unsigned long refcnt; uint16_t type; uint16_t length; - uint8_t value[1]; /* will be extended */ + uint8_t value[0]; /* will be extended */ }; #if ENABLE_BGP_VNC diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index bcb3c5fc18..c1c4f2b39c 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -1615,12 +1615,12 @@ DEFUN (no_debug_bgp, return CMD_SUCCESS; } -DEFUN (show_debugging_bgp, - show_debugging_bgp_cmd, - "show debugging bgp", - SHOW_STR - DEBUG_STR - BGP_STR) +DEFUN_NOSH (show_debugging_bgp, + show_debugging_bgp_cmd, + "show debugging [bgp]", + SHOW_STR + DEBUG_STR + BGP_STR) { vty_out(vty, "BGP debugging status:\n"); diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 25a562ed68..fa8c45b004 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -140,11 +140,8 @@ __attribute__((__noreturn__)) void sigint(void) { zlog_notice("Terminating on signal"); - if (!retain_mode) { + if (!retain_mode) bgp_terminate(); - if (bgpd_privs.user) /* NULL if skip_runas flag set */ - zprivs_terminate(&bgpd_privs); - } bgp_exit(0); @@ -172,13 +169,12 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) /* it only makes sense for this to be called on a clean exit */ assert(status == 0); + frr_early_fini(); + bfd_gbl_exit(); bgp_close(); - if (retain_mode) - if_add_hook(IF_DELETE_HOOK, NULL); - /* reverse bgp_master_init */ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) bgp_delete(bgp); @@ -214,24 +210,15 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) community_list_terminate(bgp_clist); bgp_vrf_terminate(); - cmd_terminate(); - vty_terminate(); #if ENABLE_BGP_VNC vnc_zebra_destroy(); #endif bgp_zebra_destroy(); - /* reverse bgp_master_init */ - if (bm->master) - thread_master_free(bm->master); - - closezlog(); - list_delete(bm->bgp); memset(bm, 0, sizeof(*bm)); - if (bgp_debug_count()) - log_memstats_stderr("bgpd"); + frr_fini(); exit(status); } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 36063af7cd..b18ed9c71f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -20,6 +20,7 @@ */ #include +#include #include "prefix.h" #include "linklist.h" @@ -2001,18 +2002,15 @@ int bgp_zebra_has_route_changed(struct bgp_node *rn, struct bgp_info *selected) struct bgp_process_queue { struct bgp *bgp; - struct bgp_node *rn; - afi_t afi; - safi_t safi; + STAILQ_HEAD(, bgp_node)pqueue; +#define BGP_PROCESS_QUEUE_EOIU_MARKER (1 << 0) + unsigned int flags; + unsigned int queued; }; -static wq_item_status bgp_process_main(struct work_queue *wq, void *data) +static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn, + afi_t afi, safi_t safi) { - struct bgp_process_queue *pq = data; - struct bgp *bgp = pq->bgp; - struct bgp_node *rn = pq->rn; - afi_t afi = pq->afi; - safi_t safi = pq->safi; struct prefix *p = &rn->p; struct bgp_info *new_select; struct bgp_info *old_select; @@ -2033,7 +2031,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data) bgp->main_peers_update_hold = 0; bgp_start_routeadv(bgp); - return WQ_SUCCESS; + return; } /* Best path selection. */ @@ -2045,11 +2043,9 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data) /* Do we need to allocate or free labels? * Right now, since we only deal with per-prefix labels, it is not * necessary to do this upon changes to best path except if the label - * index changes. - * NOTE: This is only relevant for the default instance. + * index changes */ - if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT - && safi == SAFI_UNICAST) { + if (bgp->allocate_mpls_labels[afi][safi]) { if (new_select) { if (!old_select || bgp_label_index_differs(new_select, old_select) @@ -2070,8 +2066,11 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data) } else bgp_register_for_label(rn, new_select); } - } else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) + } else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) { bgp_unregister_for_label(rn); + } + } else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) { + bgp_unregister_for_label(rn); } /* If best route remains the same and this is not due to user-initiated @@ -2115,7 +2114,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data) } UNSET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED); - return WQ_SUCCESS; + return; } /* If the user did "clear ip bgp prefix x.x.x.x" this flag will be set @@ -2193,21 +2192,42 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data) bgp_info_reap(rn, old_select); UNSET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED); + return; +} + +static wq_item_status bgp_process_wq(struct work_queue *wq, void *data) +{ + struct bgp_process_queue *pqnode = data; + struct bgp *bgp = pqnode->bgp; + struct bgp_table *table; + struct bgp_node *rn, *nrn; + + /* eoiu marker */ + if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER)) { + bgp_process_main_one(bgp, NULL, 0, 0); + + return WQ_SUCCESS; + } + + STAILQ_FOREACH_SAFE(rn, &pqnode->pqueue, pq, nrn) { + table = bgp_node_table(rn); + + bgp_process_main_one(bgp, rn, table->afi, table->safi); + + bgp_unlock_node(rn); + bgp_table_unlock(table); + } + return WQ_SUCCESS; } static void bgp_processq_del(struct work_queue *wq, void *data) { - struct bgp_process_queue *pq = data; - struct bgp_table *table; + struct bgp_process_queue *pqnode = data; - bgp_unlock(pq->bgp); - if (pq->rn) { - table = bgp_node_table(pq->rn); - bgp_unlock_node(pq->rn); - bgp_table_unlock(table); - } - XFREE(MTYPE_BGP_PROCESS_QUEUE, pq); + bgp_unlock(pqnode->bgp); + + XFREE(MTYPE_BGP_PROCESS_QUEUE, pqnode); } void bgp_process_queue_init(void) @@ -2222,7 +2242,7 @@ void bgp_process_queue_init(void) } } - bm->process_main_queue->spec.workfunc = &bgp_process_main; + bm->process_main_queue->spec.workfunc = &bgp_process_wq; bm->process_main_queue->spec.del_item_data = &bgp_processq_del; bm->process_main_queue->spec.max_retries = 0; bm->process_main_queue->spec.hold = 50; @@ -2230,31 +2250,56 @@ void bgp_process_queue_init(void) bm->process_main_queue->spec.yield = 50 * 1000L; } +static struct bgp_process_queue *bgp_process_queue_work(struct work_queue *wq, + struct bgp *bgp) +{ + struct bgp_process_queue *pqnode; + + pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE, sizeof(struct bgp_process_queue)); + + /* unlocked in bgp_processq_del */ + pqnode->bgp = bgp_lock(bgp); + STAILQ_INIT(&pqnode->pqueue); + + work_queue_add(wq, pqnode); + + return pqnode; +} + void bgp_process(struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) { +#define ARBITRARY_PROCESS_QLEN 10000 + struct work_queue *wq = bm->process_main_queue; struct bgp_process_queue *pqnode; /* already scheduled for processing? */ if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED)) return; - if (bm->process_main_queue == NULL) + if (wq == NULL) return; - pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE, - sizeof(struct bgp_process_queue)); - if (!pqnode) - return; + /* Add route nodes to an existing work queue item until reaching the + limit only if is from the same BGP view and it's not an EOIU marker */ + if (work_queue_item_count(wq)) { + struct work_queue_item *item = work_queue_last_item(wq); + pqnode = item->data; - /* all unlocked in bgp_processq_del */ + if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) || + pqnode->bgp != bgp || pqnode->queued >= ARBITRARY_PROCESS_QLEN) + pqnode = bgp_process_queue_work(wq, bgp); + } else + pqnode = bgp_process_queue_work(wq, bgp); + + /* all unlocked in bgp_process_wq */ bgp_table_lock(bgp_node_table(rn)); - pqnode->rn = bgp_lock_node(rn); - pqnode->bgp = bgp; - bgp_lock(bgp); - pqnode->afi = afi; - pqnode->safi = safi; - work_queue_add(bm->process_main_queue, pqnode); + SET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED); + bgp_lock_node(rn); + + STAILQ_INSERT_TAIL(&pqnode->pqueue, rn, pq); + pqnode->queued++; + return; } @@ -2265,15 +2310,9 @@ void bgp_add_eoiu_mark(struct bgp *bgp) if (bm->process_main_queue == NULL) return; - pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE, - sizeof(struct bgp_process_queue)); - if (!pqnode) - return; + pqnode = bgp_process_queue_work(bm->process_main_queue, bgp); - pqnode->rn = NULL; - pqnode->bgp = bgp; - bgp_lock(bgp); - work_queue_add(bm->process_main_queue, pqnode); + SET_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER); } static int bgp_maximum_prefix_restart_timer(struct thread *thread) @@ -6050,8 +6089,7 @@ DEFUN (no_ipv6_aggregate_address, /* Redistribute route treatment. */ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, - const struct in_addr *nexthop, - const struct in6_addr *nexthop6, unsigned int ifindex, + const union g_addr *nexthop, unsigned int ifindex, u_int32_t metric, u_char type, u_short instance, route_tag_t tag) { @@ -6067,14 +6105,17 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, /* Make default attribute. */ bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE); - if (nexthop) - attr.nexthop = *nexthop; - attr.nh_ifindex = ifindex; - - if (nexthop6) { - attr.mp_nexthop_global = *nexthop6; - attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; + if (nexthop) { + switch (p->family) { + case AF_INET: + attr.nexthop = nexthop->ipv4; + break; + case AF_INET6: + attr.mp_nexthop_global = nexthop->ipv6; + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; + } } + attr.nh_ifindex = ifindex; attr.med = metric; attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); @@ -8002,7 +8043,8 @@ static int bgp_show_community_list(struct vty *vty, struct bgp *bgp, static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp, const char *prefix, afi_t afi, safi_t safi, enum bgp_show_type type); -static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi, +static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, + const char *regstr, afi_t afi, safi_t safi, enum bgp_show_type type); static int bgp_show_community(struct vty *vty, struct bgp *bgp, int argc, struct cmd_token **argv, int exact, afi_t afi, @@ -8820,32 +8862,28 @@ DEFUN (show_ip_bgp_large_community, static int bgp_table_stats(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi); -/* BGP route print out function. */ + +/* BGP route print out function without JSON */ DEFUN (show_ip_bgp, show_ip_bgp_cmd, "show [ip] bgp [ VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]\ - [<\ - cidr-only\ - |dampening \ - |route-map WORD\ - |prefix-list WORD\ - |filter-list WORD\ - |statistics\ - |community [ [exact-match]]\ - |community-list <(1-500)|WORD> [exact-match]\ - |A.B.C.D/M longer-prefixes\ - |X:X::X:X/M longer-prefixes>\ - ] [json]", + \ + |route-map WORD\ + |prefix-list WORD\ + |filter-list WORD\ + |statistics\ + |community [exact-match]\ + |community-list <(1-500)|WORD> [exact-match]\ + |A.B.C.D/M longer-prefixes\ + |X:X::X:X/M longer-prefixes\ + >", SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR BGP_SAFI_WITH_LABEL_HELP_STR - "Display only routes with non-natural netmasks\n" "Display detailed information about dampening\n" - "Display flap statistics of routes\n" - "Display paths suppressed due to dampening\n" "Display detail of configured dampening parameters\n" "Display routes matching the route-map\n" "A route-map to match on\n" @@ -8867,13 +8905,11 @@ DEFUN (show_ip_bgp, "IPv4 prefix\n" "Display route and more specific routes\n" "IPv6 prefix\n" - "Display route and more specific routes\n" - JSON_STR) + "Display route and more specific routes\n") { afi_t afi = AFI_IP6; safi_t safi = SAFI_UNICAST; int exact_match = 0; - enum bgp_show_type sh_type = bgp_show_type_normal; struct bgp *bgp = NULL; int idx = 0; @@ -8882,23 +8918,8 @@ DEFUN (show_ip_bgp, if (!idx) return CMD_WARNING; - int uj = use_json(argc, argv); - if (uj) - argc--; - - if (argv_find(argv, argc, "cidr-only", &idx)) - return bgp_show(vty, bgp, afi, safi, bgp_show_type_cidr_only, - NULL, uj); - if (argv_find(argv, argc, "dampening", &idx)) { - if (argv_find(argv, argc, "dampened-paths", &idx)) - return bgp_show(vty, bgp, afi, safi, - bgp_show_type_dampend_paths, NULL, uj); - else if (argv_find(argv, argc, "flap-statistics", &idx)) - return bgp_show(vty, bgp, afi, safi, - bgp_show_type_flap_statistics, NULL, - uj); - else if (argv_find(argv, argc, "parameters", &idx)) + if (argv_find(argv, argc, "parameters", &idx)) return bgp_show_dampening_parameters(vty, afi, safi); } @@ -8927,10 +8948,6 @@ DEFUN (show_ip_bgp, return bgp_show_community(vty, bgp, argc, argv, exact_match, afi, safi); } - /* show all communities */ - else - return bgp_show(vty, bgp, afi, safi, - bgp_show_type_community_all, NULL, uj); } if (argv_find(argv, argc, "community-list", &idx)) { @@ -8947,6 +8964,66 @@ DEFUN (show_ip_bgp, safi, bgp_show_type_prefix_longer); + return CMD_WARNING; +} + +/* BGP route print out function with JSON */ +DEFUN (show_ip_bgp_json, + show_ip_bgp_json_cmd, + "show [ip] bgp [ VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]\ + [<\ + cidr-only\ + |dampening \ + |community \ + >] [json]", + SHOW_STR + IP_STR + BGP_STR + BGP_INSTANCE_HELP_STR + BGP_AFI_HELP_STR + BGP_SAFI_WITH_LABEL_HELP_STR + "Display only routes with non-natural netmasks\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display paths suppressed due to dampening\n" + "Display routes matching the communities\n" + JSON_STR) +{ + afi_t afi = AFI_IP6; + safi_t safi = SAFI_UNICAST; + enum bgp_show_type sh_type = bgp_show_type_normal; + struct bgp *bgp = NULL; + int idx = 0; + + bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, + &bgp); + if (!idx) + return CMD_WARNING; + + int uj = use_json(argc, argv); + if (uj) + argc--; + + if (argv_find(argv, argc, "cidr-only", &idx)) + return bgp_show(vty, bgp, afi, safi, bgp_show_type_cidr_only, + NULL, uj); + + if (argv_find(argv, argc, "dampening", &idx)) { + if (argv_find(argv, argc, "dampened-paths", &idx)) + return bgp_show(vty, bgp, afi, safi, + bgp_show_type_dampend_paths, NULL, uj); + else if (argv_find(argv, argc, "flap-statistics", &idx)) + return bgp_show(vty, bgp, afi, safi, + bgp_show_type_flap_statistics, NULL, + uj); + } + + if (argv_find(argv, argc, "community", &idx)) { + /* show all communities */ + return bgp_show(vty, bgp, afi, safi, + bgp_show_type_community_all, NULL, uj); + } + if (safi == SAFI_MPLS_VPN) return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_normal, NULL, 0, uj); @@ -9056,7 +9133,7 @@ DEFUN (show_ip_bgp_regexp, idx++; char *regstr = argv_concat(argv, argc, idx); - int rc = bgp_show_regexp(vty, (const char *)regstr, afi, safi, + int rc = bgp_show_regexp(vty, bgp, (const char *)regstr, afi, safi, bgp_show_type_regexp); XFREE(MTYPE_TMP, regstr); return rc; @@ -9091,7 +9168,8 @@ DEFUN (show_ip_bgp_instance_all, return CMD_SUCCESS; } -static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi, +static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, + const char *regstr, afi_t afi, safi_t safi, enum bgp_show_type type) { regex_t *regex; @@ -9103,7 +9181,7 @@ static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi, return CMD_WARNING; } - rc = bgp_show(vty, NULL, afi, safi, type, regex, 0); + rc = bgp_show(vty, bgp, afi, safi, type, regex, 0); bgp_regex_free(regex); return rc; } @@ -9332,6 +9410,7 @@ static const char *table_stats_strs[] = { struct bgp_table_stats { struct bgp_table *table; unsigned long long counts[BGP_STATS_MAX]; + double total_space; }; #if 0 @@ -9400,8 +9479,8 @@ static int bgp_table_stats_walker(struct thread *t) ts->counts[BGP_STATS_UNAGGREGATEABLE]++; /* announced address space */ if (space) - ts->counts[BGP_STATS_SPACE] += - 1 << (space - rn->p.prefixlen); + ts->total_space += pow(2.0, + space - rn->p.prefixlen); } else if (prn->info) ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++; @@ -9511,31 +9590,26 @@ static int bgp_table_stats(struct vty *vty, struct bgp *bgp, afi_t afi, break; case BGP_STATS_SPACE: vty_out(vty, "%-30s: ", table_stats_strs[i]); - vty_out(vty, "%12llu\n", ts.counts[i]); - if (ts.counts[BGP_STATS_MAXBITLEN] < 9) - break; - vty_out(vty, "%30s: ", "%% announced "); - vty_out(vty, "%12.2f\n", - 100 * (float)ts.counts[BGP_STATS_SPACE] - / (float)((uint64_t)1UL - << ts.counts - [BGP_STATS_MAXBITLEN])); - vty_out(vty, "%30s: ", "/8 equivalent "); - vty_out(vty, "%12.2f\n", - (float)ts.counts[BGP_STATS_SPACE] - / (float)(1UL - << (ts.counts - [BGP_STATS_MAXBITLEN] - - 8))); - if (ts.counts[BGP_STATS_MAXBITLEN] < 25) - break; - vty_out(vty, "%30s: ", "/24 equivalent "); - vty_out(vty, "%12.2f", - (float)ts.counts[BGP_STATS_SPACE] - / (float)(1UL - << (ts.counts - [BGP_STATS_MAXBITLEN] - - 24))); + vty_out(vty, "%12g\n", ts.total_space); + + if (afi == AFI_IP6) { + vty_out(vty, "%30s: ", "/32 equivalent "); + vty_out(vty, "%12g\n", + ts.total_space * pow(2.0, -128+32)); + vty_out(vty, "%30s: ", "/48 equivalent "); + vty_out(vty, "%12g\n", + ts.total_space * pow(2.0, -128+48)); + } else { + vty_out(vty, "%30s: ", "% announced "); + vty_out(vty, "%12.2f\n", + ts.total_space * 100. * pow(2.0, -32)); + vty_out(vty, "%30s: ", "/8 equivalent "); + vty_out(vty, "%12.2f\n", + ts.total_space * pow(2.0, -32+8)); + vty_out(vty, "%30s: ", "/24 equivalent "); + vty_out(vty, "%12.2f\n", + ts.total_space * pow(2.0, -32+24)); + } break; default: vty_out(vty, "%-30s: ", table_stats_strs[i]); @@ -11265,6 +11339,7 @@ void bgp_route_init(void) /* IPv4 labeled-unicast configuration. */ install_element(VIEW_NODE, &show_ip_bgp_instance_all_cmd); install_element(VIEW_NODE, &show_ip_bgp_cmd); + install_element(VIEW_NODE, &show_ip_bgp_json_cmd); install_element(VIEW_NODE, &show_ip_bgp_route_cmd); install_element(VIEW_NODE, &show_ip_bgp_regexp_cmd); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 93d79e5059..1767494ac1 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -22,6 +22,7 @@ #define _QUAGGA_BGP_ROUTE_H #include "queue.h" +#include "nexthop.h" #include "bgp_table.h" struct bgp_nexthop_cache; @@ -328,8 +329,7 @@ extern int bgp_nlri_parse_ip(struct peer *, struct attr *, struct bgp_nlri *); extern int bgp_maximum_prefix_overflow(struct peer *, afi_t, safi_t, int); extern void bgp_redistribute_add(struct bgp *, struct prefix *, - const struct in_addr *, - const struct in6_addr *, unsigned int ifindex, + const union g_addr *, unsigned int ifindex, u_int32_t, u_char, u_short, route_tag_t); extern void bgp_redistribute_delete(struct bgp *, struct prefix *, u_char, u_short); diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 0d5706f7cb..a4f3b604c2 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -23,6 +23,7 @@ #include "mpls.h" #include "table.h" +#include "queue.h" struct bgp_table { /* afi/safi of this table */ @@ -52,6 +53,8 @@ struct bgp_node { struct bgp_node *prn; + STAILQ_ENTRY(bgp_node) pq; + mpls_label_t local_label; uint64_t version; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index c333d4df2c..761c586415 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -6145,6 +6145,8 @@ DEFUN (clear_ip_bgp_all, IP_STR BGP_STR BGP_INSTANCE_HELP_STR + BGP_AFI_HELP_STR + BGP_SAFI_WITH_LABEL_HELP_STR "Clear all peers\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" @@ -6153,8 +6155,6 @@ DEFUN (clear_ip_bgp_all, "Clear all external peers\n" "Clear all members of peer-group\n" "BGP peer-group name\n" - BGP_AFI_HELP_STR - BGP_SAFI_WITH_LABEL_HELP_STR BGP_SOFT_STR BGP_SOFT_IN_STR BGP_SOFT_OUT_STR @@ -7071,26 +7071,6 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, return CMD_SUCCESS; } -/* - * Return if we have a peer configured to use this afi/safi - */ -static int bgp_show_summary_afi_safi_peer_exists(struct bgp *bgp, int afi, - int safi) -{ - struct listnode *node; - struct peer *peer; - - for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { - if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) - continue; - - if (peer->afc[afi][safi]) - return 1; - } - - return 0; -} - static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, int safi, u_char use_json, json_object *json) @@ -7109,8 +7089,7 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, if (safi_wildcard) safi = 1; /* SAFI_UNICAST */ while (safi < SAFI_MAX) { - if (bgp_show_summary_afi_safi_peer_exists(bgp, afi, - safi)) { + if (bgp_afi_safi_peer_exists(bgp, afi, safi)) { json_output = true; if (is_wildcard) { /* diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 2fc75ea5a2..9a092404d5 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -58,11 +58,6 @@ /* All information about zebra. */ struct zclient *zclient = NULL; -/* Growable buffer for nexthops sent to zebra */ -struct stream *bgp_nexthop_buf = NULL; -struct stream *bgp_ifindices_buf = NULL; -struct stream *bgp_label_buf = NULL; - /* These array buffers are used in making a copy of the attributes for route-map apply. Arrays are being used here to minimize mallocs and frees for the temporary copy of the attributes. @@ -559,75 +554,36 @@ static int bgp_interface_vrf_update(int command, struct zclient *zclient, } /* Zebra route add and delete treatment. */ -static int zebra_read_ipv4(int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf_id) +static int zebra_read_route(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) { - struct stream *s; - struct zapi_ipv4 api; - struct in_addr nexthop; - struct prefix_ipv4 p; + struct zapi_route api; + union g_addr nexthop; unsigned int ifindex; - int i; + int add, i; struct bgp *bgp; bgp = bgp_lookup_by_vrf_id(vrf_id); if (!bgp) return 0; - s = zclient->ibuf; - nexthop.s_addr = 0; + if (zapi_route_decode(zclient->ibuf, &api) < 0) + return -1; - /* Type, flags, message. */ - api.type = stream_getc(s); - api.instance = stream_getw(s); - api.flags = stream_getl(s); - api.message = stream_getc(s); + /* we completely ignore srcdest routes for now. */ + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) + return 0; - /* IPv4 prefix. */ - memset(&p, 0, sizeof(struct prefix_ipv4)); - p.family = AF_INET; - p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc(s)); - stream_get(&p.prefix, s, PSIZE(p.prefixlen)); + /* ignore link-local address. */ + if (api.prefix.family == AF_INET6 + && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6)) + return 0; - /* Nexthop, ifindex, distance, metric. */ - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { - api.nexthop_num = stream_getc(s); - nexthop.s_addr = stream_get_ipv4(s); - } - - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) { - api.ifindex_num = stream_getc(s); - ifindex = stream_getl(s); /* ifindex, unused */ - } else { - ifindex = 0; - } - - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc(s); - - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl(s); - else - api.metric = 0; - - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG)) - api.tag = stream_getl(s); - else - api.tag = 0; - - if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD) { - if (bgp_debug_zebra((struct prefix *)&p)) { - char buf[2][INET_ADDRSTRLEN]; - zlog_debug( - "Rx IPv4 route add VRF %u %s[%d] %s/%d nexthop %s metric %u tag %" ROUTE_TAG_PRI, - vrf_id, zebra_route_string(api.type), - api.instance, inet_ntop(AF_INET, &p.prefix, - buf[0], sizeof(buf[0])), - p.prefixlen, inet_ntop(AF_INET, &nexthop, - buf[1], sizeof(buf[1])), - api.metric, api.tag); - } + nexthop = api.nexthops[0].gate; + ifindex = api.nexthops[0].ifindex; + add = (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD); + if (add) { /* * The ADD message is actually an UPDATE and there is no * explicit DEL @@ -639,156 +595,30 @@ static int zebra_read_ipv4(int command, struct zclient *zclient, */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (i != api.type) - bgp_redistribute_delete(bgp, - (struct prefix *)&p, i, + bgp_redistribute_delete(bgp, &api.prefix, i, api.instance); } /* Now perform the add/update. */ - bgp_redistribute_add(bgp, (struct prefix *)&p, &nexthop, NULL, - ifindex, api.metric, api.type, - api.instance, api.tag); - } else if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL) { - if (bgp_debug_zebra((struct prefix *)&p)) { - char buf[2][INET_ADDRSTRLEN]; - zlog_debug( - "Rx IPv4 route delete VRF %u %s[%d] %s/%d " - "nexthop %s metric %u tag %" ROUTE_TAG_PRI, - vrf_id, zebra_route_string(api.type), - api.instance, inet_ntop(AF_INET, &p.prefix, - buf[0], sizeof(buf[0])), - p.prefixlen, inet_ntop(AF_INET, &nexthop, - buf[1], sizeof(buf[1])), - api.metric, api.tag); - } - bgp_redistribute_delete(bgp, (struct prefix *)&p, api.type, - api.instance); - } - - return 0; -} - -/* Zebra route add and delete treatment. */ -static int zebra_read_ipv6(int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf_id) -{ - struct stream *s; - struct zapi_ipv6 api; - struct in6_addr nexthop; - struct prefix_ipv6 p, src_p; - unsigned int ifindex; - int i; - struct bgp *bgp; - - bgp = bgp_lookup_by_vrf_id(vrf_id); - if (!bgp) - return 0; - - s = zclient->ibuf; - memset(&nexthop, 0, sizeof(struct in6_addr)); - - /* Type, flags, message. */ - api.type = stream_getc(s); - api.instance = stream_getw(s); - api.flags = stream_getl(s); - api.message = stream_getc(s); - - /* IPv6 prefix. */ - memset(&p, 0, sizeof(struct prefix_ipv6)); - p.family = AF_INET6; - p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc(s)); - stream_get(&p.prefix, s, PSIZE(p.prefixlen)); - - memset(&src_p, 0, sizeof(struct prefix_ipv6)); - src_p.family = AF_INET6; - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) { - src_p.prefixlen = stream_getc(s); - stream_get(&src_p.prefix, s, PSIZE(src_p.prefixlen)); - } - - if (src_p.prefixlen) - /* we completely ignore srcdest routes for now. */ - return 0; - - /* Nexthop, ifindex, distance, metric. */ - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { - api.nexthop_num = stream_getc(s); - stream_get(&nexthop, s, 16); - } - - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) { - api.ifindex_num = stream_getc(s); - ifindex = stream_getl(s); /* ifindex, unused */ + bgp_redistribute_add(bgp, &api.prefix, &nexthop, ifindex, + api.metric, api.type, api.instance, + api.tag); } else { - ifindex = 0; + bgp_redistribute_delete(bgp, &api.prefix, api.type, + api.instance); } - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc(s); - else - api.distance = 0; + if (bgp_debug_zebra(&api.prefix)) { + char buf[2][PREFIX_STRLEN]; - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl(s); - else - api.metric = 0; - - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG)) - api.tag = stream_getl(s); - else - api.tag = 0; - - /* Simply ignore link-local address. */ - if (IN6_IS_ADDR_LINKLOCAL(&p.prefix)) - return 0; - - if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD) { - if (bgp_debug_zebra((struct prefix *)&p)) { - char buf[2][INET6_ADDRSTRLEN]; - zlog_debug( - "Rx IPv6 route add VRF %u %s[%d] %s/%d nexthop %s metric %u tag %" ROUTE_TAG_PRI, - vrf_id, zebra_route_string(api.type), - api.instance, inet_ntop(AF_INET6, &p.prefix, - buf[0], sizeof(buf[0])), - p.prefixlen, inet_ntop(AF_INET, &nexthop, - buf[1], sizeof(buf[1])), - api.metric, api.tag); - } - - /* - * The ADD message is actually an UPDATE and there is no - * explicit DEL - * for a prior redistributed route, if any. So, perform an - * implicit - * DEL processing for the same redistributed route from any - * other - * source type. - */ - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (i != api.type) - bgp_redistribute_delete(bgp, - (struct prefix *)&p, i, - api.instance); - } - - bgp_redistribute_add(bgp, (struct prefix *)&p, NULL, &nexthop, - ifindex, api.metric, api.type, - api.instance, api.tag); - } else if (command == ZEBRA_REDISTRIBUTE_IPV6_DEL) { - if (bgp_debug_zebra((struct prefix *)&p)) { - char buf[2][INET6_ADDRSTRLEN]; - zlog_debug( - "Rx IPv6 route delete VRF %u %s[%d] %s/%d " - "nexthop %s metric %u tag %" ROUTE_TAG_PRI, - vrf_id, zebra_route_string(api.type), - api.instance, inet_ntop(AF_INET6, &p.prefix, - buf[0], sizeof(buf[0])), - p.prefixlen, inet_ntop(AF_INET6, &nexthop, - buf[1], sizeof(buf[1])), - api.metric, api.tag); - } - bgp_redistribute_delete(bgp, (struct prefix *)&p, api.type, - api.instance); + prefix2str(&api.prefix, buf[0], sizeof(buf[0])); + inet_ntop(api.prefix.family, &nexthop, buf[1], sizeof(buf[1])); + zlog_debug( + "Rx route %s VRF %u %s[%d] %s " + "nexthop %s metric %u tag %" ROUTE_TAG_PRI, + (add) ? "add" : "delete", vrf_id, + zebra_route_string(api.type), api.instance, buf[0], + buf[1], api.metric, api.tag); } return 0; @@ -1153,7 +983,11 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, struct bgp_info *info, struct bgp *bgp, afi_t afi, safi_t safi) { - u_int32_t flags; + struct zapi_route api; + struct zapi_nexthop *api_nh; + int nh_family; + int valid_nh_count = 0; + int has_valid_label = 0; u_char distance; struct peer *peer; struct bgp_info *mpinfo; @@ -1169,18 +1003,17 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, if (!bgp_install_info_to_zebra(bgp)) return; - if ((p->family == AF_INET - && !vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_BGP], - bgp->vrf_id)) - || (p->family == AF_INET6 - && !vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_BGP], - bgp->vrf_id))) - return; - if (bgp->main_zebra_update_hold) return; - flags = 0; + /* Make Zebra API structure. */ + memset(&api, 0, sizeof(api)); + api.vrf_id = bgp->vrf_id; + api.type = ZEBRA_ROUTE_BGP; + api.safi = safi; + api.prefix = *p; + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + peer = info->peer; tag = info->attr->tag; @@ -1189,40 +1022,39 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, * in * the RIB */ if (info->sub_type == BGP_ROUTE_AGGREGATE) - SET_FLAG(flags, ZEBRA_FLAG_BLACKHOLE); + SET_FLAG(api.flags, ZEBRA_FLAG_BLACKHOLE); if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || info->sub_type == BGP_ROUTE_AGGREGATE) { - SET_FLAG(flags, ZEBRA_FLAG_IBGP); - SET_FLAG(flags, ZEBRA_FLAG_INTERNAL); + SET_FLAG(api.flags, ZEBRA_FLAG_IBGP); + SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL); } if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) || bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) - SET_FLAG(flags, ZEBRA_FLAG_INTERNAL); + SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL); - if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(info->attr)) { - struct zapi_ipv4 api; - struct in_addr *nexthop; - char buf[2][INET_ADDRSTRLEN]; - int valid_nh_count = 0; - int has_valid_label = 0; + /* Get nexthop address-family */ + if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(info->attr)) + nh_family = AF_INET; + else if (p->family == AF_INET6 + || (p->family == AF_INET + && BGP_ATTR_NEXTHOP_AFI_IP6(info->attr))) + nh_family = AF_INET6; + else + return; - /* resize nexthop buffer size if necessary */ - stream_reset(bgp_nexthop_buf); - nexthop = NULL; + if (bgp->table_map[afi][safi].name) + BGP_INFO_ATTR_BUF_INIT(); - stream_reset(bgp_label_buf); + /* Metric is currently based on the best-path only */ + metric = info->attr->med; + for (mpinfo = info; mpinfo; mpinfo = bgp_info_mpath_next(mpinfo)) { + if (nh_family == AF_INET) { + struct in_addr *nexthop; - if (bgp->table_map[afi][safi].name) - BGP_INFO_ATTR_BUF_INIT(); - - /* Metric is currently based on the best-path only */ - metric = info->attr->med; - for (mpinfo = info; mpinfo; - mpinfo = bgp_info_mpath_next(mpinfo)) { nexthop = NULL; if (bgp->table_map[afi][safi].name) { @@ -1234,8 +1066,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, bgp->table_map[afi][safi].map, p, info_cp)) { if (mpinfo == info) { - /* Metric is currently based on - * the best-path only */ metric = info_cp->attr->med; tag = info_cp->attr->tag; } @@ -1248,118 +1078,13 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, if (nexthop == NULL) continue; - stream_put(bgp_nexthop_buf, &nexthop, - sizeof(struct in_addr *)); - if (mpinfo->extra - && bgp_is_valid_label(&mpinfo->extra->label)) { - has_valid_label = 1; - label = label_pton(&mpinfo->extra->label); - stream_put(bgp_label_buf, &label, - sizeof(mpls_label_t)); - } - valid_nh_count++; - } - - api.vrf_id = bgp->vrf_id; - api.flags = flags; - api.type = ZEBRA_ROUTE_BGP; - api.instance = 0; - api.message = 0; - api.safi = safi; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - - if (has_valid_label) - SET_FLAG(api.message, ZAPI_MESSAGE_LABEL); - - /* Note that this currently only applies to Null0 routes for - * aggregates. - * ZEBRA_FLAG_BLACKHOLE signals zapi_ipv4_route to encode a - * special - * BLACKHOLE nexthop. We want to set api.nexthop_num to zero - * since we - * do not want to also encode the 0.0.0.0 nexthop for the - * aggregate route. - */ - if (CHECK_FLAG(flags, ZEBRA_FLAG_BLACKHOLE)) - api.nexthop_num = 0; - else - api.nexthop_num = valid_nh_count; - - api.nexthop = (struct in_addr **)STREAM_DATA(bgp_nexthop_buf); - if (has_valid_label) { - api.label_num = valid_nh_count; - api.label = (unsigned int *)STREAM_DATA(bgp_label_buf); + api_nh = &api.nexthops[valid_nh_count]; + api_nh->gate.ipv4 = *nexthop; + api_nh->type = NEXTHOP_TYPE_IPV4; } else { - api.label_num = 0; - api.label = NULL; - } - api.ifindex_num = 0; - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; - api.tag = 0; + ifindex_t ifindex; + struct in6_addr *nexthop; - if (tag) { - SET_FLAG(api.message, ZAPI_MESSAGE_TAG); - api.tag = tag; - } - - distance = bgp_distance_apply(p, info, afi, safi, bgp); - if (distance) { - SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); - api.distance = distance; - } - - if (bgp_debug_zebra(p)) { - int i; - char label_buf[20]; - zlog_debug( - "Tx IPv4 route %s VRF %u %s/%d metric %u tag %" ROUTE_TAG_PRI - " count %d", - (valid_nh_count ? "add" : "delete"), - bgp->vrf_id, inet_ntop(AF_INET, &p->u.prefix4, - buf[0], sizeof(buf[0])), - p->prefixlen, api.metric, api.tag, - api.nexthop_num); - for (i = 0; i < api.nexthop_num; i++) { - label_buf[0] = '\0'; - if (has_valid_label) - sprintf(label_buf, "label %u", - api.label[i]); - zlog_debug(" nhop [%d]: %s %s", i + 1, - inet_ntop(AF_INET, api.nexthop[i], - buf[1], sizeof(buf[1])), - label_buf); - } - } - - zapi_ipv4_route(valid_nh_count ? ZEBRA_IPV4_ROUTE_ADD - : ZEBRA_IPV4_ROUTE_DELETE, - zclient, (struct prefix_ipv4 *)p, &api); - } - - /* We have to think about a IPv6 link-local address curse. */ - if (p->family == AF_INET6 - || (p->family == AF_INET && BGP_ATTR_NEXTHOP_AFI_IP6(info->attr))) { - ifindex_t ifindex; - struct in6_addr *nexthop; - struct zapi_ipv6 api; - int valid_nh_count = 0; - char buf[2][INET6_ADDRSTRLEN]; - int has_valid_label = 0; - - stream_reset(bgp_nexthop_buf); - stream_reset(bgp_ifindices_buf); - stream_reset(bgp_label_buf); - - ifindex = 0; - nexthop = NULL; - - if (bgp->table_map[afi][safi].name) - BGP_INFO_ATTR_BUF_INIT(); - - metric = info->attr->med; - for (mpinfo = info; mpinfo; - mpinfo = bgp_info_mpath_next(mpinfo)) { ifindex = 0; nexthop = NULL; @@ -1407,147 +1132,72 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, if (ifindex == 0) continue; - stream_put(bgp_nexthop_buf, &nexthop, - sizeof(struct in6_addr *)); - stream_put(bgp_ifindices_buf, &ifindex, - sizeof(unsigned int)); - - if (mpinfo->extra - && bgp_is_valid_label(&mpinfo->extra->label)) { - has_valid_label = 1; - label = label_pton(&mpinfo->extra->label); - stream_put(bgp_label_buf, &label, - sizeof(mpls_label_t)); - } - valid_nh_count++; + api_nh = &api.nexthops[valid_nh_count]; + api_nh->gate.ipv6 = *nexthop; + api_nh->ifindex = ifindex; + api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; } - /* Make Zebra API structure. */ - api.vrf_id = bgp->vrf_id; - api.flags = flags; - api.type = ZEBRA_ROUTE_BGP; - api.instance = 0; - api.message = 0; - api.safi = safi; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + if (mpinfo->extra + && bgp_is_valid_label(&mpinfo->extra->label)) { + has_valid_label = 1; + label = label_pton(&mpinfo->extra->label); - if (has_valid_label) - SET_FLAG(api.message, ZAPI_MESSAGE_LABEL); - - /* Note that this currently only applies to Null0 routes for - * aggregates. - * ZEBRA_FLAG_BLACKHOLE signals zapi_ipv6_route to encode a - * special - * BLACKHOLE nexthop. We want to set api.nexthop_num to zero - * since we - * do not want to also encode the :: nexthop for the aggregate - * route. - */ - if (CHECK_FLAG(flags, ZEBRA_FLAG_BLACKHOLE)) - api.nexthop_num = 0; - else - api.nexthop_num = valid_nh_count; - - api.nexthop = (struct in6_addr **)STREAM_DATA(bgp_nexthop_buf); - SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = valid_nh_count; - api.ifindex = (ifindex_t *)STREAM_DATA(bgp_ifindices_buf); - if (has_valid_label) { - api.label_num = valid_nh_count; - api.label = (unsigned int *)STREAM_DATA(bgp_label_buf); - } else { - api.label_num = 0; - api.label = NULL; + api_nh->label_num = 1; + api_nh->labels[0] = label; } - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; - api.tag = 0; + valid_nh_count++; + } - if (tag) { - SET_FLAG(api.message, ZAPI_MESSAGE_TAG); - api.tag = tag; - } + if (has_valid_label) + SET_FLAG(api.message, ZAPI_MESSAGE_LABEL); - distance = bgp_distance_apply(p, info, afi, safi, bgp); - if (distance) { - SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); - api.distance = distance; - } + if (!CHECK_FLAG(api.flags, ZEBRA_FLAG_BLACKHOLE)) + api.nexthop_num = valid_nh_count; - if (p->family == AF_INET) { - if (bgp_debug_zebra(p)) { - int i; - char label_buf[20]; - zlog_debug( - "Tx IPv4 route %s VRF %u %s/%d metric %u tag %" ROUTE_TAG_PRI, - valid_nh_count ? "add" : "delete", - bgp->vrf_id, - inet_ntop(AF_INET, &p->u.prefix4, - buf[0], sizeof(buf[0])), - p->prefixlen, api.metric, api.tag); - for (i = 0; i < api.nexthop_num; i++) { - label_buf[0] = '\0'; - if (has_valid_label) - sprintf(label_buf, "label %u", - api.label[i]); - zlog_debug( - " nhop [%d]: %s if %s %s", - i + 1, - inet_ntop(AF_INET6, - api.nexthop[i], - buf[1], - sizeof(buf[1])), - ifindex2ifname(api.ifindex[i], - bgp->vrf_id), - label_buf); - } - } + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; - if (valid_nh_count) - zapi_ipv4_route_ipv6_nexthop( - ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD, - zclient, (struct prefix_ipv4 *)p, - (struct zapi_ipv6 *)&api); - else - zapi_ipv4_route(ZEBRA_IPV4_ROUTE_DELETE, - zclient, - (struct prefix_ipv4 *)p, - (struct zapi_ipv4 *)&api); - } else { - if (bgp_debug_zebra(p)) { - int i; - char label_buf[20]; - zlog_debug( - "Tx IPv6 route %s VRF %u %s/%d metric %u tag %" ROUTE_TAG_PRI, - valid_nh_count ? "add" : "delete", - bgp->vrf_id, - inet_ntop(AF_INET6, &p->u.prefix6, - buf[0], sizeof(buf[0])), - p->prefixlen, api.metric, api.tag); - for (i = 0; i < api.nexthop_num; i++) { - label_buf[0] = '\0'; - if (has_valid_label) - sprintf(label_buf, "label %u", - api.label[i]); - zlog_debug( - " nhop [%d]: %s if %s %s", - i + 1, - inet_ntop(AF_INET6, - api.nexthop[i], - buf[1], - sizeof(buf[1])), - ifindex2ifname(api.ifindex[i], - bgp->vrf_id), - label_buf); - } - } + if (tag) { + SET_FLAG(api.message, ZAPI_MESSAGE_TAG); + api.tag = tag; + } - zapi_ipv6_route( - valid_nh_count ? ZEBRA_IPV6_ROUTE_ADD - : ZEBRA_IPV6_ROUTE_DELETE, - zclient, (struct prefix_ipv6 *)p, NULL, &api); + distance = bgp_distance_apply(p, info, afi, safi, bgp); + if (distance) { + SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = distance; + } + + if (bgp_debug_zebra(p)) { + char prefix_buf[PREFIX_STRLEN]; + char nh_buf[INET6_ADDRSTRLEN]; + char label_buf[20]; + int i; + + prefix2str(&api.prefix, prefix_buf, sizeof(prefix_buf)); + zlog_debug("Tx route %s VRF %u %s metric %u tag %" ROUTE_TAG_PRI + " count %d", + valid_nh_count ? "add" : "delete", bgp->vrf_id, + prefix_buf, api.metric, api.tag, api.nexthop_num); + for (i = 0; i < api.nexthop_num; i++) { + api_nh = &api.nexthops[i]; + + inet_ntop(nh_family, &api_nh->gate, nh_buf, + sizeof(nh_buf)); + + label_buf[0] = '\0'; + if (has_valid_label) + sprintf(label_buf, "label %u", + api_nh->labels[0]); + zlog_debug(" nhop [%d]: %s %s", i + 1, nh_buf, + label_buf); } } + + zclient_route_send(valid_nh_count ? ZEBRA_ROUTE_ADD + : ZEBRA_ROUTE_DELETE, + zclient, &api); } /* Announce all routes of a table to zebra */ @@ -1578,7 +1228,7 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi) void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi) { - u_int32_t flags; + struct zapi_route api; struct peer *peer; peer = info->peer; @@ -1590,101 +1240,30 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi) if (!bgp_install_info_to_zebra(peer->bgp)) return; - if ((p->family == AF_INET - && !vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_BGP], - peer->bgp->vrf_id)) - || (p->family == AF_INET6 - && !vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_BGP], - peer->bgp->vrf_id))) - return; - - flags = 0; + memset(&api, 0, sizeof(api)); + api.vrf_id = peer->bgp->vrf_id; + api.type = ZEBRA_ROUTE_BGP; + api.safi = safi; + api.prefix = *p; if (peer->sort == BGP_PEER_IBGP) { - SET_FLAG(flags, ZEBRA_FLAG_INTERNAL); - SET_FLAG(flags, ZEBRA_FLAG_IBGP); + SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL); + SET_FLAG(api.flags, ZEBRA_FLAG_IBGP); } if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) || bgp_flag_check(peer->bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) - SET_FLAG(flags, ZEBRA_FLAG_INTERNAL); + SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL); - if (p->family == AF_INET) { - struct zapi_ipv4 api; + if (bgp_debug_zebra(p)) { + char buf[PREFIX_STRLEN]; - api.vrf_id = peer->bgp->vrf_id; - api.flags = flags; - - api.type = ZEBRA_ROUTE_BGP; - api.instance = 0; - api.message = 0; - api.safi = safi; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 0; - api.nexthop = NULL; - api.label_num = 0; - api.label = NULL; - api.ifindex_num = 0; - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = info->attr->med; - api.tag = 0; - - if (info->attr->tag != 0) { - SET_FLAG(api.message, ZAPI_MESSAGE_TAG); - api.tag = info->attr->tag; - } - - if (bgp_debug_zebra(p)) { - char buf[2][INET_ADDRSTRLEN]; - zlog_debug( - "Tx IPv4 route delete VRF %u %s/%d metric %u tag %" ROUTE_TAG_PRI, - peer->bgp->vrf_id, - inet_ntop(AF_INET, &p->u.prefix4, buf[0], - sizeof(buf[0])), - p->prefixlen, api.metric, api.tag); - } - - zapi_ipv4_route(ZEBRA_IPV4_ROUTE_DELETE, zclient, - (struct prefix_ipv4 *)p, &api); + prefix2str(&api.prefix, buf, sizeof(buf)); + zlog_debug("Tx route delete VRF %u %s", peer->bgp->vrf_id, buf); } - /* We have to think about a IPv6 link-local address curse. */ - if (p->family == AF_INET6) { - struct zapi_ipv6 api; - api.vrf_id = peer->bgp->vrf_id; - api.flags = flags; - api.type = ZEBRA_ROUTE_BGP; - api.instance = 0; - api.message = 0; - api.safi = safi; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 0; - api.nexthop = NULL; - api.ifindex_num = 0; - api.label_num = 0; - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = info->attr->med; - api.tag = 0; - - if (info->attr->tag != 0) { - SET_FLAG(api.message, ZAPI_MESSAGE_TAG); - api.tag = info->attr->tag; - } - - if (bgp_debug_zebra(p)) { - char buf[2][INET6_ADDRSTRLEN]; - zlog_debug( - "Tx IPv6 route delete VRF %u %s/%d metric %u tag %" ROUTE_TAG_PRI, - peer->bgp->vrf_id, - inet_ntop(AF_INET6, &p->u.prefix6, buf[0], - sizeof(buf[0])), - p->prefixlen, api.metric, api.tag); - } - - zapi_ipv6_route(ZEBRA_IPV6_ROUTE_DELETE, zclient, - (struct prefix_ipv6 *)p, NULL, &api); - } + zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); } struct bgp_redist *bgp_redist_lookup(struct bgp *bgp, afi_t afi, u_char type, @@ -2198,12 +1777,10 @@ void bgp_zebra_init(struct thread_master *master) zclient->interface_nbr_address_delete = bgp_interface_nbr_address_delete; zclient->interface_vrf_update = bgp_interface_vrf_update; - zclient->redistribute_route_ipv4_add = zebra_read_ipv4; - zclient->redistribute_route_ipv4_del = zebra_read_ipv4; + zclient->redistribute_route_add = zebra_read_route; + zclient->redistribute_route_del = zebra_read_route; zclient->interface_up = bgp_interface_up; zclient->interface_down = bgp_interface_down; - zclient->redistribute_route_ipv6_add = zebra_read_ipv6; - zclient->redistribute_route_ipv6_del = zebra_read_ipv6; zclient->nexthop_update = bgp_read_nexthop_update; zclient->import_check_update = bgp_read_import_check_update; zclient->fec_update = bgp_read_fec_update; @@ -2211,22 +1788,10 @@ void bgp_zebra_init(struct thread_master *master) zclient->local_vni_del = bgp_zebra_process_local_vni; zclient->local_macip_add = bgp_zebra_process_local_macip; zclient->local_macip_del = bgp_zebra_process_local_macip; - - bgp_nexthop_buf = stream_new(multipath_num * sizeof(struct in6_addr)); - bgp_ifindices_buf = stream_new(multipath_num * sizeof(unsigned int)); - bgp_label_buf = stream_new(multipath_num * sizeof(unsigned int)); } void bgp_zebra_destroy(void) { - - if (bgp_nexthop_buf) - stream_free(bgp_nexthop_buf); - if (bgp_ifindices_buf) - stream_free(bgp_ifindices_buf); - if (bgp_label_buf) - stream_free(bgp_label_buf); - if (zclient == NULL) return; zclient_stop(zclient); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index b6a48c9928..3fc3fe85f3 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1116,9 +1116,8 @@ struct peer *peer_new(struct bgp *bgp) peer->status = Idle; peer->ostatus = Idle; peer->cur_event = peer->last_event = peer->last_major_event = 0; - peer->bgp = bgp; + peer->bgp = bgp_lock(bgp); peer = peer_lock(peer); /* initial reference */ - bgp_lock(bgp); peer->password = NULL; /* Set default flags. */ @@ -1392,6 +1391,32 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer) hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); } +static void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi, + safi_t safi) +{ + struct bgp_node *rn, *nrn; + + for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; + rn = bgp_route_next(rn)) { + if (rn->info != NULL) { + /* Special handling for 2-level routing + * tables. */ + if (safi == SAFI_MPLS_VPN + || safi == SAFI_ENCAP + || safi == SAFI_EVPN) { + for (nrn = bgp_table_top(( + struct bgp_table + *)(rn->info)); + nrn; + nrn = bgp_route_next(nrn)) + bgp_process(bgp, nrn, + afi, safi); + } else + bgp_process(bgp, rn, afi, safi); + } + } +} + /* Force a bestpath recalculation for all prefixes. This is used * when 'bgp bestpath' commands are entered. */ @@ -1399,29 +1424,10 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp) { afi_t afi; safi_t safi; - struct bgp_node *rn, *nrn; for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; - rn = bgp_route_next(rn)) { - if (rn->info != NULL) { - /* Special handling for 2-level routing - * tables. */ - if (safi == SAFI_MPLS_VPN - || safi == SAFI_ENCAP - || safi == SAFI_EVPN) { - for (nrn = bgp_table_top(( - struct bgp_table - *)(rn->info)); - nrn; - nrn = bgp_route_next(nrn)) - bgp_process(bgp, nrn, - afi, safi); - } else - bgp_process(bgp, rn, afi, safi); - } - } + bgp_recalculate_afi_safi_bestpaths(bgp, afi, safi); } } } @@ -1501,6 +1507,25 @@ struct peer *peer_create_accept(struct bgp *bgp) return peer; } +/* + * Return true if we have a peer configured to use this afi/safi + */ +int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi) +{ + struct listnode *node; + struct peer *peer; + + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) + continue; + + if (peer->afc[afi][safi]) + return 1; + } + + return 0; +} + /* Change peer's AS number. */ void peer_as_change(struct peer *peer, as_t as, int as_specified) { @@ -1715,11 +1740,14 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi) struct peer_group *group; struct listnode *node, *nnode; struct peer *tmp_peer; + struct bgp *bgp; /* Nothing to do if we've already activated this peer */ if (peer->afc[afi][safi]) return ret; + bgp = peer->bgp; + /* This is a peer-group so activate all of the members of the * peer-group as well */ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { @@ -1742,6 +1770,17 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi) ret |= non_peergroup_activate_af(peer, afi, safi); } + /* If this is the first peer to be activated for this afi/labeled-unicast + * recalc bestpaths to trigger label allocation */ + if (safi == SAFI_LABELED_UNICAST && !bgp->allocate_mpls_labels[afi][SAFI_UNICAST]) { + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_info("peer(s) are now active for labeled-unicast, allocate MPLS labels"); + + bgp->allocate_mpls_labels[afi][SAFI_UNICAST] = 1; + bgp_recalculate_afi_safi_bestpaths(bgp, afi, SAFI_UNICAST); + } + return ret; } @@ -1799,6 +1838,7 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi) struct peer_group *group; struct peer *tmp_peer; struct listnode *node, *nnode; + struct bgp *bgp; /* Nothing to do if we've already de-activated this peer */ if (!peer->afc[afi][safi]) @@ -1822,6 +1862,20 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi) ret |= non_peergroup_deactivate_af(peer, afi, safi); } + bgp = peer->bgp; + + /* If this is the last peer to be deactivated for this afi/labeled-unicast + * recalc bestpaths to trigger label deallocation */ + if (safi == SAFI_LABELED_UNICAST && + bgp->allocate_mpls_labels[afi][SAFI_UNICAST] && + !bgp_afi_safi_peer_exists(bgp, afi, safi)) { + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_info("peer(s) are no longer active for labeled-unicast, deallocate MPLS labels"); + + bgp->allocate_mpls_labels[afi][SAFI_UNICAST] = 0; + bgp_recalculate_afi_safi_bestpaths(bgp, afi, SAFI_UNICAST); + } return ret; } @@ -3107,6 +3161,8 @@ int bgp_delete(struct bgp *bgp) * routes to be processed still referencing the struct bgp. */ listnode_delete(bm->bgp, bgp); + if (list_isempty(bm->bgp)) + bgp_close(); /* Deregister from Zebra, if needed */ if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) @@ -3125,21 +3181,7 @@ int bgp_delete(struct bgp *bgp) return 0; } -static void bgp_free(struct bgp *); - -void bgp_lock(struct bgp *bgp) -{ - ++bgp->lock; -} - -void bgp_unlock(struct bgp *bgp) -{ - assert(bgp->lock > 0); - if (--bgp->lock == 0) - bgp_free(bgp); -} - -static void bgp_free(struct bgp *bgp) +void bgp_free(struct bgp *bgp) { afi_t afi; safi_t safi; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 344b850fb4..0d7092c98c 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -337,6 +337,9 @@ struct bgp { /* BGP redistribute configuration. */ struct list *redist[AFI_MAX][ZEBRA_ROUTE_MAX]; + /* Allocate MPLS labels */ + u_char allocate_mpls_labels[AFI_MAX][SAFI_MAX]; + /* timer to re-evaluate neighbor default-originate route-maps */ struct thread *t_rmap_def_originate_eval; #define RMAP_DEFAULT_ORIGINATE_EVAL_TIMER 5 @@ -1256,9 +1259,6 @@ extern int bgp_flag_set(struct bgp *, int); extern int bgp_flag_unset(struct bgp *, int); extern int bgp_flag_check(struct bgp *, int); -extern void bgp_lock(struct bgp *); -extern void bgp_unlock(struct bgp *); - extern void bgp_router_id_zebra_bump(vrf_id_t, const struct prefix *); extern int bgp_router_id_static_set(struct bgp *, struct in_addr); @@ -1287,6 +1287,7 @@ extern int bgp_listen_limit_unset(struct bgp *); extern int bgp_update_delay_active(struct bgp *); extern int bgp_update_delay_configured(struct bgp *); +extern int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi); extern void peer_as_change(struct peer *, as_t, int); extern int peer_remote_as(struct bgp *, union sockunion *, const char *, as_t *, int, afi_t, safi_t); @@ -1399,6 +1400,20 @@ extern struct peer_af *peer_af_find(struct peer *, afi_t, safi_t); extern int peer_af_delete(struct peer *, afi_t, safi_t); extern void bgp_close(void); +extern void bgp_free(struct bgp *); + +static inline struct bgp *bgp_lock(struct bgp *bgp) +{ + bgp->lock++; + return bgp; +} + +static inline void bgp_unlock(struct bgp *bgp) +{ + assert(bgp->lock > 0); + if (--bgp->lock == 0) + bgp_free(bgp); +} static inline int afindex(afi_t afi, safi_t safi) { @@ -1544,10 +1559,8 @@ static inline struct vrf *bgp_vrf_lookup_by_instance_type(struct bgp *bgp) static inline void bgp_vrf_link(struct bgp *bgp, struct vrf *vrf) { bgp->vrf_id = vrf->vrf_id; - if (vrf->info != (void *)bgp) { - bgp_lock(bgp); - vrf->info = (void *)bgp; - } + if (vrf->info != (void *)bgp) + vrf->info = (void *)bgp_lock(bgp); } /* Unlink BGP instance from VRF. */ diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 7e0ed9150b..d63975a22b 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -1224,8 +1224,8 @@ static int rfapiVpnBiSamePtUn(struct bgp_info *bi1, struct bgp_info *bi2) switch (pfx_un1.family) { case AF_INET: - if (!IPV4_ADDR_SAME(&pfx_un1.u.prefix4.s_addr, - &pfx_un2.u.prefix4.s_addr)) + if (!IPV4_ADDR_SAME(&pfx_un1.u.prefix4, + &pfx_un2.u.prefix4)) return 0; break; case AF_INET6: diff --git a/bgpd/rfapi/vnc_debug.c b/bgpd/rfapi/vnc_debug.c index d4ff9451c3..3e9b5ed6b9 100644 --- a/bgpd/rfapi/vnc_debug.c +++ b/bgpd/rfapi/vnc_debug.c @@ -142,13 +142,13 @@ DEFUN (no_debug_bgp_vnc_all, * show/save ***********************************************************************/ -DEFUN (show_debugging_bgp_vnc, - show_debugging_bgp_vnc_cmd, - "show debugging bgp vnc", - SHOW_STR - DEBUG_STR - BGP_STR - VNC_STR) +DEFUN_NOSH (show_debugging_bgp_vnc, + show_debugging_bgp_vnc_cmd, + "show debugging bgp vnc", + SHOW_STR + DEBUG_STR + BGP_STR + VNC_STR) { size_t i; diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c index 3075d4109f..d472e06fa5 100644 --- a/bgpd/rfapi/vnc_zebra.c +++ b/bgpd/rfapi/vnc_zebra.c @@ -57,8 +57,8 @@ static struct zclient *zclient_vnc = NULL; /* * Routes coming from zebra get added to VNC here */ -static void vnc_redistribute_add(struct prefix *p, struct in_addr *nexthop, - u_int32_t metric, uint8_t type) +static void vnc_redistribute_add(struct prefix *p, u_int32_t metric, + uint8_t type) { struct bgp *bgp = bgp_get_default(); struct prefix_rd prd; @@ -329,156 +329,33 @@ static void vnc_redistribute_withdraw(struct bgp *bgp, afi_t afi, uint8_t type) * * Assumes 1 nexthop */ -static int vnc_zebra_read_ipv4(int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf_id) +static int vnc_zebra_read_route(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) { - struct stream *s; - struct zapi_ipv4 api; - struct in_addr nexthop; - struct prefix_ipv4 p; + struct zapi_route api; + int add; - s = zclient->ibuf; - nexthop.s_addr = 0; + if (zapi_route_decode(zclient->ibuf, &api) < 0) + return -1; - /* Type, flags, message. */ - api.type = stream_getc(s); - api.flags = stream_getc(s); - api.message = stream_getc(s); - - /* IPv4 prefix. */ - memset(&p, 0, sizeof(struct prefix_ipv4)); - p.family = AF_INET; - p.prefixlen = stream_getc(s); - stream_get(&p.prefix, s, PSIZE(p.prefixlen)); - - /* Nexthop, ifindex, distance, metric. */ - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { - api.nexthop_num = stream_getc(s); - nexthop.s_addr = stream_get_ipv4(s); - } - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) { - api.ifindex_num = stream_getc(s); - stream_getl(s); - } - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc(s); - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl(s); - else - api.metric = 0; - - if (command == ZEBRA_IPV4_ROUTE_ADD) { - if (BGP_DEBUG(zebra, ZEBRA)) { - char buf[2][INET_ADDRSTRLEN]; - vnc_zlog_debug_verbose( - "%s: Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u", - __func__, zebra_route_string(api.type), - inet_ntop(AF_INET, &p.prefix, buf[0], - sizeof(buf[0])), - p.prefixlen, inet_ntop(AF_INET, &nexthop, - buf[1], sizeof(buf[1])), - api.metric); - } - vnc_redistribute_add((struct prefix *)&p, &nexthop, api.metric, - api.type); - } else { - if (BGP_DEBUG(zebra, ZEBRA)) { - char buf[2][INET_ADDRSTRLEN]; - vnc_zlog_debug_verbose( - "%s: Zebra rcvd: IPv4 route delete %s %s/%d " - "nexthop %s metric %u", - __func__, zebra_route_string(api.type), - inet_ntop(AF_INET, &p.prefix, buf[0], - sizeof(buf[0])), - p.prefixlen, inet_ntop(AF_INET, &nexthop, - buf[1], sizeof(buf[1])), - api.metric); - } - vnc_redistribute_delete((struct prefix *)&p, api.type); - } - - return 0; -} - -/* Zebra route add and delete treatment. */ -static int vnc_zebra_read_ipv6(int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf_id) -{ - struct stream *s; - struct zapi_ipv6 api; - struct in6_addr nexthop; - struct prefix_ipv6 p, src_p; - - s = zclient->ibuf; - memset(&nexthop, 0, sizeof(struct in6_addr)); - - /* Type, flags, message. */ - api.type = stream_getc(s); - api.flags = stream_getc(s); - api.message = stream_getc(s); - - /* IPv6 prefix. */ - memset(&p, 0, sizeof(struct prefix_ipv6)); - p.family = AF_INET6; - p.prefixlen = stream_getc(s); - stream_get(&p.prefix, s, PSIZE(p.prefixlen)); - - memset(&src_p, 0, sizeof(struct prefix_ipv6)); - src_p.family = AF_INET6; - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) { - src_p.prefixlen = stream_getc(s); - stream_get(&src_p.prefix, s, PSIZE(src_p.prefixlen)); - } - - if (src_p.prefixlen) - /* we completely ignore srcdest routes for now. */ + /* we completely ignore srcdest routes for now. */ + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) return 0; - /* Nexthop, ifindex, distance, metric. */ - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { - api.nexthop_num = stream_getc(s); - stream_get(&nexthop, s, 16); - } - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) { - api.ifindex_num = stream_getc(s); - stream_getl(s); - } - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc(s); + add = (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD); + if (add) + vnc_redistribute_add(&api.prefix, api.metric, api.type); else - api.distance = 0; - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl(s); - else - api.metric = 0; + vnc_redistribute_delete(&api.prefix, api.type); - /* Simply ignore link-local address. */ - if (IN6_IS_ADDR_LINKLOCAL(&p.prefix)) - return 0; + if (BGP_DEBUG(zebra, ZEBRA)) { + char buf[PREFIX_STRLEN]; - if (command == ZEBRA_IPV6_ROUTE_ADD) { - if (BGP_DEBUG(zebra, ZEBRA)) { - char buf[INET6_ADDRSTRLEN]; - vnc_zlog_debug_verbose( - "Zebra rcvd: IPv6 route add %s %s/%d metric %u", - zebra_route_string(api.type), - inet_ntop(AF_INET6, &p.prefix, buf, - sizeof(buf)), - p.prefixlen, api.metric); - } - vnc_redistribute_add((struct prefix *)&p, NULL, api.metric, - api.type); - } else { - if (BGP_DEBUG(zebra, ZEBRA)) { - char buf[INET6_ADDRSTRLEN]; - vnc_zlog_debug_verbose( - "Zebra rcvd: IPv6 route delete %s %s/%d metric %u", - zebra_route_string(api.type), - inet_ntop(AF_INET6, &p.prefix, buf, - sizeof(buf)), - p.prefixlen, api.metric); - } - vnc_redistribute_delete((struct prefix *)&p, api.type); + prefix2str(&api.prefix, buf, sizeof(buf)); + vnc_zlog_debug_verbose( + "%s: Zebra rcvd: route delete %s %s metric %u", + __func__, zebra_route_string(api.type), buf, + api.metric); } return 0; @@ -494,83 +371,57 @@ static int vnc_zebra_read_ipv6(int command, struct zclient *zclient, static void vnc_zebra_route_msg(struct prefix *p, int nhp_count, void *nhp_ary, int add) /* 1 = add, 0 = del */ { + struct zapi_route api; + struct zapi_nexthop *api_nh; + int i; + if (!nhp_count) { vnc_zlog_debug_verbose("%s: empty nexthop list, skipping", __func__); return; } - if (p->family == AF_INET) { + memset(&api, 0, sizeof(api)); + api.vrf_id = VRF_DEFAULT; + api.type = ZEBRA_ROUTE_VNC; + api.safi = SAFI_UNICAST; + api.prefix = *p; - struct zapi_ipv4 api; + /* Nexthops */ + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = nhp_count; + for (i = 0; i < nhp_count; i++) { + struct in_addr *nhp_ary4; + struct in6_addr *nhp_ary6; - api.flags = 0; - api.vrf_id = VRF_DEFAULT; - api.type = ZEBRA_ROUTE_VNC; - api.message = 0; - SET_FLAG(api.message, - ZAPI_MESSAGE_NEXTHOP); /* TBD what's it mean? */ - api.nexthop_num = nhp_count; - api.nexthop = nhp_ary; - api.ifindex_num = 0; - api.instance = 0; - api.safi = SAFI_UNICAST; - - if (BGP_DEBUG(zebra, ZEBRA)) { - - char buf[INET_ADDRSTRLEN]; - vnc_zlog_debug_verbose( - "%s: Zebra send: IPv4 route %s %s/%d, nhp_count=%d", - __func__, (add ? "add" : "del"), - inet_ntop(AF_INET, &p->u.prefix4, buf, - sizeof(buf)), - p->prefixlen, nhp_count); + api_nh = &api.nexthops[i]; + switch (p->family) { + case AF_INET: + nhp_ary4 = nhp_ary; + memcpy(&api_nh->gate.ipv4, &nhp_ary4[i], + sizeof(api_nh->gate.ipv4)); + api_nh->type = NEXTHOP_TYPE_IPV4; + break; + case AF_INET6: + nhp_ary6 = nhp_ary; + memcpy(&api_nh->gate.ipv6, &nhp_ary6[i], + sizeof(api_nh->gate.ipv6)); + api_nh->type = NEXTHOP_TYPE_IPV6; + break; } - - zapi_ipv4_route((add ? ZEBRA_IPV4_NEXTHOP_ADD - : ZEBRA_IPV4_NEXTHOP_DELETE), - zclient_vnc, (struct prefix_ipv4 *)p, &api); - - } else if (p->family == AF_INET6) { - - struct zapi_ipv6 api; - ifindex_t ifindex = 0; - - /* Make Zebra API structure. */ - api.flags = 0; - api.vrf_id = VRF_DEFAULT; - api.type = ZEBRA_ROUTE_VNC; - api.message = 0; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); /* TBD means? */ - api.nexthop_num = nhp_count; - api.nexthop = nhp_ary; - SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = 1; - api.ifindex = &ifindex; - api.instance = 0; - api.safi = SAFI_UNICAST; - - if (BGP_DEBUG(zebra, ZEBRA)) { - - char buf[INET6_ADDRSTRLEN]; - vnc_zlog_debug_verbose( - "%s: Zebra send: IPv6 route %s %s/%d nhp_count=%d", - __func__, (add ? "add" : "del"), - inet_ntop(AF_INET6, &p->u.prefix6, buf, - sizeof(buf)), - p->prefixlen, nhp_count); - } - - zapi_ipv6_route((add ? ZEBRA_IPV6_NEXTHOP_ADD - : ZEBRA_IPV6_NEXTHOP_DELETE), - zclient_vnc, (struct prefix_ipv6 *)p, NULL, - &api); - } else { - vnc_zlog_debug_verbose( - "%s: unknown prefix address family, skipping", - __func__); - return; } + + if (BGP_DEBUG(zebra, ZEBRA)) { + char buf[PREFIX_STRLEN]; + + prefix2str(&api.prefix, buf, sizeof(buf)); + vnc_zlog_debug_verbose( + "%s: Zebra send: route %s %s, nhp_count=%d", __func__, + (add ? "add" : "del"), buf, nhp_count); + } + + zclient_route_send((add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE), + zclient_vnc, &api); } @@ -1042,10 +893,8 @@ void vnc_zebra_init(struct thread_master *master) zclient_vnc = zclient_new(master); zclient_init(zclient_vnc, ZEBRA_ROUTE_VNC, 0); - zclient_vnc->redistribute_route_ipv4_add = vnc_zebra_read_ipv4; - zclient_vnc->redistribute_route_ipv4_del = vnc_zebra_read_ipv4; - zclient_vnc->redistribute_route_ipv6_add = vnc_zebra_read_ipv6; - zclient_vnc->redistribute_route_ipv6_del = vnc_zebra_read_ipv6; + zclient_vnc->redistribute_route_add = vnc_zebra_read_route; + zclient_vnc->redistribute_route_del = vnc_zebra_read_route; } void vnc_zebra_destroy(void) diff --git a/common.am b/common.am index b115a871b9..c0094b1b88 100644 --- a/common.am +++ b/common.am @@ -13,8 +13,7 @@ CLIPPY_DEPS = $(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py SUFFIXES = _clippy.c .proto .pb-c.c .pb-c.h .pb.h .c_clippy.c: @{ test -x $(top_builddir)/$(HOSTTOOLS)lib/clippy || $(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/clippy; } - $(AM_V_CLIPPY)$(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py $< > $@.tmp - @{ test -f $@ && diff $@.tmp $@ >/dev/null 2>/dev/null; } && rm $@.tmp || mv $@.tmp $@ + $(AM_V_CLIPPY)$(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py -o $@ $< ## automake's "ylwrap" is a great piece of GNU software... not. .l.c: diff --git a/configure.ac b/configure.ac index 574992342f..f6f38b47cf 100755 --- a/configure.ac +++ b/configure.ac @@ -195,6 +195,7 @@ fi dnl always want these CFLAGS AC_C_FLAG([-fno-omit-frame-pointer]) +AC_C_FLAG([-funwind-tables]) AC_C_FLAG([-Wall]) AC_C_FLAG([-Wextra]) AC_C_FLAG([-Wmissing-prototypes]) @@ -320,6 +321,8 @@ AC_ARG_WITH(rfp-path, AS_HELP_STRING([--with-rfp-path[=DIR]],[path to replaced stub RFP used with BGP VNC])) AC_ARG_ENABLE(snmp, AS_HELP_STRING([--enable-snmp=ARG], [enable SNMP support (smux or agentx)])) +AC_ARG_ENABLE(zeromq, + AS_HELP_STRING([--enable-zeromq], [enable ZeroMQ handler (libfrrzmq)])) AC_ARG_WITH(libpam, AS_HELP_STRING([--with-libpam], [use libpam for PAM support in vtysh])) AC_ARG_ENABLE(ospfapi, @@ -344,7 +347,7 @@ AC_ARG_ENABLE(shell_access, AC_ARG_ENABLE(rtadv, AS_HELP_STRING([--disable-rtadv], [disable IPV6 router advertisement feature])) AC_ARG_ENABLE(irdp, - AS_HELP_STRING([--enable-irdp], [enable IRDP server support in zebra])) + AS_HELP_STRING([--disable-irdp], [enable IRDP server support in zebra (default if supported)])) AC_ARG_ENABLE(capabilities, AS_HELP_STRING([--disable-capabilities], [disable using POSIX capabilities])) AC_ARG_ENABLE(rusage, @@ -570,10 +573,6 @@ else AC_MSG_RESULT(no) fi -if test "${enable_irdp}" = "yes"; then - AC_DEFINE(HAVE_IRDP,, IRDP ) -fi - if test x"${enable_user}" = x"no"; then enable_user="" else @@ -1370,7 +1369,7 @@ fi dnl ------------------ dnl check Net-SNMP library dnl ------------------ -if test "${enable_snmp}" != ""; then +if test "${enable_snmp}" != "" -a "${enable_snmp}" != "no"; then AC_PATH_TOOL([NETSNMP_CONFIG], [net-snmp-config], [no]) if test x"$NETSNMP_CONFIG" = x"no"; then AC_MSG_ERROR([--enable-snmp given but unable to find net-snmp-config]) @@ -1479,17 +1478,27 @@ AC_CHECK_MEMBERS([struct sockaddr.sa_len, dnl --------------------------- dnl IRDP/pktinfo/icmphdr checks dnl --------------------------- -AC_CHECK_TYPES([struct in_pktinfo], - [AC_CHECK_TYPES([struct icmphdr], - [if test "${enable_irdp}" != "no"; then - AC_DEFINE(HAVE_IRDP,, IRDP) - fi], - [if test "${enable_irdp}" = "yes"; then - AC_MSG_ERROR(['IRDP requires in_pktinfo at the moment!']) - fi], [FRR_INCLUDES])], - [if test "${enable_irdp}" = "yes"; then - AC_MSG_ERROR(['IRDP requires in_pktinfo at the moment!']) - fi], [FRR_INCLUDES]) + +AC_CHECK_TYPES([struct in_pktinfo], [ + AC_CHECK_TYPES([struct icmphdr], [ + IRDP=true + ], [ + IRDP=false + ], [FRR_INCLUDES]) +], [ + IRDP=false +], [FRR_INCLUDES]) + +case "${enable_irdp}" in +yes) + $IRDP || AC_MSG_ERROR(['IRDP requires in_pktinfo at the moment!']) + ;; +no) + IRDP=false + ;; +esac + +AM_CONDITIONAL(IRDP, $IRDP) dnl ----------------------- dnl checking for IP_PKTINFO @@ -1708,6 +1717,21 @@ AC_CHECK_HEADER([malloc.h], ) ], [], FRR_INCLUDES) +dnl ------ +dnl ZeroMQ +dnl ------ +if test "x$enable_zeromq" != "xno"; then + PKG_CHECK_MODULES(ZEROMQ, [libzmq >= 4.0.0], [ + AC_DEFINE(HAVE_ZEROMQ, 1, [Enable ZeroMQ support]) + ZEROMQ=true + ], [ + if test "x$enable_zeromq" = "xyes"; then + AC_MSG_ERROR([configuration specifies --enable-zeromq but libzmq was not found]) + fi + ]) +fi +AM_CONDITIONAL([ZEROMQ], test "x$ZEROMQ" = "xtrue") + dnl ---------- dnl configure date dnl ---------- diff --git a/doc/code/.gitignore b/doc/code/.gitignore new file mode 100644 index 0000000000..0505537159 --- /dev/null +++ b/doc/code/.gitignore @@ -0,0 +1,3 @@ +/_templates +/_build +!/Makefile diff --git a/doc/code/Makefile b/doc/code/Makefile new file mode 100644 index 0000000000..056b78e68e --- /dev/null +++ b/doc/code/Makefile @@ -0,0 +1,216 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make ' where 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." diff --git a/doc/code/conf.py b/doc/code/conf.py new file mode 100644 index 0000000000..38be7f2fca --- /dev/null +++ b/doc/code/conf.py @@ -0,0 +1,293 @@ +# -*- coding: utf-8 -*- +# +# FRR documentation build configuration file, created by +# sphinx-quickstart on Tue Jan 31 16:00:52 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os +import re + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.todo'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'FRR' +copyright = u'2017, FRR' +author = u'FRR' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. + +# The short X.Y version. +version = u'?.?' +# The full version, including alpha/beta/rc tags. +release = u'?.?-?' + +val = re.compile('^S\["([^"]+)"\]="(.*)"$') +with open('../../config.status', 'r') as cfgstatus: + for ln in cfgstatus.readlines(): + m = val.match(ln) + if m is None: continue + if m.group(1) == 'PACKAGE_VERSION': + release = m.group(2) + version = release.split('-')[0] + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v 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 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 diff --git a/doc/code/hooks.rst b/doc/code/hooks.rst new file mode 100644 index 0000000000..0afa297aa7 --- /dev/null +++ b/doc/code/hooks.rst @@ -0,0 +1,171 @@ +.. highlight:: c + +Hooks +===== + +Libfrr provides type-safe subscribable hook points where other pieces of +code can add one or more callback functions. "type-safe" in this case +applies to the function pointers used for subscriptions. The +implementations checks (at compile-time) wheter a callback to be added has +the appropriate function signature (parameters) for the hook. + +Example: + +.. code-block:: c + :caption: mydaemon.h + + #include "hook.h" + DECLARE_HOOK(some_update_event, (struct eventinfo *info), (info)) + +.. code-block:: c + :caption: mydaemon.c + + #include "mydaemon.h" + DEFINE_HOOK(some_update_event, (struct eventinfo *info), (info)) + ... + hook_call(some_update_event, info); + +.. code-block:: c + :caption: mymodule.c + + #include "mydaemon.h" + static int event_handler(struct eventinfo *info); + ... + hook_register(some_update_event, event_handler); + +Do not use parameter names starting with "hook", these can collide with +names used by the hook code itself. + + +Return values +------------- + +Callbacks to be placed on hooks always return "int" for now; hook_call will +sum up the return values from each called function. (The default is 0 if no +callbacks are registered.) + +There are no pre-defined semantics for the value, in most cases it is +ignored. For success/failure indication, 0 should be success, and +handlers should make sure to only return 0 or 1 (not -1 or other values). + +There is no built-in way to abort executing a chain after a failure of one +of the callbacks. If this is needed, the hook can use an extra +``bool *aborted`` argument. + + +Priorities +---------- + +Hooks support a "priority" value for ordering registered calls +relative to each other. The priority is a signed integer where lower +values are called earlier. There are also "Koohs", which is hooks with +reverse priority ordering (for cleanup/deinit hooks, so you can use the +same priority value). + +Recommended priority value ranges are: + +======================== =================================================== +Range Usage +------------------------ --------------------------------------------------- + -999 ... 0 ... 999 main executable / daemon, or library + +-1999 ... -1000 modules registering calls that should run before + the daemon's bits + +1000 ... 1999 modules' calls that should run after daemon's + (includes default value: 1000) +======================== =================================================== + +Note: the default value is 1000, based on the following 2 expectations: + +- most hook_register() usage will be in loadable modules +- usage of hook_register() in the daemon itself may need relative ordering + to itself, making an explicit value the expected case + +The priority value is passed as extra argument on hook_register_prio() / +hook_register_arg_prio(). Whether a hook runs in reverse is determined +solely by the code defining / calling the hook. (DECLARE_KOOH is actually +the same thing as DECLARE_HOOK, it's just there to make it obvious.) + + +Definition +---------- + +.. c:macro:: DECLARE_HOOK(name, arglist, passlist) +.. c:macro:: DECLARE_KOOH(name, arglist, passlist) + + :param name: Name of the hook to be defined + :param arglist: Function definition style parameter list in braces. + :param passlist: List of the same parameters without their types. + + Note: the second and third macro args must be the hook function's + parameter list, with the same names for each parameter. The second + macro arg is with types (used for defining things), the third arg is + just the names (used for passing along parameters). + + This macro must be placed in a header file; this header file must be + included to register a callback on the hook. + + Examples: + + .. code-block:: c + + DECLARE_HOOK(foo, (), ()) + DECLARE_HOOK(bar, (int arg), (arg)) + DECLARE_HOOK(baz, (const void *x, in_addr_t y), (x, y)) + +.. c:macro:: DEFINE_HOOK(name, arglist, passlist) + + Implements an hook. Each ``DECLARE_HOOK`` must have be accompanied by + exactly one ``DEFINE_HOOK``, which needs to be placed in a source file. + **The hook can only be called from this source file.** This is intentional + to avoid overloading and/or misusing hooks for distinct purposes. + + The compiled source file will include a global symbol with the name of the + hook prefixed by `_hook_`. Trying to register a callback for a hook that + doesn't exist will therefore result in a linker error, or a module + load-time error for dynamic modules. + +.. c:macro:: DEFINE_KOOH(name, arglist, passlist) + + Same as ``DEFINE_HOOK``, but the sense of priorities / order of callbacks + is reversed. This should be used for cleanup hooks. + +.. c:function:: int hook_call(name, ...) + + Calls the specified named hook. Parameters to the hook are passed right + after the hook name, e.g.: + + .. code-block:: c + + hook_call(foo); + hook_call(bar, 0); + hook_call(baz, NULL, INADDR_ANY); + + Returns the sum of return values from all callbacks. The ``DEFINE_HOOK`` + statement for the hook must be placed in the file before any ``hook_call`` + use of the hook. + + +Callback registration +--------------------- + +.. c:function:: void hook_register(name, int (*callback)(...)) +.. c:function:: void hook_register_prio(name, int priority, int (*callback)(...)) +.. c:function:: void hook_register_arg(name, int (*callback)(void *arg, ...), void *arg) +.. c:function:: void hook_register_arg_prio(name, int priority, int (*callback)(void *arg, ...), void *arg) + + Register a callback with an hook. If the caller needs to pass an extra + argument to the callback, the _arg variant can be used and the extra + parameter will be passed as first argument to the callback. There is no + typechecking for this argument. + + The priority value is used as described above. The variants without a + priority parameter use 1000 as priority value. + +.. c:function:: void hook_unregister(name, int (*callback)(...)) +.. c:function:: void hook_unregister_arg(name, int (*callback)(void *arg, ...), void *arg) + + Removes a previously registered callback from a hook. Note that there + is no _prio variant of these calls. The priority value is only used during + registration. diff --git a/doc/code/index.rst b/doc/code/index.rst new file mode 100644 index 0000000000..79647d0b92 --- /dev/null +++ b/doc/code/index.rst @@ -0,0 +1,18 @@ +Welcome to FRR's documentation! +=============================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + library + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/doc/code/library.rst b/doc/code/library.rst new file mode 100644 index 0000000000..dd46021db8 --- /dev/null +++ b/doc/code/library.rst @@ -0,0 +1,10 @@ +libfrr library facilities +========================= + +.. toctree:: + :maxdepth: 2 + + memtypes + hooks + + diff --git a/doc/code/memtypes.rst b/doc/code/memtypes.rst new file mode 100644 index 0000000000..62d211e864 --- /dev/null +++ b/doc/code/memtypes.rst @@ -0,0 +1,117 @@ +.. highlight:: c + +Memtypes +======== + +FRR includes wrappers arround ``malloc()`` and ``free()`` that count the number +of objects currently allocated, for each of a defined ``MTYPE``. + +To this extent, there are `memory groups` and `memory types`. Each memory +type must belong to a memory group, this is used just to provide some basic +structure. + +Example: + +.. code-block:: c + :caption: mydaemon.h + + DECLARE_MGROUP(MYDAEMON) + DECLARE_MTYPE(MYNEIGHBOR) + +.. code-block:: c + :caption: mydaemon.c + + DEFINE_MGROUP( MYDAEMON, "My daemon's memory") + DEFINE_MTYPE( MYDAEMON, MYNEIGHBOR, "Neighbor entry") + DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name") + + struct neigh *neighbor_new(const char *name) + { + struct neigh *n = XMALLOC(MYNEIGHBOR, sizeof(*n)); + n->name = XSTRDUP(MYNEIGHBORNAME, name); + return n; + } + + void neighbor_free(struct neigh *n) + { + XFREE(MYNEIGHBORNAME, n->name); + XFREE(MYNEIGHBOR, n); + } + + +Definition +---------- + +.. c:macro:: DECLARE_MGROUP(name) + + This macro forward-declares a memory group and should be placed in a + ``.h`` file. It expands to an ``extern struct memgroup`` statement. + +.. c:macro:: DEFINE_MGROUP(mname, description) + + Defines/implements a memory group. Must be placed into exactly one ``.c`` + file (multiple inclusion will result in a link-time symbol conflict). + + Contains additional logic (constructor and destructor) to register the + memory group in a global list. + +.. c:macro:: DECLARE_MTYPE(name) + + Forward-declares a memory type and makes ``MTYPE_name`` available for use. + Note that the ``MTYPE_`` prefix must not be included in the name, it is + automatically prefixed. + + ``MTYPE_name`` is created as a `static const` symbol, i.e. a compile-time + constant. It refers to an ``extern struct memtype _mt_name``, where `name` + is replaced with the actual name. + +.. c:macro:: DEFINE_MTYPE(group, name, description) + + Define/implement a memory type, must be placed into exactly one ``.c`` + file (multiple inclusion will result in a link-time symbol conflict). + + Like ``DEFINE_MGROUP``, this contains actual code to register the MTYPE + under its group. + +.. c:macro:: DEFINE_MTYPE_STATIC(group, name, description) + + Same as ``DEFINE_MTYPE``, but the ``DEFINE_MTYPE_STATIC`` variant places + the C ``static`` keyword on the definition, restricting the MTYPE's + availability to the current source file. This should be appropriate in + >80% of cases. + + .. todo:: + + Daemons currently have ``daemon_memory.[ch]`` files listing all of + their MTYPEs. This is not how it should be, most of these types + should be moved into the appropriate files where they are used. + Only a few MTYPEs should remain non-static after that. + + +Usage +----- + +.. c:function:: void *XMALLOC(struct memtype *mtype, size_t size) + +.. c:function:: void *XCALLOC(struct memtype *mtype, size_t size) + +.. c:function:: void *XSTRDUP(struct memtype *mtype, size_t size) + + Allocation wrappers for malloc/calloc/realloc/strdup, taking an extra + mtype parameter. + +.. c:function:: void *XREALLOC(struct memtype *mtype, void *ptr, size_t size) + + Wrapper around realloc() with MTYPE tracking. Note that ``ptr`` may + be NULL, in which case the function does the same as XMALLOC (regardless + of whether the system realloc() supports this.) + +.. c:function:: void XFREE(struct memtype *mtype, void *ptr) + + Wrapper around free(), again taking an extra mtype parameter. This is + actually a macro, with the following additional properties: + + - the macro contains ``ptr = NULL`` + - if ptr is NULL, no operation is performed (as is guaranteed by system + implementations.) Do not surround XFREE with ``if (ptr != NULL)`` + checks. diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c index aca6e59816..74515c98cb 100644 --- a/eigrpd/eigrp_dump.c +++ b/eigrpd/eigrp_dump.c @@ -158,7 +158,7 @@ const char *eigrp_topology_ip_string(struct eigrp_prefix_entry *tn) static char buf[EIGRP_IF_STRING_MAXLEN] = ""; u_int32_t ifaddr; - ifaddr = ntohl(tn->destination_ipv4->prefix.s_addr); + ifaddr = ntohl(tn->destination->u.prefix4.s_addr); snprintf(buf, EIGRP_IF_STRING_MAXLEN, "%u.%u.%u.%u", (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, (ifaddr >> 8) & 0xff, ifaddr & 0xff); @@ -289,11 +289,12 @@ void show_ip_eigrp_topology_header(struct vty *vty, struct eigrp *eigrp) void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn) { struct list *successors = eigrp_topology_get_successor(tn); + char buffer[PREFIX_STRLEN]; vty_out(vty, "%-3c", (tn->state > 0) ? 'A' : 'P'); - vty_out(vty, "%s/%u, ", inet_ntoa(tn->destination_ipv4->prefix), - tn->destination_ipv4->prefixlen); + vty_out(vty, "%s, ", + prefix2str(tn->destination, buffer, PREFIX_STRLEN)); vty_out(vty, "%u successors, ", successors->count); vty_out(vty, "FD is %u, serno: %" PRIu64 " \n", tn->fdistance, tn->serno); @@ -323,12 +324,12 @@ void show_ip_eigrp_neighbor_entry(struct vty *vty, struct eigrp *eigrp, } -DEFUN (show_debugging_eigrp, - show_debugging_eigrp_cmd, - "show debugging eigrp", - SHOW_STR - DEBUG_STR - EIGRP_STR) +DEFUN_NOSH (show_debugging_eigrp, + show_debugging_eigrp_cmd, + "show debugging [eigrp]", + SHOW_STR + DEBUG_STR + EIGRP_STR) { int i; diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c index 8e2a26447e..47cd112cf5 100644 --- a/eigrpd/eigrp_fsm.c +++ b/eigrpd/eigrp_fsm.c @@ -178,7 +178,7 @@ struct { * Return number of occurred event (arrow in diagram). * */ -int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) +static int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) { // Loading base information from message // struct eigrp *eigrp = msg->eigrp; @@ -204,8 +204,7 @@ int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) switch (actual_state) { case EIGRP_FSM_STATE_PASSIVE: { struct eigrp_neighbor_entry *head = - (struct eigrp_neighbor_entry *) - entry->prefix->entries->head->data; + listnode_head(prefix->entries); if (head->reported_distance < prefix->fdistance) { return EIGRP_FSM_KEEP_STATE; @@ -226,8 +225,7 @@ int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) case EIGRP_FSM_STATE_ACTIVE_0: { if (msg->packet_type == EIGRP_OPC_REPLY) { struct eigrp_neighbor_entry *head = - (struct eigrp_neighbor_entry *) - entry->prefix->entries->head->data; + listnode_head(prefix->entries); listnode_delete(prefix->rij, entry->adv_router); if (prefix->rij->count) @@ -279,8 +277,7 @@ int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) case EIGRP_FSM_STATE_ACTIVE_2: { if (msg->packet_type == EIGRP_OPC_REPLY) { struct eigrp_neighbor_entry *head = - (struct eigrp_neighbor_entry *) - prefix->entries->head->data; + listnode_head(prefix->entries); listnode_delete(prefix->rij, entry->adv_router); if (prefix->rij->count) { @@ -331,9 +328,10 @@ int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) * Function made to execute in separate thread. * Load argument from thread and execute proper NSM function */ -int eigrp_fsm_event(struct eigrp_fsm_action_message *msg, int event) +int eigrp_fsm_event(struct eigrp_fsm_action_message *msg) { - zlog_info("EIGRP AS: %d State: %d Event: %d Network: %s\n", + int event = eigrp_get_fsm_event(msg); + zlog_info("EIGRP AS: %d State: %d Event: %d Network: %s", msg->eigrp->AS, msg->prefix->state, event, eigrp_topology_ip_string(msg->prefix)); (*(NSM[msg->prefix->state][event].func))(msg); @@ -350,16 +348,15 @@ int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg) struct eigrp *eigrp = msg->eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; struct list *successors = eigrp_topology_get_successor(prefix); + struct eigrp_neighbor_entry *ne; assert(successors); // If this is NULL we have shit the bed, fun huh? + ne = listnode_head(successors); prefix->state = EIGRP_FSM_STATE_ACTIVE_1; prefix->rdistance = prefix->distance = prefix->fdistance = - ((struct eigrp_neighbor_entry *)successors->head->data) - ->distance; - prefix->reported_metric = - ((struct eigrp_neighbor_entry *)successors->head->data) - ->total_metric; + ne->distance; + prefix->reported_metric = ne->total_metric; if (eigrp_nbr_count_get()) { prefix->req_action |= EIGRP_FSM_NEED_QUERY; @@ -379,16 +376,15 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg) struct eigrp *eigrp = msg->eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; struct list *successors = eigrp_topology_get_successor(prefix); + struct eigrp_neighbor_entry *ne; assert(successors); // If this is NULL somebody poked us in the eye. + ne = listnode_head(successors); prefix->state = EIGRP_FSM_STATE_ACTIVE_3; prefix->rdistance = prefix->distance = prefix->fdistance = - ((struct eigrp_neighbor_entry *)successors->head->data) - ->distance; - prefix->reported_metric = - ((struct eigrp_neighbor_entry *)successors->head->data) - ->total_metric; + ne->distance; + prefix->reported_metric = ne->total_metric; if (eigrp_nbr_count_get()) { prefix->req_action |= EIGRP_FSM_NEED_QUERY; listnode_add(eigrp->topology_changes_internalIPV4, prefix); @@ -405,21 +401,15 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg) { struct eigrp_prefix_entry *prefix = msg->prefix; + struct eigrp_neighbor_entry *ne = listnode_head(prefix->entries); if (prefix->state == EIGRP_FSM_STATE_PASSIVE) { if (!eigrp_metrics_is_same(prefix->reported_metric, - ((struct eigrp_neighbor_entry *) - prefix->entries->head->data) - ->total_metric)) { + ne->total_metric)) { prefix->rdistance = prefix->fdistance = - prefix->distance = - ((struct eigrp_neighbor_entry *) - prefix->entries->head->data) - ->distance; + prefix->distance = ne->distance; prefix->reported_metric = - ((struct eigrp_neighbor_entry *) - prefix->entries->head->data) - ->total_metric; + ne->total_metric; if (msg->packet_type == EIGRP_OPC_QUERY) eigrp_send_reply(msg->adv_router, prefix); prefix->req_action |= EIGRP_FSM_NEED_UPDATE; @@ -441,22 +431,20 @@ int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; + struct eigrp_neighbor_entry *ne = listnode_head(prefix->entries); + prefix->fdistance = prefix->distance = prefix->rdistance = - ((struct eigrp_neighbor_entry *)(prefix->entries->head->data)) - ->distance; - prefix->reported_metric = - ((struct eigrp_neighbor_entry *)(prefix->entries->head->data)) - ->total_metric; + ne->distance; + prefix->reported_metric = ne->total_metric; if (prefix->state == EIGRP_FSM_STATE_ACTIVE_3) { struct list *successors = eigrp_topology_get_successor(prefix); assert(successors); // It's like Napolean and Waterloo - eigrp_send_reply( - ((struct eigrp_neighbor_entry *)successors->head->data) - ->adv_router, - prefix); + ne = listnode_head(successors); + eigrp_send_reply(ne->adv_router, + prefix); list_delete(successors); } @@ -473,15 +461,15 @@ int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg) { struct list *successors = eigrp_topology_get_successor(msg->prefix); + struct eigrp_neighbor_entry *ne; assert(successors); // Trump and his big hands + ne = listnode_head(successors); msg->prefix->state = msg->prefix->state == EIGRP_FSM_STATE_ACTIVE_1 ? EIGRP_FSM_STATE_ACTIVE_0 : EIGRP_FSM_STATE_ACTIVE_2; - msg->prefix->distance = - ((struct eigrp_neighbor_entry *)successors->head->data) - ->distance; + msg->prefix->distance = ne->distance; if (!msg->prefix->rij->count) (*(NSM[msg->prefix->state][eigrp_get_fsm_event(msg)].func))( msg); @@ -495,13 +483,11 @@ int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; + struct eigrp_neighbor_entry *ne = listnode_head(prefix->entries); + prefix->state = EIGRP_FSM_STATE_PASSIVE; - prefix->distance = prefix->rdistance = - ((struct eigrp_neighbor_entry *)(prefix->entries->head->data)) - ->distance; - prefix->reported_metric = - ((struct eigrp_neighbor_entry *)(prefix->entries->head->data)) - ->total_metric; + prefix->distance = prefix->rdistance = ne->distance; + prefix->reported_metric = ne->total_metric; prefix->fdistance = prefix->fdistance > prefix->distance ? prefix->distance : prefix->fdistance; @@ -510,11 +496,9 @@ int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg) assert(successors); // Having a spoon and all you need is a // knife - - eigrp_send_reply( - ((struct eigrp_neighbor_entry *)successors->head->data) - ->adv_router, - prefix); + ne = listnode_head(successors); + eigrp_send_reply(ne->adv_router, + prefix); list_delete(successors); } @@ -531,6 +515,7 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg) { struct eigrp *eigrp = msg->eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; + struct eigrp_neighbor_entry *best_successor; struct list *successors = eigrp_topology_get_successor(prefix); assert(successors); // Routing without a stack @@ -538,8 +523,8 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg) prefix->state = prefix->state == EIGRP_FSM_STATE_ACTIVE_0 ? EIGRP_FSM_STATE_ACTIVE_1 : EIGRP_FSM_STATE_ACTIVE_3; - struct eigrp_neighbor_entry *best_successor = - ((struct eigrp_neighbor_entry *)(successors->head->data)); + + best_successor = listnode_head(successors); prefix->rdistance = prefix->distance = best_successor->distance; prefix->reported_metric = best_successor->total_metric; @@ -559,13 +544,13 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg) { struct list *successors = eigrp_topology_get_successor(msg->prefix); + struct eigrp_neighbor_entry *ne; assert(successors); // Cats and no Dogs + ne = listnode_head(successors); msg->prefix->state = EIGRP_FSM_STATE_ACTIVE_2; - msg->prefix->distance = - ((struct eigrp_neighbor_entry *)(successors->head->data)) - ->distance; + msg->prefix->distance = ne->distance; list_delete(successors); return 1; diff --git a/eigrpd/eigrp_fsm.h b/eigrpd/eigrp_fsm.h index 97a1f49281..8fad9d1f51 100644 --- a/eigrpd/eigrp_fsm.h +++ b/eigrpd/eigrp_fsm.h @@ -28,8 +28,7 @@ #ifndef _ZEBRA_EIGRP_FSM_H #define _ZEBRA_EIGRP_FSM_H -extern int eigrp_get_fsm_event(struct eigrp_fsm_action_message *); -extern int eigrp_fsm_event(struct eigrp_fsm_action_message *, int); +extern int eigrp_fsm_event(struct eigrp_fsm_action_message *msg); #endif /* _ZEBRA_EIGRP_DUAL_H */ diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c index b7c2f7f18d..ef10ebf54c 100644 --- a/eigrpd/eigrp_hello.c +++ b/eigrpd/eigrp_hello.c @@ -405,6 +405,20 @@ void eigrp_hello_receive(struct eigrp *eigrp, struct ip *iph, inet_ntoa(nbr->src)); } +u_int32_t FRR_MAJOR; +u_int32_t FRR_MINOR; + +void eigrp_sw_version_initialize(void) +{ + char ver_string[] = VERSION; + char *dash = strstr(ver_string, "-"); + + if (dash) + dash[0] = '\0'; + + sscanf(ver_string, "%d.%d", &FRR_MAJOR, &FRR_MINOR); +} + /** * @fn eigrp_sw_version_encode * @@ -425,10 +439,8 @@ static u_int16_t eigrp_sw_version_encode(struct stream *s) stream_putw(s, EIGRP_TLV_SW_VERSION); stream_putw(s, length); - // encode the version of quagga we're running - // DVS: need to figure out a cleaner way to do this - stream_putc(s, 0); //!< major os version - stream_putc(s, 99); //!< minor os version + stream_putc(s, FRR_MAJOR); //!< major os version + stream_putc(s, FRR_MINOR); //!< minor os version /* and the core eigrp version */ stream_putc(s, EIGRP_MAJOR_VERSION); @@ -614,11 +626,11 @@ static struct eigrp_packet *eigrp_hello_encode(struct eigrp_interface *ei, u_int16_t length = EIGRP_HEADER_LEN; // allocate a new packet to be sent - ep = eigrp_packet_new(ei->ifp->mtu); + ep = eigrp_packet_new(ei->ifp->mtu, NULL); if (ep) { // encode common header feilds - eigrp_packet_header_init(EIGRP_OPC_HELLO, ei, ep->s, 0, 0, ack); + eigrp_packet_header_init(EIGRP_OPC_HELLO, ei->eigrp, ep->s, 0, 0, ack); // encode Authentication TLV if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) @@ -707,7 +719,7 @@ void eigrp_hello_send_ack(struct eigrp_neighbor *nbr) inet_ntoa(nbr->src)); /* Add packet to the top of the interface output queue*/ - eigrp_fifo_push_head(nbr->ei->obuf, ep); + eigrp_fifo_push(nbr->ei->obuf, ep); /* Hook thread to write packet. */ if (nbr->ei->on_write_q == 0) { @@ -755,7 +767,7 @@ void eigrp_hello_send(struct eigrp_interface *ei, u_char flags, if (ep) { // Add packet to the top of the interface output queue - eigrp_fifo_push_head(ei->obuf, ep); + eigrp_fifo_push(ei->obuf, ep); /* Hook thread to write packet. */ if (ei->on_write_q == 0) { diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c index 7f05e14703..aa59516002 100644 --- a/eigrpd/eigrp_interface.c +++ b/eigrpd/eigrp_interface.c @@ -53,6 +53,7 @@ #include "eigrpd/eigrp_network.h" #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_memory.h" +#include "eigrpd/eigrp_fsm.h" static void eigrp_delete_from_if(struct interface *, struct eigrp_interface *); @@ -150,8 +151,8 @@ struct list *eigrp_iflist; void eigrp_if_init() { /* Initialize Zebra interface data structure. */ - if_add_hook(IF_NEW_HOOK, eigrp_if_new_hook); - if_add_hook(IF_DELETE_HOOK, eigrp_if_delete_hook); + hook_register_prio(if_add, 0, eigrp_if_new_hook); + hook_register_prio(if_del, 0, eigrp_if_delete_hook); } int eigrp_if_new_hook(struct interface *ifp) @@ -224,14 +225,14 @@ void eigrp_del_if_params(struct eigrp_if_params *eip) struct eigrp_if_params *eigrp_lookup_if_params(struct interface *ifp, struct in_addr addr) { - struct prefix_ipv4 p; + struct prefix p; struct route_node *rn; p.family = AF_INET; p.prefixlen = IPV4_MAX_PREFIXLEN; - p.prefix = addr; + p.u.prefix4 = addr; - rn = route_node_lookup(IF_OIFS_PARAMS(ifp), (struct prefix *)&p); + rn = route_node_lookup(IF_OIFS_PARAMS(ifp), &p); if (rn) { route_unlock_node(rn); @@ -279,49 +280,63 @@ int eigrp_if_up(struct eigrp_interface *ei) /*Add connected entry to topology table*/ - struct prefix_ipv4 dest_addr; - - dest_addr.family = AF_INET; - dest_addr.prefix = ei->connected->address->u.prefix4; - dest_addr.prefixlen = ei->connected->address->prefixlen; - apply_mask_ipv4(&dest_addr); - pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table, - &dest_addr); - - if (pe == NULL) { - pe = eigrp_prefix_entry_new(); - pe->serno = eigrp->serno; - pe->destination_ipv4 = prefix_ipv4_new(); - prefix_copy((struct prefix *)pe->destination_ipv4, - (struct prefix *)&dest_addr); - pe->af = AF_INET; - pe->nt = EIGRP_TOPOLOGY_TYPE_CONNECTED; - - pe->state = EIGRP_FSM_STATE_PASSIVE; - pe->fdistance = eigrp_calculate_metrics(eigrp, metric); - pe->req_action |= EIGRP_FSM_NEED_UPDATE; - eigrp_prefix_entry_add(eigrp->topology_table, pe); - listnode_add(eigrp->topology_changes_internalIPV4, pe); - } ne = eigrp_neighbor_entry_new(); ne->ei = ei; ne->reported_metric = metric; ne->total_metric = metric; ne->distance = eigrp_calculate_metrics(eigrp, metric); ne->reported_distance = 0; - ne->prefix = pe; ne->adv_router = eigrp->neighbor_self; ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG; - eigrp_neighbor_entry_add(pe, ne); - for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei2)) { - if (ei2->nbrs->count != 0) { + struct prefix dest_addr; + + dest_addr.family = AF_INET; + dest_addr.u.prefix4 = ei->connected->address->u.prefix4; + dest_addr.prefixlen = ei->connected->address->prefixlen; + apply_mask(&dest_addr); + pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table, + &dest_addr); + + if (pe == NULL) { + pe = eigrp_prefix_entry_new(); + pe->serno = eigrp->serno; + pe->destination = (struct prefix *)prefix_ipv4_new(); + prefix_copy(pe->destination, &dest_addr); + pe->af = AF_INET; + pe->nt = EIGRP_TOPOLOGY_TYPE_CONNECTED; + + ne->prefix = pe; + pe->reported_metric = metric; + pe->state = EIGRP_FSM_STATE_PASSIVE; + pe->fdistance = eigrp_calculate_metrics(eigrp, metric); + pe->req_action |= EIGRP_FSM_NEED_UPDATE; + eigrp_prefix_entry_add(eigrp->topology_table, pe); + listnode_add(eigrp->topology_changes_internalIPV4, pe); + + eigrp_neighbor_entry_add(pe, ne); + + for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei2)) { eigrp_update_send(ei2); } - } - pe->req_action &= ~EIGRP_FSM_NEED_UPDATE; - listnode_delete(eigrp->topology_changes_internalIPV4, pe); + pe->req_action &= ~EIGRP_FSM_NEED_UPDATE; + listnode_delete(eigrp->topology_changes_internalIPV4, pe); + } else { + struct eigrp_fsm_action_message msg; + + ne->prefix = pe; + eigrp_neighbor_entry_add(pe, ne); + + msg.packet_type = EIGRP_OPC_UPDATE; + msg.eigrp = eigrp; + msg.data_type = EIGRP_CONNECTED; + msg.adv_router = NULL; + msg.entry = ne; + msg.prefix = pe; + + eigrp_fsm_event(&msg); + } return 1; } @@ -416,7 +431,7 @@ u_char eigrp_default_iftype(struct interface *ifp) void eigrp_if_free(struct eigrp_interface *ei, int source) { - struct prefix_ipv4 dest_addr; + struct prefix dest_addr; struct eigrp_prefix_entry *pe; struct eigrp *eigrp = eigrp_lookup(); @@ -425,10 +440,8 @@ void eigrp_if_free(struct eigrp_interface *ei, int source) eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL); } - dest_addr.family = AF_INET; - dest_addr.prefix = ei->connected->address->u.prefix4; - dest_addr.prefixlen = ei->connected->address->prefixlen; - apply_mask_ipv4(&dest_addr); + dest_addr = *ei->connected->address; + apply_mask(&dest_addr); pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table, &dest_addr); if (pe) @@ -532,11 +545,11 @@ struct eigrp_interface *eigrp_if_lookup_recv_if(struct eigrp *eigrp, struct interface *ifp) { struct route_node *rn; - struct prefix_ipv4 addr; + struct prefix addr; struct eigrp_interface *ei, *match; addr.family = AF_INET; - addr.prefix = src; + addr.u.prefix4 = src; addr.prefixlen = IPV4_MAX_BITLEN; match = NULL; @@ -551,7 +564,7 @@ struct eigrp_interface *eigrp_if_lookup_recv_if(struct eigrp *eigrp, continue; if (prefix_match(CONNECTED_PREFIX(ei->connected), - (struct prefix *)&addr)) { + &addr)) { if ((match == NULL) || (match->address->prefixlen < ei->address->prefixlen)) match = ei; diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index 4c99821d3c..705e04b34d 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -159,6 +159,8 @@ int main(int argc, char **argv, char **envp) } } + eigrp_sw_version_initialize(); + /* EIGRP master init. */ eigrp_master_init(); eigrp_om->master = frr_init(); diff --git a/eigrpd/eigrp_neighbor.c b/eigrpd/eigrp_neighbor.c index d5fc6a2996..5d78dc375c 100644 --- a/eigrpd/eigrp_neighbor.c +++ b/eigrpd/eigrp_neighbor.c @@ -357,3 +357,11 @@ void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty) /* delete neighbor */ eigrp_nbr_delete(nbr); } + +int eigrp_nbr_split_horizon_check(struct eigrp_neighbor_entry *ne, struct eigrp_interface *ei) +{ + if (ne->distance == EIGRP_MAX_METRIC) + return 0; + + return (ne->ei == ei); +} diff --git a/eigrpd/eigrp_neighbor.h b/eigrpd/eigrp_neighbor.h index 006aa9ab75..6467fb24a9 100644 --- a/eigrpd/eigrp_neighbor.h +++ b/eigrpd/eigrp_neighbor.h @@ -53,4 +53,6 @@ extern struct eigrp_neighbor *eigrp_nbr_lookup_by_addr_process(struct eigrp *, struct in_addr); extern void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty); +extern int eigrp_nbr_split_horizon_check(struct eigrp_neighbor_entry *ne, + struct eigrp_interface *ei); #endif /* _ZEBRA_EIGRP_NEIGHBOR_H */ diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c index ec8806750b..0cf5bd9bad 100644 --- a/eigrpd/eigrp_network.c +++ b/eigrpd/eigrp_network.c @@ -229,7 +229,7 @@ int eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p, return ret; } -int eigrp_network_set(struct eigrp *eigrp, struct prefix_ipv4 *p) +int eigrp_network_set(struct eigrp *eigrp, struct prefix *p) { struct route_node *rn; struct interface *ifp; @@ -242,7 +242,7 @@ int eigrp_network_set(struct eigrp *eigrp, struct prefix_ipv4 *p) return 0; } - struct prefix_ipv4 *pref = prefix_ipv4_new(); + struct prefix *pref = prefix_new(); PREFIX_COPY_IPV4(pref, p); rn->info = (void *)pref; @@ -253,7 +253,7 @@ int eigrp_network_set(struct eigrp *eigrp, struct prefix_ipv4 *p) /* Get target interface. */ for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { zlog_debug("Setting up %s", ifp->name); - eigrp_network_run_interface(eigrp, (struct prefix *)p, ifp); + eigrp_network_run_interface(eigrp, p, ifp); } return 1; } @@ -334,21 +334,21 @@ void eigrp_if_update(struct interface *ifp) } } -int eigrp_network_unset(struct eigrp *eigrp, struct prefix_ipv4 *p) +int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p) { struct route_node *rn; struct listnode *node, *nnode; struct eigrp_interface *ei; struct prefix *pref; - rn = route_node_lookup(eigrp->networks, (struct prefix *)p); + rn = route_node_lookup(eigrp->networks, p); if (rn == NULL) return 0; pref = rn->info; route_unlock_node(rn); - if (!IPV4_ADDR_SAME(&pref->u.prefix4, &p->prefix)) + if (!IPV4_ADDR_SAME(&pref->u.prefix4, &p->u.prefix4)) return 0; prefix_ipv4_free(rn->info); diff --git a/eigrpd/eigrp_network.h b/eigrpd/eigrp_network.h index e38f7ded40..6ddd57eee5 100644 --- a/eigrpd/eigrp_network.h +++ b/eigrpd/eigrp_network.h @@ -32,8 +32,8 @@ extern int eigrp_sock_init(void); extern int eigrp_if_ipmulticast(struct eigrp *, struct prefix *, unsigned int); -extern int eigrp_network_set(struct eigrp *, struct prefix_ipv4 *); -extern int eigrp_network_unset(struct eigrp *eigrp, struct prefix_ipv4 *p); +extern int eigrp_network_set(struct eigrp *eigrp, struct prefix *p); +extern int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p); extern int eigrp_hello_timer(struct thread *); extern void eigrp_if_update(struct interface *); diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c index dfc7463025..68e7cdcbbe 100644 --- a/eigrpd/eigrp_packet.c +++ b/eigrpd/eigrp_packet.c @@ -299,18 +299,6 @@ int eigrp_check_sha256_digest(struct stream *s, return 1; } -/* - * eigrp_packet_dump - * - * This routing dumps the contents of the IP packet either received or - * built by EIGRP. - */ -static void eigrp_packet_dump(struct stream *s) -{ - // not yet... - return; -} - int eigrp_write(struct thread *thread) { struct eigrp *eigrp = THREAD_ARG(thread); @@ -322,6 +310,7 @@ int eigrp_write(struct thread *thread) struct msghdr msg; struct iovec iov[2]; u_int16_t opcode = 0; + u_int32_t seqno, ack; int ret; int flags = 0; @@ -347,7 +336,7 @@ int eigrp_write(struct thread *thread) #endif /* WANT_EIGRP_WRITE_FRAGMENT */ /* Get one packet from queue. */ - ep = eigrp_fifo_head(ei->obuf); + ep = eigrp_fifo_next(ei->obuf); assert(ep); assert(ep->length >= EIGRP_HEADER_LEN); @@ -357,6 +346,25 @@ int eigrp_write(struct thread *thread) memset(&iph, 0, sizeof(struct ip)); memset(&sa_dst, 0, sizeof(sa_dst)); + /* + * We build and schedule packets to go out + * in the future. In the mean time we may + * process some update packets from the + * neighbor, thus making it necessary + * to update the ack we are using for + * this outgoing packet. + */ + eigrph = (struct eigrp_header *)STREAM_DATA(ep->s); + opcode = eigrph->opcode; + seqno = ntohl(eigrph->sequence); + ack = ntohl(eigrph->ack); + if (ep->nbr && (ack != ep->nbr->recv_sequence_number)) { + eigrph->ack = htonl(ep->nbr->recv_sequence_number); + ack = ep->nbr->recv_sequence_number; + eigrph->checksum = 0; + eigrp_packet_checksum(ei, ep->s, ep->length); + } + sa_dst.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sa_dst.sin_len = sizeof(sa_dst); @@ -412,8 +420,9 @@ int eigrp_write(struct thread *thread) if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND)) { eigrph = (struct eigrp_header *)STREAM_DATA(ep->s); opcode = eigrph->opcode; - zlog_debug("Sending [%s] to [%s] via [%s] ret [%d].", + zlog_debug("Sending [%s][%d/%d] to [%s] via [%s] ret [%d].", lookup_msg(eigrp_packet_type_str, opcode, NULL), + seqno, ack, inet_ntoa(ep->dst), IF_NAME(ei), ret); } @@ -425,22 +434,10 @@ int eigrp_write(struct thread *thread) iph.ip_len, ei->ifp->name, ei->ifp->mtu, safe_strerror(errno)); - /* Show debug sending packet. */ - if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND) - && (IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))) { - zlog_debug( - "-----------------------------------------------------"); - eigrp_ip_header_dump(&iph); - stream_set_getp(ep->s, 0); - eigrp_packet_dump(ep->s); - zlog_debug( - "-----------------------------------------------------"); - } - /* Now delete packet from queue. */ eigrp_packet_delete(ei); - if (eigrp_fifo_head(ei->obuf) == NULL) { + if (eigrp_fifo_next(ei->obuf) == NULL) { ei->on_write_q = 0; list_delete_node(eigrp->oi_write_q, node); } @@ -530,7 +527,7 @@ int eigrp_read(struct thread *thread) /* Self-originated packet should be discarded silently. */ if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src) - || (IPV4_ADDR_SAME(&iph->ip_src.s_addr, &ei->address->u.prefix4))) { + || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address->u.prefix4))) { if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) zlog_debug( "eigrp_read[%s]: Dropping self-originated packet", @@ -615,52 +612,51 @@ int eigrp_read(struct thread *thread) start of the eigrp TLVs */ opcode = eigrph->opcode; - if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) - zlog_debug( - "Received [%s] length [%u] via [%s] src [%s] dst [%s]", - lookup_msg(eigrp_packet_type_str, opcode, NULL), length, - IF_NAME(ei), inet_ntoa(iph->ip_src), - inet_ntoa(iph->ip_dst)); + if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) { + char src[100], dst[100]; + + strcpy(src, inet_ntoa(iph->ip_src)); + strcpy(dst, inet_ntoa(iph->ip_dst)); + zlog_debug("Received [%s][%d/%d] length [%u] via [%s] src [%s] dst [%s]", + lookup_msg(eigrp_packet_type_str, opcode, NULL), + ntohl(eigrph->sequence), ntohl(eigrph->ack), length, + IF_NAME(ei), src, dst); + } /* Read rest of the packet and call each sort of packet routine. */ stream_forward_getp(ibuf, EIGRP_HEADER_LEN); /* New testing block of code for handling Acks */ if (ntohl(eigrph->ack) != 0) { + struct eigrp_packet *ep = NULL; + nbr = eigrp_nbr_get(ei, eigrph, iph); - /* neighbor must be valid, eigrp_nbr_get creates if none existed - */ + // neighbor must be valid, eigrp_nbr_get creates if none existed assert(nbr); - struct eigrp_packet *ep; + ep = eigrp_fifo_next(nbr->retrans_queue); + if ((ep) && (ntohl(eigrph->ack) == ep->sequence_number)) { + ep = eigrp_fifo_pop(nbr->retrans_queue); + eigrp_packet_free(ep); - ep = eigrp_fifo_tail(nbr->retrans_queue); - if (ep) { - if (ntohl(eigrph->ack) == ep->sequence_number) { - if ((nbr->state == EIGRP_NEIGHBOR_PENDING) - && (ntohl(eigrph->ack) - == nbr->init_sequence_number)) { - eigrp_nbr_state_set(nbr, - EIGRP_NEIGHBOR_UP); - zlog_info( - "Neighbor adjacency became full"); - nbr->init_sequence_number = 0; - nbr->recv_sequence_number = - ntohl(eigrph->sequence); - eigrp_update_send_EOT(nbr); - } - ep = eigrp_fifo_pop_tail(nbr->retrans_queue); - eigrp_packet_free(ep); - if (nbr->retrans_queue->count > 0) { - eigrp_send_packet_reliably(nbr); - } + if ((nbr->state == EIGRP_NEIGHBOR_PENDING) + && (ntohl(eigrph->ack) == nbr->init_sequence_number)) { + eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_UP); + zlog_info("Neighbor(%s) adjacency became full", + inet_ntoa(nbr->src)); + nbr->init_sequence_number = 0; + nbr->recv_sequence_number = + ntohl(eigrph->sequence); + eigrp_update_send_EOT(nbr); } + else + eigrp_send_packet_reliably(nbr); } - ep = eigrp_fifo_tail(nbr->multicast_queue); + ep = eigrp_fifo_next(nbr->multicast_queue); if (ep) { if (ntohl(eigrph->ack) == ep->sequence_number) { - ep = eigrp_fifo_pop_tail(nbr->multicast_queue); + ep = eigrp_fifo_pop(nbr->multicast_queue); eigrp_packet_free(ep); if (nbr->multicast_queue->count > 0) { eigrp_send_packet_reliably(nbr); @@ -826,13 +822,14 @@ void eigrp_fifo_reset(struct eigrp_fifo *fifo) fifo->count = 0; } -struct eigrp_packet *eigrp_packet_new(size_t size) +struct eigrp_packet *eigrp_packet_new(size_t size, struct eigrp_neighbor *nbr) { struct eigrp_packet *new; new = XCALLOC(MTYPE_EIGRP_PACKET, sizeof(struct eigrp_packet)); new->s = stream_new(size); new->retrans_counter = 0; + new->nbr = nbr; return new; } @@ -841,13 +838,13 @@ void eigrp_send_packet_reliably(struct eigrp_neighbor *nbr) { struct eigrp_packet *ep; - ep = eigrp_fifo_tail(nbr->retrans_queue); + ep = eigrp_fifo_next(nbr->retrans_queue); if (ep) { struct eigrp_packet *duplicate; duplicate = eigrp_packet_duplicate(ep, nbr); /* Add packet to the top of the interface output queue*/ - eigrp_fifo_push_head(nbr->ei->obuf, duplicate); + eigrp_fifo_push(nbr->ei->obuf, duplicate); /*Start retransmission timer*/ thread_add_timer(master, eigrp_unack_packet_retrans, nbr, @@ -880,7 +877,7 @@ void eigrp_packet_checksum(struct eigrp_interface *ei, struct stream *s, } /* Make EIGRP header. */ -void eigrp_packet_header_init(int type, struct eigrp_interface *ei, +void eigrp_packet_header_init(int type, struct eigrp *eigrp, struct stream *s, u_int32_t flags, u_int32_t sequence, u_int32_t ack) { @@ -893,15 +890,15 @@ void eigrp_packet_header_init(int type, struct eigrp_interface *ei, eigrph->opcode = (u_char)type; eigrph->checksum = 0; - eigrph->vrid = htons(ei->eigrp->vrid); - eigrph->ASNumber = htons(ei->eigrp->AS); + eigrph->vrid = htons(eigrp->vrid); + eigrph->ASNumber = htons(eigrp->AS); eigrph->ack = htonl(ack); eigrph->sequence = htonl(sequence); // if(flags == EIGRP_INIT_FLAG) // eigrph->sequence = htonl(3); eigrph->flags = htonl(flags); - if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) + if (IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL)) zlog_debug("Packet Header Init Seq [%u] Ack [%u]", htonl(eigrph->sequence), htonl(eigrph->ack)); @@ -909,7 +906,7 @@ void eigrp_packet_header_init(int type, struct eigrp_interface *ei, } /* Add new packet to head of fifo. */ -void eigrp_fifo_push_head(struct eigrp_fifo *fifo, struct eigrp_packet *ep) +void eigrp_fifo_push(struct eigrp_fifo *fifo, struct eigrp_packet *ep) { ep->next = fifo->head; ep->previous = NULL; @@ -925,14 +922,8 @@ void eigrp_fifo_push_head(struct eigrp_fifo *fifo, struct eigrp_packet *ep) fifo->count++; } -/* Return first fifo entry. */ -struct eigrp_packet *eigrp_fifo_head(struct eigrp_fifo *fifo) -{ - return fifo->head; -} - /* Return last fifo entry. */ -struct eigrp_packet *eigrp_fifo_tail(struct eigrp_fifo *fifo) +struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *fifo) { return fifo->tail; } @@ -947,27 +938,6 @@ void eigrp_packet_delete(struct eigrp_interface *ei) eigrp_packet_free(ep); } -/* Delete first packet from fifo. */ -struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *fifo) -{ - struct eigrp_packet *ep; - - ep = fifo->head; - - if (ep) { - fifo->head = ep->next; - - if (fifo->head == NULL) - fifo->tail = NULL; - else - fifo->head->previous = NULL; - - fifo->count--; - } - - return ep; -} - void eigrp_packet_free(struct eigrp_packet *ep) { if (ep->s) @@ -1028,14 +998,14 @@ int eigrp_unack_packet_retrans(struct thread *thread) nbr = (struct eigrp_neighbor *)THREAD_ARG(thread); struct eigrp_packet *ep; - ep = eigrp_fifo_tail(nbr->retrans_queue); + ep = eigrp_fifo_next(nbr->retrans_queue); if (ep) { struct eigrp_packet *duplicate; duplicate = eigrp_packet_duplicate(ep, nbr); /* Add packet to the top of the interface output queue*/ - eigrp_fifo_push_head(nbr->ei->obuf, duplicate); + eigrp_fifo_push(nbr->ei->obuf, duplicate); ep->retrans_counter++; if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX) @@ -1065,13 +1035,13 @@ int eigrp_unack_multicast_packet_retrans(struct thread *thread) nbr = (struct eigrp_neighbor *)THREAD_ARG(thread); struct eigrp_packet *ep; - ep = eigrp_fifo_tail(nbr->multicast_queue); + ep = eigrp_fifo_next(nbr->multicast_queue); if (ep) { struct eigrp_packet *duplicate; duplicate = eigrp_packet_duplicate(ep, nbr); /* Add packet to the top of the interface output queue*/ - eigrp_fifo_push_head(nbr->ei->obuf, duplicate); + eigrp_fifo_push(nbr->ei->obuf, duplicate); ep->retrans_counter++; if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX) @@ -1096,9 +1066,9 @@ int eigrp_unack_multicast_packet_retrans(struct thread *thread) } /* Get packet from tail of fifo. */ -struct eigrp_packet *eigrp_fifo_pop_tail(struct eigrp_fifo *fifo) +struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *fifo) { - struct eigrp_packet *ep; + struct eigrp_packet *ep = NULL; ep = fifo->tail; @@ -1121,7 +1091,7 @@ struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old, { struct eigrp_packet *new; - new = eigrp_packet_new(nbr->ei->ifp->mtu); + new = eigrp_packet_new(nbr->ei->ifp->mtu, nbr); new->length = old->length; new->retrans_counter = old->retrans_counter; new->dst = old->dst; @@ -1131,6 +1101,16 @@ struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old, return new; } +static struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new() +{ + struct TLV_IPv4_Internal_type *new; + + new = XCALLOC(MTYPE_EIGRP_IPV4_INT_TLV, + sizeof(struct TLV_IPv4_Internal_type)); + + return new; +} + struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s) { struct TLV_IPv4_Internal_type *tlv; @@ -1187,21 +1167,21 @@ u_int16_t eigrp_add_internalTLV_to_stream(struct stream *s, u_int16_t length; stream_putw(s, EIGRP_TLV_IPv4_INT); - if (pe->destination_ipv4->prefixlen <= 8) { + if (pe->destination->prefixlen <= 8) { stream_putw(s, 0x001A); length = 0x001A; } - if ((pe->destination_ipv4->prefixlen > 8) - && (pe->destination_ipv4->prefixlen <= 16)) { + if ((pe->destination->prefixlen > 8) + && (pe->destination->prefixlen <= 16)) { stream_putw(s, 0x001B); length = 0x001B; } - if ((pe->destination_ipv4->prefixlen > 16) - && (pe->destination_ipv4->prefixlen <= 24)) { + if ((pe->destination->prefixlen > 16) + && (pe->destination->prefixlen <= 24)) { stream_putw(s, 0x001C); length = 0x001C; } - if (pe->destination_ipv4->prefixlen > 24) { + if (pe->destination->prefixlen > 24) { stream_putw(s, 0x001D); length = 0x001D; } @@ -1220,34 +1200,18 @@ u_int16_t eigrp_add_internalTLV_to_stream(struct stream *s, stream_putc(s, pe->reported_metric.tag); stream_putc(s, pe->reported_metric.flags); - stream_putc(s, pe->destination_ipv4->prefixlen); + stream_putc(s, pe->destination->prefixlen); - if (pe->destination_ipv4->prefixlen <= 8) { - stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF); - } - if ((pe->destination_ipv4->prefixlen > 8) - && (pe->destination_ipv4->prefixlen <= 16)) { - stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF); + stream_putc(s, pe->destination->u.prefix4.s_addr & 0xFF); + if (pe->destination->prefixlen > 8) stream_putc(s, - (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF); - } - if ((pe->destination_ipv4->prefixlen > 16) - && (pe->destination_ipv4->prefixlen <= 24)) { - stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF); + (pe->destination->u.prefix4.s_addr >> 8) & 0xFF); + if (pe->destination->prefixlen > 16) stream_putc(s, - (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF); + (pe->destination->u.prefix4.s_addr >> 16) & 0xFF); + if (pe->destination->prefixlen > 24) stream_putc(s, - (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF); - } - if (pe->destination_ipv4->prefixlen > 24) { - stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF); - stream_putc(s, - (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF); - stream_putc(s, - (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF); - stream_putc(s, - (pe->destination_ipv4->prefix.s_addr >> 24) & 0xFF); - } + (pe->destination->u.prefix4.s_addr >> 24) & 0xFF); return length; } @@ -1362,16 +1326,6 @@ void eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *authTLV) XFREE(MTYPE_EIGRP_AUTH_SHA256_TLV, authTLV); } -struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new() -{ - struct TLV_IPv4_Internal_type *new; - - new = XCALLOC(MTYPE_EIGRP_IPV4_INT_TLV, - sizeof(struct TLV_IPv4_Internal_type)); - - return new; -} - void eigrp_IPv4_InternalTLV_free( struct TLV_IPv4_Internal_type *IPv4_InternalTLV) { diff --git a/eigrpd/eigrp_packet.h b/eigrpd/eigrp_packet.h index 2f607e5cab..e52fd268fa 100644 --- a/eigrpd/eigrp_packet.h +++ b/eigrpd/eigrp_packet.h @@ -36,23 +36,21 @@ extern int eigrp_read(struct thread *); extern int eigrp_write(struct thread *); -extern struct eigrp_packet *eigrp_packet_new(size_t); +extern struct eigrp_packet *eigrp_packet_new(size_t, struct eigrp_neighbor *); extern struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *, struct eigrp_neighbor *); extern void eigrp_packet_free(struct eigrp_packet *); extern void eigrp_packet_delete(struct eigrp_interface *); -extern void eigrp_packet_header_init(int, struct eigrp_interface *, +extern void eigrp_packet_header_init(int, struct eigrp *, struct stream *, u_int32_t, u_int32_t, u_int32_t); extern void eigrp_packet_checksum(struct eigrp_interface *, struct stream *, u_int16_t); extern struct eigrp_fifo *eigrp_fifo_new(void); -extern struct eigrp_packet *eigrp_fifo_head(struct eigrp_fifo *); -extern struct eigrp_packet *eigrp_fifo_tail(struct eigrp_fifo *); +extern struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *); extern struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *); -extern struct eigrp_packet *eigrp_fifo_pop_tail(struct eigrp_fifo *); -extern void eigrp_fifo_push_head(struct eigrp_fifo *, struct eigrp_packet *); +extern void eigrp_fifo_push(struct eigrp_fifo *, struct eigrp_packet *); extern void eigrp_fifo_free(struct eigrp_fifo *); extern void eigrp_fifo_reset(struct eigrp_fifo *); @@ -73,6 +71,7 @@ extern int eigrp_unack_multicast_packet_retrans(struct thread *); * untill there is reason to have their own header, these externs are found in * eigrp_hello.c */ +extern void eigrp_sw_version_initialize(void); extern void eigrp_hello_send(struct eigrp_interface *, u_char, struct in_addr *); extern void eigrp_hello_send_ack(struct eigrp_neighbor *); @@ -153,7 +152,6 @@ extern int eigrp_check_sha256_digest(struct stream *, struct eigrp_neighbor *, u_char); -extern struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new(void); extern void eigrp_IPv4_InternalTLV_free(struct TLV_IPv4_Internal_type *); extern struct TLV_Sequence_Type *eigrp_SequenceTLV_new(void); diff --git a/eigrpd/eigrp_query.c b/eigrpd/eigrp_query.c index 653eae258f..0167c8b3c2 100644 --- a/eigrpd/eigrp_query.c +++ b/eigrpd/eigrp_query.c @@ -91,8 +91,10 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph, { struct eigrp_neighbor *nbr; struct TLV_IPv4_Internal_type *tlv; + struct prefix dest_addr; u_int16_t type; + u_int16_t length; /* increment statistics. */ ei->query_in++; @@ -107,15 +109,14 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph, while (s->endp > s->getp) { type = stream_getw(s); - if (type == EIGRP_TLV_IPv4_INT) { - struct prefix_ipv4 dest_addr; - + switch (type) { + case EIGRP_TLV_IPv4_INT: stream_set_getp(s, s->getp - sizeof(u_int16_t)); tlv = eigrp_read_ipv4_tlv(s); dest_addr.family = AF_INET; - dest_addr.prefix = tlv->destination; + dest_addr.u.prefix4 = tlv->destination; dest_addr.prefixlen = tlv->prefix_length; struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( @@ -124,24 +125,32 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph, /* If the destination exists (it should, but one never * know)*/ if (dest != NULL) { - struct eigrp_fsm_action_message *msg; - msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, - sizeof(struct - eigrp_fsm_action_message)); + struct eigrp_fsm_action_message msg; struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(dest->entries, nbr); - msg->packet_type = EIGRP_OPC_QUERY; - msg->eigrp = eigrp; - msg->data_type = EIGRP_TLV_IPv4_INT; - msg->adv_router = nbr; - msg->data.ipv4_int_type = tlv; - msg->entry = entry; - msg->prefix = dest; - int event = eigrp_get_fsm_event(msg); - eigrp_fsm_event(msg, event); + msg.packet_type = EIGRP_OPC_QUERY; + msg.eigrp = eigrp; + msg.data_type = EIGRP_INT; + msg.adv_router = nbr; + msg.metrics = tlv->metric; + msg.entry = entry; + msg.prefix = dest; + eigrp_fsm_event(&msg); } eigrp_IPv4_InternalTLV_free(tlv); + break; + + case EIGRP_TLV_IPv4_EXT: + /* DVS: processing of external routes needs packet and fsm work. + * for now, lets just not creash the box + */ + default: + length = stream_getw(s); + // -2 for type, -2 for len + for (length-=4; length ; length--) { + (void)stream_getc(s); + } } } eigrp_hello_send_ack(nbr); @@ -159,10 +168,10 @@ void eigrp_send_query(struct eigrp_interface *ei) char has_tlv; bool ep_saved = false; - ep = eigrp_packet_new(ei->ifp->mtu); + ep = eigrp_packet_new(ei->ifp->mtu, NULL); /* Prepare EIGRP INIT UPDATE header */ - eigrp_packet_header_init(EIGRP_OPC_QUERY, ei, ep->s, 0, + eigrp_packet_header_init(EIGRP_OPC_QUERY, ei->eigrp, ep->s, 0, ei->eigrp->sequence_number, 0); // encode Authentication TLV, if needed @@ -207,7 +216,7 @@ void eigrp_send_query(struct eigrp_interface *ei) for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr)) { if (nbr->state == EIGRP_NEIGHBOR_UP) { /*Put packet to retransmission queue*/ - eigrp_fifo_push_head(nbr->retrans_queue, ep); + eigrp_fifo_push(nbr->retrans_queue, ep); ep_saved = true; if (nbr->retrans_queue->count == 1) { diff --git a/eigrpd/eigrp_reply.c b/eigrpd/eigrp_reply.c index 4eb08c60d0..2b5b0aa44b 100644 --- a/eigrpd/eigrp_reply.c +++ b/eigrpd/eigrp_reply.c @@ -84,40 +84,36 @@ void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe) plist = e->prefix[EIGRP_FILTER_OUT]; alist_i = nbr->ei->list[EIGRP_FILTER_OUT]; plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT]; - zlog_info("REPLY Send: Filtering"); - zlog_info("REPLY SEND Prefix: %s", inet_ntoa(nbr->src)); /* Check if any list fits */ if ((alist - && access_list_apply(alist, (struct prefix *)pe2->destination_ipv4) + && access_list_apply(alist, pe2->destination) == FILTER_DENY) || (plist && prefix_list_apply(plist, - (struct prefix *)pe2->destination_ipv4) + pe2->destination) == PREFIX_DENY) || (alist_i && access_list_apply(alist_i, - (struct prefix *)pe2->destination_ipv4) + pe2->destination) == FILTER_DENY) || (plist_i && prefix_list_apply(plist_i, - (struct prefix *)pe2->destination_ipv4) + pe2->destination) == PREFIX_DENY)) { zlog_info("REPLY SEND: Setting Metric to max"); pe2->reported_metric.delay = EIGRP_MAX_METRIC; - } else { - zlog_info("REPLY SEND: Not setting metric"); } /* * End of filtering */ - ep = eigrp_packet_new(nbr->ei->ifp->mtu); + ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr); /* Prepare EIGRP INIT UPDATE header */ - eigrp_packet_header_init(EIGRP_OPC_REPLY, nbr->ei, ep->s, 0, + eigrp_packet_header_init(EIGRP_OPC_REPLY, e, ep->s, 0, nbr->ei->eigrp->sequence_number, 0); // encode Authentication TLV, if needed @@ -144,7 +140,7 @@ void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe) ep->sequence_number = nbr->ei->eigrp->sequence_number; /*Put packet to retransmission queue*/ - eigrp_fifo_push_head(nbr->retrans_queue, ep); + eigrp_fifo_push(nbr->retrans_queue, ep); if (nbr->retrans_queue->count == 1) { eigrp_send_packet_reliably(nbr); @@ -183,14 +179,14 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph, while (s->endp > s->getp) { type = stream_getw(s); if (type == EIGRP_TLV_IPv4_INT) { - struct prefix_ipv4 dest_addr; + struct prefix dest_addr; stream_set_getp(s, s->getp - sizeof(u_int16_t)); tlv = eigrp_read_ipv4_tlv(s); dest_addr.family = AF_INET; - dest_addr.prefix = tlv->destination; + dest_addr.u.prefix4 = tlv->destination; dest_addr.prefixlen = tlv->prefix_length; struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( @@ -200,9 +196,7 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph, */ assert(dest); - struct eigrp_fsm_action_message *msg; - msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, - sizeof(struct eigrp_fsm_action_message)); + struct eigrp_fsm_action_message msg; struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(dest->entries, nbr); @@ -241,15 +235,14 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph, * End of filtering */ - msg->packet_type = EIGRP_OPC_REPLY; - msg->eigrp = eigrp; - msg->data_type = EIGRP_TLV_IPv4_INT; - msg->adv_router = nbr; - msg->data.ipv4_int_type = tlv; - msg->entry = entry; - msg->prefix = dest; - int event = eigrp_get_fsm_event(msg); - eigrp_fsm_event(msg, event); + msg.packet_type = EIGRP_OPC_REPLY; + msg.eigrp = eigrp; + msg.data_type = EIGRP_INT; + msg.adv_router = nbr; + msg.metrics = tlv->metric; + msg.entry = entry; + msg.prefix = dest; + eigrp_fsm_event(&msg); eigrp_IPv4_InternalTLV_free(tlv); diff --git a/eigrpd/eigrp_siaquery.c b/eigrpd/eigrp_siaquery.c index f16f49a330..7264e53b6b 100644 --- a/eigrpd/eigrp_siaquery.c +++ b/eigrpd/eigrp_siaquery.c @@ -78,14 +78,14 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph, while (s->endp > s->getp) { type = stream_getw(s); if (type == EIGRP_TLV_IPv4_INT) { - struct prefix_ipv4 dest_addr; + struct prefix dest_addr; stream_set_getp(s, s->getp - sizeof(u_int16_t)); tlv = eigrp_read_ipv4_tlv(s); dest_addr.family = AFI_IP; - dest_addr.prefix = tlv->destination; + dest_addr.u.prefix4 = tlv->destination; dest_addr.prefixlen = tlv->prefix_length; struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( @@ -94,22 +94,18 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph, /* If the destination exists (it should, but one never * know)*/ if (dest != NULL) { - struct eigrp_fsm_action_message *msg; - msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, - sizeof(struct - eigrp_fsm_action_message)); + struct eigrp_fsm_action_message msg; struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(dest->entries, nbr); - msg->packet_type = EIGRP_OPC_SIAQUERY; - msg->eigrp = eigrp; - msg->data_type = EIGRP_TLV_IPv4_INT; - msg->adv_router = nbr; - msg->data.ipv4_int_type = tlv; - msg->entry = entry; - msg->prefix = dest; - int event = eigrp_get_fsm_event(msg); - eigrp_fsm_event(msg, event); + msg.packet_type = EIGRP_OPC_SIAQUERY; + msg.eigrp = eigrp; + msg.data_type = EIGRP_INT; + msg.adv_router = nbr; + msg.metrics = tlv->metric; + msg.entry = entry; + msg.prefix = dest; + eigrp_fsm_event(&msg); } eigrp_IPv4_InternalTLV_free(tlv); } @@ -123,10 +119,10 @@ void eigrp_send_siaquery(struct eigrp_neighbor *nbr, struct eigrp_packet *ep; u_int16_t length = EIGRP_HEADER_LEN; - ep = eigrp_packet_new(nbr->ei->ifp->mtu); + ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr); /* Prepare EIGRP INIT UPDATE header */ - eigrp_packet_header_init(EIGRP_OPC_SIAQUERY, nbr->ei, ep->s, 0, + eigrp_packet_header_init(EIGRP_OPC_SIAQUERY, nbr->ei->eigrp, ep->s, 0, nbr->ei->eigrp->sequence_number, 0); // encode Authentication TLV, if needed @@ -153,7 +149,7 @@ void eigrp_send_siaquery(struct eigrp_neighbor *nbr, if (nbr->state == EIGRP_NEIGHBOR_UP) { /*Put packet to retransmission queue*/ - eigrp_fifo_push_head(nbr->retrans_queue, ep); + eigrp_fifo_push(nbr->retrans_queue, ep); if (nbr->retrans_queue->count == 1) { eigrp_send_packet_reliably(nbr); diff --git a/eigrpd/eigrp_siareply.c b/eigrpd/eigrp_siareply.c index 9a768566d3..8496c05675 100644 --- a/eigrpd/eigrp_siareply.c +++ b/eigrpd/eigrp_siareply.c @@ -77,14 +77,14 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph, while (s->endp > s->getp) { type = stream_getw(s); if (type == EIGRP_TLV_IPv4_INT) { - struct prefix_ipv4 dest_addr; + struct prefix dest_addr; stream_set_getp(s, s->getp - sizeof(u_int16_t)); tlv = eigrp_read_ipv4_tlv(s); dest_addr.family = AFI_IP; - dest_addr.prefix = tlv->destination; + dest_addr.u.prefix4 = tlv->destination; dest_addr.prefixlen = tlv->prefix_length; struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( @@ -93,22 +93,18 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph, /* If the destination exists (it should, but one never * know)*/ if (dest != NULL) { - struct eigrp_fsm_action_message *msg; - msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, - sizeof(struct - eigrp_fsm_action_message)); + struct eigrp_fsm_action_message msg; struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(dest->entries, nbr); - msg->packet_type = EIGRP_OPC_SIAQUERY; - msg->eigrp = eigrp; - msg->data_type = EIGRP_TLV_IPv4_INT; - msg->adv_router = nbr; - msg->data.ipv4_int_type = tlv; - msg->entry = entry; - msg->prefix = dest; - int event = eigrp_get_fsm_event(msg); - eigrp_fsm_event(msg, event); + msg.packet_type = EIGRP_OPC_SIAQUERY; + msg.eigrp = eigrp; + msg.data_type = EIGRP_INT; + msg.adv_router = nbr; + msg.metrics = tlv->metric; + msg.entry = entry; + msg.prefix = dest; + eigrp_fsm_event(&msg); } eigrp_IPv4_InternalTLV_free(tlv); } @@ -122,10 +118,10 @@ void eigrp_send_siareply(struct eigrp_neighbor *nbr, struct eigrp_packet *ep; u_int16_t length = EIGRP_HEADER_LEN; - ep = eigrp_packet_new(nbr->ei->ifp->mtu); + ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr); /* Prepare EIGRP INIT UPDATE header */ - eigrp_packet_header_init(EIGRP_OPC_SIAREPLY, nbr->ei, ep->s, 0, + eigrp_packet_header_init(EIGRP_OPC_SIAREPLY, nbr->ei->eigrp, ep->s, 0, nbr->ei->eigrp->sequence_number, 0); // encode Authentication TLV, if needed @@ -152,7 +148,7 @@ void eigrp_send_siareply(struct eigrp_neighbor *nbr, if (nbr->state == EIGRP_NEIGHBOR_UP) { /*Put packet to retransmission queue*/ - eigrp_fifo_push_head(nbr->retrans_queue, ep); + eigrp_fifo_push(nbr->retrans_queue, ep); if (nbr->retrans_queue->count == 1) { eigrp_send_packet_reliably(nbr); diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h index fd3e4b2014..b769774a03 100644 --- a/eigrpd/eigrp_structs.h +++ b/eigrpd/eigrp_structs.h @@ -311,6 +311,8 @@ struct eigrp_packet { /* EIGRP packet length. */ u_int16_t length; + + struct eigrp_neighbor *nbr; }; struct eigrp_fifo { @@ -467,10 +469,7 @@ struct eigrp_prefix_entry { u_char af; // address family u_char req_action; // required action - struct prefix_ipv4 - *destination_ipv4; // pointer to struct with ipv4 address - struct prefix_ipv6 - *destination_ipv6; // pointer to struct with ipv6 address + struct prefix *destination; // If network type is REMOTE_EXTERNAL, pointer will have reference to // its external TLV @@ -497,6 +496,11 @@ struct eigrp_neighbor_entry { }; //--------------------------------------------------------------------------------------------------------------------------------------------- +typedef enum { + EIGRP_CONNECTED, + EIGRP_INT, + EIGRP_EXT, +} msg_data_t; /* EIGRP Finite State Machine */ @@ -506,11 +510,8 @@ struct eigrp_fsm_action_message { struct eigrp_neighbor *adv_router; // advertising neighbor struct eigrp_neighbor_entry *entry; struct eigrp_prefix_entry *prefix; - int data_type; // internal or external tlv type - union { - struct TLV_IPv4_External_type *ipv4_ext_data; - struct TLV_IPv4_Internal_type *ipv4_int_type; - } data; + msg_data_t data_type; // internal or external tlv type + struct eigrp_metrics metrics; }; #endif /* _ZEBRA_EIGRP_STRUCTURES_H_ */ diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c index 50d83430a8..64e65b694c 100644 --- a/eigrpd/eigrp_topology.c +++ b/eigrpd/eigrp_topology.c @@ -81,25 +81,18 @@ static int eigrp_prefix_entry_cmp(struct eigrp_prefix_entry *node1, { if (node1->af == AF_INET) { if (node2->af == AF_INET) { - if (node1->destination_ipv4->prefix.s_addr - < node2->destination_ipv4->prefix.s_addr) { - return -1; // if it belong above node2 - } else { - if (node1->destination_ipv4->prefix.s_addr - > node2->destination_ipv4->prefix.s_addr) { - return 1; // if it belongs under node2 - } else { - return 0; // same value... ERROR...in - // case of adding same prefix - // again - } - } - } else { + if (node1->destination->u.prefix4.s_addr + < node2->destination->u.prefix4.s_addr) + return -1; + if (node1->destination->u.prefix4.s_addr + > node2->destination->u.prefix4.s_addr) + return 1; + else + return 0; + } else return 1; - } - } else { // TODO check if the prefix dont exists - return 1; // add to end - } + } else + return 1; } /* @@ -125,8 +118,7 @@ struct eigrp_prefix_entry *eigrp_prefix_entry_new() new->rij = list_new(); new->entries->cmp = (int (*)(void *, void *))eigrp_neighbor_entry_cmp; new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC; - new->destination_ipv4 = NULL; - new->destination_ipv6 = NULL; + new->destination = NULL; return new; } @@ -137,9 +129,8 @@ struct eigrp_prefix_entry *eigrp_prefix_entry_new() static int eigrp_neighbor_entry_cmp(struct eigrp_neighbor_entry *entry1, struct eigrp_neighbor_entry *entry2) { - if (entry1->distance - < entry2->distance) // parameter used in list_add_sort () - return -1; // actually set to sort by distance + if (entry1->distance < entry2->distance) + return -1; if (entry1->distance > entry2->distance) return 1; @@ -205,7 +196,7 @@ void eigrp_neighbor_entry_add(struct eigrp_prefix_entry *node, listnode_add_sort(node->entries, entry); entry->prefix = node; - eigrp_zebra_route_add(node->destination_ipv4, l); + eigrp_zebra_route_add(node->destination, l); } list_delete(l); @@ -230,7 +221,7 @@ void eigrp_prefix_entry_delete(struct list *topology, list_free(node->entries); list_free(node->rij); listnode_delete(topology, node); - eigrp_zebra_route_delete(node->destination_ipv4); + eigrp_zebra_route_delete(node->destination); XFREE(MTYPE_EIGRP_PREFIX_ENTRY, node); } } @@ -243,7 +234,7 @@ void eigrp_neighbor_entry_delete(struct eigrp_prefix_entry *node, { if (listnode_lookup(node->entries, entry) != NULL) { listnode_delete(node->entries, entry); - eigrp_zebra_route_delete(node->destination_ipv4); + eigrp_zebra_route_delete(node->destination); XFREE(MTYPE_EIGRP_NEIGHBOR_ENTRY, entry); } } @@ -270,16 +261,12 @@ unsigned int eigrp_topology_table_isempty(struct list *topology) struct eigrp_prefix_entry * eigrp_topology_table_lookup_ipv4(struct list *topology_table, - struct prefix_ipv4 *address) + struct prefix *address) { struct eigrp_prefix_entry *data; struct listnode *node; for (ALL_LIST_ELEMENTS_RO(topology_table, node, data)) { - if ((data->af == AF_INET) - && (data->destination_ipv4->prefix.s_addr - == address->prefix.s_addr) - && (data->destination_ipv4->prefixlen - == address->prefixlen)) + if (prefix_same(data->destination, address)) return data; } @@ -380,37 +367,56 @@ enum metric_change eigrp_topology_update_distance(struct eigrp_fsm_action_messag struct eigrp_prefix_entry *prefix = msg->prefix; struct eigrp_neighbor_entry *entry = msg->entry; enum metric_change change = METRIC_SAME; + u_int32_t new_reported_distance; + assert(entry); - struct TLV_IPv4_External_type *ext_data = NULL; - struct TLV_IPv4_Internal_type *int_data = NULL; - if (msg->data_type == EIGRP_TLV_IPv4_INT) { - u_int32_t new_reported_distance; + switch(msg->data_type) { + case EIGRP_CONNECTED: + if (prefix->nt == EIGRP_TOPOLOGY_TYPE_CONNECTED) + return change; - int_data = msg->data.ipv4_int_type; - if (eigrp_metrics_is_same(int_data->metric, + change = METRIC_DECREASE; + break; + case EIGRP_INT: + if (prefix->nt == EIGRP_TOPOLOGY_TYPE_CONNECTED) { + change = METRIC_INCREASE; + goto distance_done; + } + if (eigrp_metrics_is_same(msg->metrics, entry->reported_metric)) { return change; // No change } new_reported_distance = eigrp_calculate_metrics(eigrp, - int_data->metric); + msg->metrics); - if (entry->reported_distance < new_reported_distance) + if (entry->reported_distance < new_reported_distance) { change = METRIC_INCREASE; - else + goto distance_done; + } else change = METRIC_DECREASE; - entry->reported_metric = int_data->metric; + entry->reported_metric = msg->metrics; entry->reported_distance = new_reported_distance; - eigrp_calculate_metrics(eigrp, int_data->metric); + eigrp_calculate_metrics(eigrp, msg->metrics); entry->distance = eigrp_calculate_total_metrics(eigrp, entry); - } else { - ext_data = msg->data.ipv4_ext_data; - if (eigrp_metrics_is_same(ext_data->metric, - entry->reported_metric)) - return change; + break; + case EIGRP_EXT: + if (prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL) { + if (eigrp_metrics_is_same(msg->metrics, + entry->reported_metric)) + return change; + } else { + change = METRIC_INCREASE; + goto distance_done; + } + break; + default: + zlog_err("%s: Please implement handler", __PRETTY_FUNCTION__); + break; } + distance_done: /* * Move to correct position in list according to new distance */ @@ -464,13 +470,14 @@ void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix) struct eigrp_neighbor_entry *entry; if (successors) { - eigrp_zebra_route_add(prefix->destination_ipv4, successors); + eigrp_zebra_route_add(prefix->destination, + successors); for (ALL_LIST_ELEMENTS_RO(successors, node, entry)) entry->flags |= EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG; list_delete(successors); } else { - eigrp_zebra_route_delete(prefix->destination_ipv4); + eigrp_zebra_route_delete(prefix->destination); for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry)) entry->flags &= ~EIGRP_NEIGHBOR_ENTRY_INTABLE_FLAG; } @@ -485,24 +492,19 @@ void eigrp_topology_neighbor_down(struct eigrp *eigrp, for (ALL_LIST_ELEMENTS(eigrp->topology_table, node1, node11, prefix)) { for (ALL_LIST_ELEMENTS(prefix->entries, node2, node22, entry)) { - if (entry->adv_router == nbr) { - struct eigrp_fsm_action_message *msg; - msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, - sizeof(struct - eigrp_fsm_action_message)); - struct TLV_IPv4_Internal_type *tlv = - eigrp_IPv4_InternalTLV_new(); - tlv->metric.delay = EIGRP_MAX_METRIC; - msg->packet_type = EIGRP_OPC_UPDATE; - msg->eigrp = eigrp; - msg->data_type = EIGRP_TLV_IPv4_INT; - msg->adv_router = nbr; - msg->data.ipv4_int_type = tlv; - msg->entry = entry; - msg->prefix = prefix; - int event = eigrp_get_fsm_event(msg); - eigrp_fsm_event(msg, event); - } + struct eigrp_fsm_action_message msg; + + if (entry->adv_router != nbr) + continue; + + msg.metrics.delay = EIGRP_MAX_METRIC; + msg.packet_type = EIGRP_OPC_UPDATE; + msg.eigrp = eigrp; + msg.data_type = EIGRP_INT; + msg.adv_router = nbr; + msg.entry = entry; + msg.prefix = prefix; + eigrp_fsm_event(&msg); } } diff --git a/eigrpd/eigrp_topology.h b/eigrpd/eigrp_topology.h index 0c9b5c60c6..8bff08b75a 100644 --- a/eigrpd/eigrp_topology.h +++ b/eigrpd/eigrp_topology.h @@ -49,7 +49,7 @@ extern void eigrp_neighbor_entry_delete(struct eigrp_prefix_entry *, extern void eigrp_topology_delete_all(struct list *); extern unsigned int eigrp_topology_table_isempty(struct list *); extern struct eigrp_prefix_entry * -eigrp_topology_table_lookup_ipv4(struct list *, struct prefix_ipv4 *); +eigrp_topology_table_lookup_ipv4(struct list *, struct prefix *); extern struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *); extern struct list * eigrp_topology_get_successor_max(struct eigrp_prefix_entry *pe, diff --git a/eigrpd/eigrp_update.c b/eigrpd/eigrp_update.c index e0169c514b..d6a1134124 100644 --- a/eigrpd/eigrp_update.c +++ b/eigrpd/eigrp_update.c @@ -112,47 +112,31 @@ static void eigrp_update_receive_GR_ask(struct eigrp *eigrp, { struct listnode *node1; struct eigrp_prefix_entry *prefix; - struct TLV_IPv4_Internal_type *tlv_max; + struct eigrp_fsm_action_message fsm_msg; /* iterate over all prefixes which weren't advertised by neighbor */ for (ALL_LIST_ELEMENTS_RO(nbr_prefixes, node1, prefix)) { - zlog_debug("GR receive: Neighbor not advertised %s/%d", - inet_ntoa(prefix->destination_ipv4->prefix), - prefix->destination_ipv4->prefixlen); + char buffer[PREFIX_STRLEN]; + zlog_debug("GR receive: Neighbor not advertised %s", + prefix2str(prefix->destination, + buffer, PREFIX_STRLEN)); - /* create internal IPv4 TLV with infinite delay */ - tlv_max = eigrp_IPv4_InternalTLV_new(); - tlv_max->type = EIGRP_TLV_IPv4_INT; - tlv_max->length = 28U; - tlv_max->metric = prefix->reported_metric; + fsm_msg.metrics = prefix->reported_metric; /* set delay to MAX */ - tlv_max->metric.delay = EIGRP_MAX_METRIC; - tlv_max->destination = prefix->destination_ipv4->prefix; - tlv_max->prefix_length = prefix->destination_ipv4->prefixlen; - - - /* prepare message for FSM */ - struct eigrp_fsm_action_message *fsm_msg; - fsm_msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, - sizeof(struct eigrp_fsm_action_message)); + fsm_msg.metrics.delay = EIGRP_MAX_METRIC; struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(prefix->entries, nbr); - fsm_msg->packet_type = EIGRP_OPC_UPDATE; - fsm_msg->eigrp = eigrp; - fsm_msg->data_type = EIGRP_TLV_IPv4_INT; - fsm_msg->adv_router = nbr; - fsm_msg->data.ipv4_int_type = tlv_max; - fsm_msg->entry = entry; - fsm_msg->prefix = prefix; + fsm_msg.packet_type = EIGRP_OPC_UPDATE; + fsm_msg.eigrp = eigrp; + fsm_msg.data_type = EIGRP_INT; + fsm_msg.adv_router = nbr; + fsm_msg.entry = entry; + fsm_msg.prefix = prefix; /* send message to FSM */ - int event = eigrp_get_fsm_event(fsm_msg); - eigrp_fsm_event(fsm_msg, event); - - /* free memory used by TLV */ - eigrp_IPv4_InternalTLV_free(tlv_max); + eigrp_fsm_event(&fsm_msg); } } @@ -169,9 +153,11 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, struct eigrp_neighbor_entry *ne; u_int32_t flags; u_int16_t type; + u_int16_t length; u_char same; struct access_list *alist; struct prefix_list *plist; + struct prefix dest_addr; struct eigrp *e; u_char graceful_restart; u_char graceful_restart_final; @@ -287,16 +273,15 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, /*If there is topology information*/ while (s->endp > s->getp) { type = stream_getw(s); - if (type == EIGRP_TLV_IPv4_INT) { - struct prefix_ipv4 dest_addr; - + switch (type) { + case EIGRP_TLV_IPv4_INT: stream_set_getp(s, s->getp - sizeof(u_int16_t)); tlv = eigrp_read_ipv4_tlv(s); /*searching if destination exists */ dest_addr.family = AF_INET; - dest_addr.prefix = tlv->destination; + dest_addr.u.prefix4 = tlv->destination; dest_addr.prefixlen = tlv->prefix_length; struct eigrp_prefix_entry *dest = eigrp_topology_table_lookup_ipv4( @@ -310,31 +295,26 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, remove_received_prefix_gr(nbr_prefixes, dest); - struct eigrp_fsm_action_message *msg; - msg = XCALLOC(MTYPE_EIGRP_FSM_MSG, - sizeof(struct - eigrp_fsm_action_message)); + struct eigrp_fsm_action_message msg; struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(dest->entries, nbr); - msg->packet_type = EIGRP_OPC_UPDATE; - msg->eigrp = eigrp; - msg->data_type = EIGRP_TLV_IPv4_INT; - msg->adv_router = nbr; - msg->data.ipv4_int_type = tlv; - msg->entry = entry; - msg->prefix = dest; - int event = eigrp_get_fsm_event(msg); - eigrp_fsm_event(msg, event); + msg.packet_type = EIGRP_OPC_UPDATE; + msg.eigrp = eigrp; + msg.data_type = EIGRP_INT; + msg.adv_router = nbr; + msg.metrics = tlv->metric; + msg.entry = entry; + msg.prefix = dest; + eigrp_fsm_event(&msg); } else { /*Here comes topology information save*/ pe = eigrp_prefix_entry_new(); pe->serno = eigrp->serno; - pe->destination_ipv4 = prefix_ipv4_new(); - prefix_copy( - (struct prefix *)pe->destination_ipv4, - (struct prefix *)&dest_addr); + pe->destination = (struct prefix *)prefix_ipv4_new(); + prefix_copy(pe->destination, + &dest_addr); pe->af = AF_INET; pe->state = EIGRP_FSM_STATE_PASSIVE; pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE; @@ -358,9 +338,8 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, /* Check if access-list fits */ if (alist - && access_list_apply( - alist, - (struct prefix *)&dest_addr) + && access_list_apply(alist, + &dest_addr) == FILTER_DENY) { /* If yes, set reported metric to Max */ ne->reported_metric.delay = @@ -375,9 +354,8 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, /* Check if prefix-list fits */ if (plist - && prefix_list_apply( - plist, - (struct prefix *)&dest_addr) + && prefix_list_apply(plist, + &dest_addr) == PREFIX_DENY) { /* If yes, set reported metric to Max */ ne->reported_metric.delay = @@ -389,9 +367,8 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, /* Check if access-list fits */ if (alist - && access_list_apply( - alist, - (struct prefix *)&dest_addr) + && access_list_apply(alist, + &dest_addr) == FILTER_DENY) { /* If yes, set reported metric to Max */ ne->reported_metric.delay = @@ -402,9 +379,8 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, /* Check if prefix-list fits */ if (plist - && prefix_list_apply( - plist, - (struct prefix *)&dest_addr) + && prefix_list_apply(plist, + &dest_addr) == PREFIX_DENY) { /* If yes, set reported metric to Max */ ne->reported_metric.delay = @@ -436,6 +412,18 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph, pe); } eigrp_IPv4_InternalTLV_free(tlv); + break; + + case EIGRP_TLV_IPv4_EXT: + /* DVS: processing of external routes needs packet and fsm work. + * for now, lets just not creash the box + */ + default: + length = stream_getw(s); + // -2 for type, -2 for len + for (length-=4; length ; length--) { + (void)stream_getc(s); + } } } @@ -463,7 +451,7 @@ void eigrp_update_send_init(struct eigrp_neighbor *nbr) struct eigrp_packet *ep; u_int16_t length = EIGRP_HEADER_LEN; - ep = eigrp_packet_new(nbr->ei->ifp->mtu); + ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr); /* Prepare EIGRP INIT UPDATE header */ if (IS_DEBUG_EIGRP_PACKET(0, RECV)) @@ -471,9 +459,10 @@ void eigrp_update_send_init(struct eigrp_neighbor *nbr) nbr->ei->eigrp->sequence_number, nbr->recv_sequence_number); - eigrp_packet_header_init( - EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_INIT_FLAG, - nbr->ei->eigrp->sequence_number, nbr->recv_sequence_number); + eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp, + ep->s, EIGRP_INIT_FLAG, + nbr->ei->eigrp->sequence_number, + nbr->recv_sequence_number); // encode Authentication TLV, if needed if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) @@ -497,7 +486,7 @@ void eigrp_update_send_init(struct eigrp_neighbor *nbr) ep->length, ep->sequence_number, inet_ntoa(ep->dst)); /*Put packet to retransmission queue*/ - eigrp_fifo_push_head(nbr->retrans_queue, ep); + eigrp_fifo_push(nbr->retrans_queue, ep); if (nbr->retrans_queue->count == 1) { eigrp_send_packet_reliably(nbr); @@ -528,7 +517,42 @@ static void eigrp_update_place_on_nbr_queue(struct eigrp_neighbor *nbr, ep->length, ep->sequence_number, inet_ntoa(ep->dst)); /*Put packet to retransmission queue*/ - eigrp_fifo_push_head(nbr->retrans_queue, ep); + eigrp_fifo_push(nbr->retrans_queue, ep); + + if (nbr->retrans_queue->count == 1) + eigrp_send_packet_reliably(nbr); +} + +static void eigrp_update_send_to_all_nbrs(struct eigrp_interface *ei, + struct eigrp_packet *ep) +{ + struct listnode *node, *nnode; + struct eigrp_neighbor *nbr; + bool packet_sent = false; + + for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr)) { + struct eigrp_packet *ep_dup; + + if (nbr->state != EIGRP_NEIGHBOR_UP) + continue; + + if (packet_sent) + ep_dup = eigrp_packet_duplicate(ep, NULL); + else + ep_dup = ep; + + ep_dup->nbr = nbr; + packet_sent = true; + /*Put packet to retransmission queue*/ + eigrp_fifo_push(nbr->retrans_queue, ep_dup); + + if (nbr->retrans_queue->count == 1) { + eigrp_send_packet_reliably(nbr); + } + } + + if (!packet_sent) + eigrp_packet_free(ep); } void eigrp_update_send_EOT(struct eigrp_neighbor *nbr) @@ -543,15 +567,15 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr) struct access_list *alist_i; struct prefix_list *plist_i; struct eigrp *e; - struct prefix_ipv4 *dest_addr; + struct prefix *dest_addr; u_int32_t seq_no = nbr->ei->eigrp->sequence_number; - ep = eigrp_packet_new(nbr->ei->ifp->mtu); + ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr); /* Prepare EIGRP EOT UPDATE header */ - eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG, - seq_no, - nbr->recv_sequence_number); + eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp, + ep->s, EIGRP_EOT_FLAG, + seq_no, nbr->recv_sequence_number); // encode Authentication TLV, if needed if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && @@ -561,18 +585,17 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr) for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe)) { for (ALL_LIST_ELEMENTS(pe->entries, node2, nnode2, te)) { - if ((te->ei == nbr->ei) - && (te->prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE)) + if (eigrp_nbr_split_horizon_check(te, nbr->ei)) continue; if ((length + 0x001D) > (u_int16_t)nbr->ei->ifp->mtu) { eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length); - eigrp_send_packet_reliably(nbr); seq_no++; length = EIGRP_HEADER_LEN; - ep = eigrp_packet_new(nbr->ei->ifp->mtu); - eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG, + ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr); + eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp, + ep->s, EIGRP_EOT_FLAG, seq_no, nbr->recv_sequence_number); if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) && @@ -582,7 +605,7 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr) } } /* Get destination address from prefix */ - dest_addr = pe->destination_ipv4; + dest_addr = pe->destination; /* * Filtering @@ -599,13 +622,13 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr) /* Check if any list fits */ if ((alist && access_list_apply (alist, - (struct prefix *) dest_addr) == FILTER_DENY)|| + dest_addr) == FILTER_DENY)|| (plist && prefix_list_apply (plist, - (struct prefix *) dest_addr) == PREFIX_DENY)|| + dest_addr) == PREFIX_DENY)|| (alist_i && access_list_apply (alist_i, - (struct prefix *) dest_addr) == FILTER_DENY)|| + dest_addr) == FILTER_DENY)|| (plist_i && prefix_list_apply (plist_i, - (struct prefix *) dest_addr) == PREFIX_DENY)) { + dest_addr) == PREFIX_DENY)) { //pe->reported_metric.delay = EIGRP_MAX_METRIC; continue; } else { @@ -615,14 +638,13 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr) } eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length); - eigrp_send_packet_reliably(nbr); + nbr->ei->eigrp->sequence_number = seq_no++; } void eigrp_update_send(struct eigrp_interface *ei) { struct eigrp_packet *ep; struct listnode *node, *nnode; - struct eigrp_neighbor *nbr; struct eigrp_prefix_entry *pe; u_char has_tlv; struct access_list *alist; @@ -630,16 +652,19 @@ void eigrp_update_send(struct eigrp_interface *ei) struct access_list *alist_i; struct prefix_list *plist_i; struct eigrp *e; - struct prefix_ipv4 *dest_addr; - bool packet_sent = false; + struct prefix *dest_addr; + u_int32_t seq_no = ei->eigrp->sequence_number; + + if (ei->nbrs->count == 0) + return; u_int16_t length = EIGRP_HEADER_LEN; - ep = eigrp_packet_new(ei->ifp->mtu); + ep = eigrp_packet_new(ei->ifp->mtu, NULL); /* Prepare EIGRP INIT UPDATE header */ - eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei, ep->s, 0, - ei->eigrp->sequence_number, 0); + eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei->eigrp, + ep->s, 0, seq_no, 0); // encode Authentication TLV, if needed if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) @@ -650,57 +675,77 @@ void eigrp_update_send(struct eigrp_interface *ei) has_tlv = 0; for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node, nnode, pe)) { - if (pe->req_action & EIGRP_FSM_NEED_UPDATE) { - /* Get destination address from prefix */ - dest_addr = pe->destination_ipv4; + struct eigrp_neighbor_entry *ne; - /* - * Filtering - */ - // TODO: Work in progress - /* get list from eigrp process */ - e = eigrp_lookup(); - /* Get access-lists and prefix-lists from process and - * interface */ - alist = e->list[EIGRP_FILTER_OUT]; - plist = e->prefix[EIGRP_FILTER_OUT]; - alist_i = ei->list[EIGRP_FILTER_OUT]; - plist_i = ei->prefix[EIGRP_FILTER_OUT]; + if (!(pe->req_action & EIGRP_FSM_NEED_UPDATE)) + continue; - /* Check if any list fits */ - if ((alist - && access_list_apply(alist, - (struct prefix *)dest_addr) - == FILTER_DENY) - || (plist - && prefix_list_apply(plist, - (struct prefix *)dest_addr) - == PREFIX_DENY) - || (alist_i - && access_list_apply(alist_i, - (struct prefix *)dest_addr) - == FILTER_DENY) - || (plist_i - && prefix_list_apply(plist_i, - (struct prefix *)dest_addr) - == PREFIX_DENY)) { - zlog_info("PROC OUT: Skipping"); - // pe->reported_metric.delay = EIGRP_MAX_METRIC; - zlog_info("PROC OUT Prefix: %s", - inet_ntoa(dest_addr->prefix)); - continue; - } else { - zlog_info("PROC OUT: NENastavujem metriku "); - length += eigrp_add_internalTLV_to_stream(ep->s, - pe); - has_tlv = 1; + ne = listnode_head(pe->entries); + if (eigrp_nbr_split_horizon_check(ne, ei)) + continue; + + if ((length + 0x001D) > (u_int16_t)ei->ifp->mtu) { + if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) + && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) { + eigrp_make_md5_digest(ei, ep->s, EIGRP_AUTH_UPDATE_FLAG); } - /* - * End of filtering - */ - /* NULL the pointer */ - dest_addr = NULL; + eigrp_packet_checksum(ei, ep->s, length); + ep->length = length; + + ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS); + + ep->sequence_number = seq_no; + seq_no++; + eigrp_update_send_to_all_nbrs(ei, ep); + + length = EIGRP_HEADER_LEN; + ep = eigrp_packet_new(ei->ifp->mtu, NULL); + eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei->eigrp, + ep->s, 0, seq_no, 0); + if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) + && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) { + length += eigrp_add_authTLV_MD5_to_stream(ep->s, ei); + } + has_tlv = 0; + } + /* Get destination address from prefix */ + dest_addr = pe->destination; + + /* + * Filtering + */ + e = eigrp_lookup(); + /* Get access-lists and prefix-lists from process and + * interface */ + alist = e->list[EIGRP_FILTER_OUT]; + plist = e->prefix[EIGRP_FILTER_OUT]; + alist_i = ei->list[EIGRP_FILTER_OUT]; + plist_i = ei->prefix[EIGRP_FILTER_OUT]; + + /* Check if any list fits */ + if ((alist + && access_list_apply(alist, + dest_addr) + == FILTER_DENY) + || (plist + && prefix_list_apply(plist, + dest_addr) + == PREFIX_DENY) + || (alist_i + && access_list_apply(alist_i, + dest_addr) + == FILTER_DENY) + || (plist_i + && prefix_list_apply(plist_i, + dest_addr) + == PREFIX_DENY)) { + // pe->reported_metric.delay = EIGRP_MAX_METRIC; + continue; + } else { + length += eigrp_add_internalTLV_to_stream(ep->s, + pe); + has_tlv = 1; } } @@ -727,20 +772,8 @@ void eigrp_update_send(struct eigrp_interface *ei) zlog_debug("Enqueuing Update length[%u] Seq [%u]", length, ep->sequence_number); - for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr)) { - if (nbr->state == EIGRP_NEIGHBOR_UP) { - packet_sent = true; - /*Put packet to retransmission queue*/ - eigrp_fifo_push_head(nbr->retrans_queue, ep); - - if (nbr->retrans_queue->count == 1) { - eigrp_send_packet_reliably(nbr); - } - } - } - - if (!packet_sent) - eigrp_packet_free(ep); + eigrp_update_send_to_all_nbrs(ei, ep); + ei->eigrp->sequence_number = seq_no++; } void eigrp_update_send_all(struct eigrp *eigrp, @@ -762,8 +795,6 @@ void eigrp_update_send_all(struct eigrp *eigrp, pe->req_action &= ~EIGRP_FSM_NEED_UPDATE; listnode_delete(eigrp->topology_changes_internalIPV4, pe); - zlog_debug("UPDATE COUNT: %d", - eigrp->topology_changes_internalIPV4->count); } } } @@ -789,14 +820,13 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) u_int16_t length = EIGRP_HEADER_LEN; struct listnode *node, *nnode; struct eigrp_prefix_entry *pe; - struct prefix_ipv4 *dest_addr; + struct prefix *dest_addr; struct eigrp *e; struct access_list *alist, *alist_i; struct prefix_list *plist, *plist_i; struct list *prefixes; u_int32_t flags; unsigned int send_prefixes; - struct TLV_IPv4_Internal_type *tlv_max; /* get prefixes to send to neighbor */ prefixes = nbr->nbr_gr_prefixes_send; @@ -835,10 +865,10 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) } } - ep = eigrp_packet_new(nbr->ei->ifp->mtu); + ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr); /* Prepare EIGRP Graceful restart UPDATE header */ - eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, flags, + eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp, ep->s, flags, nbr->ei->eigrp->sequence_number, nbr->recv_sequence_number); @@ -853,7 +883,7 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) /* * Filtering */ - dest_addr = pe->destination_ipv4; + dest_addr = pe->destination; /* get list from eigrp process */ e = eigrp_lookup(); /* Get access-lists and prefix-lists from process and interface @@ -865,22 +895,20 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) /* Check if any list fits */ if ((alist - && access_list_apply(alist, (struct prefix *)dest_addr) + && access_list_apply(alist, dest_addr) == FILTER_DENY) || (plist - && prefix_list_apply(plist, (struct prefix *)dest_addr) + && prefix_list_apply(plist, dest_addr) == PREFIX_DENY) || (alist_i - && access_list_apply(alist_i, - (struct prefix *)dest_addr) + && access_list_apply(alist_i, dest_addr) == FILTER_DENY) || (plist_i - && prefix_list_apply(plist_i, - (struct prefix *)dest_addr) + && prefix_list_apply(plist_i, dest_addr) == PREFIX_DENY)) { /* do not send filtered route */ zlog_info("Filtered prefix %s won't be sent out.", - inet_ntoa(dest_addr->prefix)); + inet_ntoa(dest_addr->u.prefix4)); } else { /* sending route which wasn't filtered */ length += eigrp_add_internalTLV_to_stream(ep->s, pe); @@ -894,56 +922,39 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) /* Check if any list fits */ if ((alist - && access_list_apply(alist, (struct prefix *)dest_addr) + && access_list_apply(alist, dest_addr) == FILTER_DENY) || (plist - && prefix_list_apply(plist, (struct prefix *)dest_addr) + && prefix_list_apply(plist, dest_addr) == PREFIX_DENY) || (alist_i - && access_list_apply(alist_i, - (struct prefix *)dest_addr) + && access_list_apply(alist_i, dest_addr) == FILTER_DENY) || (plist_i - && prefix_list_apply(plist_i, - (struct prefix *)dest_addr) + && prefix_list_apply(plist_i, dest_addr) == PREFIX_DENY)) { /* do not send filtered route */ zlog_info("Filtered prefix %s will be removed.", - inet_ntoa(dest_addr->prefix)); - - tlv_max = eigrp_IPv4_InternalTLV_new(); - tlv_max->type = EIGRP_TLV_IPv4_INT; - tlv_max->length = 28U; - tlv_max->metric = pe->reported_metric; - /* set delay to MAX */ - tlv_max->metric.delay = EIGRP_MAX_METRIC; - tlv_max->destination = pe->destination_ipv4->prefix; - tlv_max->prefix_length = - pe->destination_ipv4->prefixlen; + inet_ntoa(dest_addr->u.prefix4)); /* prepare message for FSM */ - struct eigrp_fsm_action_message *fsm_msg; - fsm_msg = XCALLOC( - MTYPE_EIGRP_FSM_MSG, - sizeof(struct eigrp_fsm_action_message)); + struct eigrp_fsm_action_message fsm_msg; struct eigrp_neighbor_entry *entry = eigrp_prefix_entry_lookup(pe->entries, nbr); - fsm_msg->packet_type = EIGRP_OPC_UPDATE; - fsm_msg->eigrp = e; - fsm_msg->data_type = EIGRP_TLV_IPv4_INT; - fsm_msg->adv_router = nbr; - fsm_msg->data.ipv4_int_type = tlv_max; - fsm_msg->entry = entry; - fsm_msg->prefix = pe; + fsm_msg.packet_type = EIGRP_OPC_UPDATE; + fsm_msg.eigrp = e; + fsm_msg.data_type = EIGRP_INT; + fsm_msg.adv_router = nbr; + fsm_msg.metrics = pe->reported_metric; + /* Set delay to MAX */ + fsm_msg.metrics.delay = EIGRP_MAX_METRIC; + fsm_msg.entry = entry; + fsm_msg.prefix = pe; /* send message to FSM */ - int event = eigrp_get_fsm_event(fsm_msg); - eigrp_fsm_event(fsm_msg, event); - - /* free memory used by TLV */ - eigrp_IPv4_InternalTLV_free(tlv_max); + eigrp_fsm_event(&fsm_msg); } /* * End of filtering @@ -980,7 +991,7 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr) ep->length, ep->sequence_number, inet_ntoa(ep->dst)); /*Put packet to retransmission queue*/ - eigrp_fifo_push_head(nbr->retrans_queue, ep); + eigrp_fifo_push(nbr->retrans_queue, ep); if (nbr->retrans_queue->count == 1) { eigrp_send_packet_reliably(nbr); diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c index 465007478d..4a8842f30e 100644 --- a/eigrpd/eigrp_vty.c +++ b/eigrpd/eigrp_vty.c @@ -391,10 +391,10 @@ DEFUN (eigrp_network, "EIGRP network prefix\n") { VTY_DECLVAR_CONTEXT(eigrp, eigrp); - struct prefix_ipv4 p; + struct prefix p; int ret; - str2prefix_ipv4(argv[1]->arg, &p); + str2prefix(argv[1]->arg, &p); ret = eigrp_network_set(eigrp, &p); @@ -414,10 +414,10 @@ DEFUN (no_eigrp_network, "EIGRP network prefix\n") { VTY_DECLVAR_CONTEXT(eigrp, eigrp); - struct prefix_ipv4 p; + struct prefix p; int ret; - str2prefix_ipv4(argv[2]->arg, &p); + str2prefix(argv[2]->arg, &p); ret = eigrp_network_unset(eigrp, &p); diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index 1ee1237f75..47871dfd3e 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -66,8 +66,8 @@ static int eigrp_interface_state_down(int, struct zclient *, zebra_size_t, vrf_id_t vrf_id); static struct interface *zebra_interface_if_lookup(struct stream *); -static int eigrp_zebra_read_ipv4(int, struct zclient *, zebra_size_t, - vrf_id_t vrf_id); +static int eigrp_zebra_read_route(int, struct zclient *, zebra_size_t, + vrf_id_t vrf_id); /* Zebra structure to hold current status. */ struct zclient *zclient = NULL; @@ -112,59 +112,31 @@ void eigrp_zebra_init(void) zclient->interface_down = eigrp_interface_state_down; zclient->interface_address_add = eigrp_interface_address_add; zclient->interface_address_delete = eigrp_interface_address_delete; - zclient->redistribute_route_ipv4_add = eigrp_zebra_read_ipv4; - zclient->redistribute_route_ipv4_del = eigrp_zebra_read_ipv4; + zclient->redistribute_route_add = eigrp_zebra_read_route; + zclient->redistribute_route_del = eigrp_zebra_read_route; } /* Zebra route add and delete treatment. */ -static int eigrp_zebra_read_ipv4(int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf_id) +static int eigrp_zebra_read_route(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) { - struct stream *s; - struct zapi_ipv4 api; - struct prefix_ipv4 p; + struct zapi_route api; struct eigrp *eigrp; - s = zclient->ibuf; + if (zapi_route_decode(zclient->ibuf, &api) < 0) + return -1; - /* Type, flags, message. */ - api.type = stream_getc(s); - api.instance = stream_getw(s); - api.flags = stream_getc(s); - api.message = stream_getc(s); - - /* IPv4 prefix. */ - memset(&p, 0, sizeof(struct prefix_ipv4)); - p.family = AF_INET; - p.prefixlen = stream_getc(s); - stream_get(&p.prefix, s, PSIZE(p.prefixlen)); - - if (IPV4_NET127(ntohl(p.prefix.s_addr))) + if (IPV4_NET127(ntohl(api.prefix.u.prefix4.s_addr))) return 0; - /* Nexthop, ifindex, distance, metric. */ - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { - api.nexthop_num = stream_getc(s); - stream_get_ipv4(s); - } - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) { - api.ifindex_num = stream_getc(s); - /* XXX assert(api.ifindex_num == 1); */ - stream_getl(s); /* ifindex, unused */ - } - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc(s); - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl(s); - eigrp = eigrp_lookup(); if (eigrp == NULL) return 0; - if (command == ZEBRA_IPV4_ROUTE_ADD) { + if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) { - } else /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */ + } else /* if (command == ZEBRA_REDISTRIBUTE_ROUTE_DEL) */ { } @@ -389,90 +361,67 @@ static struct interface *zebra_interface_if_lookup(struct stream *s) ifname_tmp, strnlen(ifname_tmp, INTERFACE_NAMSIZ), VRF_DEFAULT); } -void eigrp_zebra_route_add(struct prefix_ipv4 *p, struct list *successors) +void eigrp_zebra_route_add(struct prefix *p, struct list *successors) { + struct zapi_route api; + struct zapi_nexthop *api_nh; struct eigrp_neighbor_entry *te; struct listnode *node; - u_char message; - u_char flags; - int psize; - struct stream *s; + int count = 0; - if (zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP]) { - message = 0; - flags = 0; + if (!zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP]) + return; - /* EIGRP pass nexthop and metric */ - SET_FLAG(message, ZAPI_MESSAGE_NEXTHOP); + memset(&api, 0, sizeof(api)); + api.vrf_id = VRF_DEFAULT; + api.type = ZEBRA_ROUTE_EIGRP; + api.safi = SAFI_UNICAST; + memcpy(&api.prefix, p, sizeof(*p)); - /* Make packet. */ - s = zclient->obuf; - stream_reset(s); + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = successors->count; - /* Put command, type, flags, message. */ - zclient_create_header(s, ZEBRA_IPV4_ROUTE_ADD, VRF_DEFAULT); - stream_putc(s, ZEBRA_ROUTE_EIGRP); - stream_putw(s, 0); - stream_putl(s, flags); - stream_putc(s, message); - stream_putw(s, SAFI_UNICAST); + /* Nexthop, ifindex, distance and metric information. */ + for (ALL_LIST_ELEMENTS_RO(successors, node, te)) { + api_nh = &api.nexthops[count]; + if (te->adv_router->src.s_addr) { + api_nh->gate.ipv4 = te->adv_router->src; + api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; + } else + api_nh->type = NEXTHOP_TYPE_IFINDEX; + api_nh->ifindex = te->ei->ifp->ifindex; - /* Put prefix information. */ - psize = PSIZE(p->prefixlen); - stream_putc(s, p->prefixlen); - stream_write(s, (u_char *)&p->prefix, psize); - - /* Nexthop count. */ - stream_putc(s, successors->count); - - /* Nexthop, ifindex, distance and metric information. */ - for (ALL_LIST_ELEMENTS_RO(successors, node, te)) { - if (te->adv_router->src.s_addr) { - stream_putc(s, NEXTHOP_TYPE_IPV4_IFINDEX); - stream_put_in_addr(s, &te->adv_router->src); - } else - stream_putc(s, NEXTHOP_TYPE_IFINDEX); - stream_putl(s, te->ei->ifp->ifindex); - } - - if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) { - char buf[2][INET_ADDRSTRLEN]; - zlog_debug("Zebra: Route add %s/%d nexthop %s", - inet_ntop(AF_INET, &p->prefix, buf[0], - sizeof(buf[0])), - p->prefixlen, - inet_ntop(AF_INET, 0 /*&p->nexthop*/, buf[1], - sizeof(buf[1]))); - } - - stream_putw_at(s, 0, stream_get_endp(s)); - - zclient_send_message(zclient); + count++; } + + if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) { + char buf[2][PREFIX_STRLEN]; + zlog_debug("Zebra: Route add %s nexthop %s", + prefix2str(p, buf[0], PREFIX_STRLEN), + inet_ntop(AF_INET, 0, buf[1], PREFIX_STRLEN)); + } + + zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); } -void eigrp_zebra_route_delete(struct prefix_ipv4 *p) +void eigrp_zebra_route_delete(struct prefix *p) { - struct zapi_ipv4 api; + struct zapi_route api; - if (zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP]) { - api.vrf_id = VRF_DEFAULT; - api.type = ZEBRA_ROUTE_EIGRP; - api.instance = 0; - api.flags = 0; - api.message = 0; - api.safi = SAFI_UNICAST; - zapi_ipv4_route(ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api); + if (!zclient->redist[AFI_IP][ZEBRA_ROUTE_EIGRP]) + return; - if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) { - char buf[2][INET_ADDRSTRLEN]; - zlog_debug("Zebra: Route del %s/%d nexthop %s", - inet_ntop(AF_INET, &p->prefix, buf[0], - sizeof(buf[0])), - p->prefixlen, - inet_ntop(AF_INET, 0 /*&p->nexthop*/, buf[1], - sizeof(buf[1]))); - } + memset(&api, 0, sizeof(api)); + api.vrf_id = VRF_DEFAULT; + api.type = ZEBRA_ROUTE_EIGRP; + api.safi = SAFI_UNICAST; + memcpy(&api.prefix, p, sizeof(*p)); + zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); + + if (IS_DEBUG_EIGRP(zebra, ZEBRA_REDISTRIBUTE)) { + char buf[PREFIX_STRLEN]; + zlog_debug("Zebra: Route del %s", + prefix2str(p, buf, PREFIX_STRLEN)); } return; diff --git a/eigrpd/eigrp_zebra.h b/eigrpd/eigrp_zebra.h index 3281c47018..1c418dddef 100644 --- a/eigrpd/eigrp_zebra.h +++ b/eigrpd/eigrp_zebra.h @@ -33,8 +33,8 @@ extern void eigrp_zebra_init(void); -extern void eigrp_zebra_route_add(struct prefix_ipv4 *, struct list *); -extern void eigrp_zebra_route_delete(struct prefix_ipv4 *); +extern void eigrp_zebra_route_add(struct prefix *, struct list *); +extern void eigrp_zebra_route_delete(struct prefix *); extern int eigrp_redistribute_set(struct eigrp *, int, struct eigrp_metrics); extern int eigrp_redistribute_unset(struct eigrp *, int); extern int eigrp_is_type_redistributed(int); diff --git a/git-reindent-branch.py b/git-reindent-branch.py index b0dd8db6de..c207f5946f 100644 --- a/git-reindent-branch.py +++ b/git-reindent-branch.py @@ -11,14 +11,28 @@ def run(cmd): proc.wait() return rv +clangfmt = run(['git', 'show', 'master:.clang-format']) + argp = argparse.ArgumentParser(description = 'git whitespace-fixing tool') argp.add_argument('branch', metavar='BRANCH', type = str, nargs = '?', default = 'HEAD') args = argp.parse_args() branch = args.branch commit = run(['git', 'rev-list', '-n', '1', branch, '--']).strip() -beforeid = run(['git', 'rev-list', '-n', '1', 'reindent-master-before', '--']).strip() -afterid = run(['git', 'rev-list', '-n', '1', 'reindent-master-after', '--']).strip() + +# frr-3.1-dev = first commit that is on master but not on stable/3.0 +masterid = run(['git', 'rev-list', '-n', '1', 'frr-3.1-dev', '--']).strip() +masterbase = run(['git', 'merge-base', commit, masterid]).strip() + +if masterbase == masterid: + refbranch = 'master' +else: + refbranch = '3.0' + +sys.stderr.write('autodetected base: %s (can be 3.0 or master)\n' % refbranch) + +beforeid = run(['git', 'rev-list', '-n', '1', 'reindent-%s-before' % refbranch, '--']).strip() +afterid = run(['git', 'rev-list', '-n', '1', 'reindent-%s-after' % refbranch, '--']).strip() beforebase = run(['git', 'merge-base', commit, beforeid]).strip() afterbase = run(['git', 'merge-base', commit, afterid]).strip() @@ -28,10 +42,10 @@ if afterbase == afterid: sys.exit(1) if beforebase != beforeid: - sys.stderr.write('you need to rebase your branch onto the tag "reindent-master-before"\n') + sys.stderr.write('you need to rebase your branch onto the tag "reindent-%s-before"\n' % refbranch) sys.exit(1) -revs = run(['git', 'rev-list', 'reindent-master-before..%s' % commit]).strip().split('\n') +revs = run(['git', 'rev-list', 'reindent-%s-before..%s' % (refbranch, commit)]).strip().split('\n') revs.reverse() srcdir = os.getcwd() @@ -39,9 +53,12 @@ tmpdir = tempfile.mkdtemp('frrindent') os.chdir(tmpdir) sys.stderr.write('using temporary directory %s; %d revisions\n' % (tmpdir, len(revs))) -run(['git', 'clone', '-s', '-b', 'reindent-master-after', srcdir, 'repo']) +run(['git', 'clone', '-s', '-b', 'reindent-%s-after' % refbranch, srcdir, 'repo']) os.chdir('repo') +with open('.clang-format', 'w') as fd: + fd.write(clangfmt) + prev = beforeid for rev in revs: filestat = run(['git', 'diff', '-z', '--name-status', prev, rev]).rstrip('\0').split('\0') diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c index 98f612f827..2c8b126088 100644 --- a/isisd/isis_bpf.c +++ b/isisd/isis_bpf.c @@ -48,14 +48,15 @@ extern struct zebra_privs_t isisd_privs; struct bpf_insn llcfilter[] = { - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, - ETHER_HDR_LEN), /* check first byte */ + /* check first byte */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETH_ALEN), BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 5), - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 1), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, - 3), /* check second byte */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 2), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1), /* check third byte */ + /* check second byte */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETH_ALEN + 1), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 3), + /* check third byte */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, ETH_ALEN + 2), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1), BPF_STMT(BPF_RET + BPF_K, (u_int)-1), BPF_STMT(BPF_RET + BPF_K, 0)}; u_int readblen = 0; @@ -243,15 +244,14 @@ int isis_recv_pdu_bcast(struct isis_circuit *circuit, u_char *ssnpa) assert(bpf_hdr->bh_caplen == bpf_hdr->bh_datalen); - offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN; + offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETH_ALEN; /* then we lose the BPF, LLC and ethernet headers */ stream_write(circuit->rcv_stream, readbuff + offset, - bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN); + bpf_hdr->bh_caplen - LLC_LEN - ETH_ALEN); stream_set_getp(circuit->rcv_stream, 0); - memcpy(ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETH_ALEN, - ETH_ALEN); + memcpy(ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETH_ALEN, ETH_ALEN); if (ioctl(circuit->fd, BIOCFLUSH, &one) < 0) zlog_warn("Flushing failed: %s", safe_strerror(errno)); @@ -265,7 +265,7 @@ int isis_send_pdu_bcast(struct isis_circuit *circuit, int level) ssize_t written; size_t buflen; - buflen = stream_get_endp(circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN; + buflen = stream_get_endp(circuit->snd_stream) + LLC_LEN + ETH_ALEN; if (buflen > sizeof(sock_buff)) { zlog_warn( "isis_send_pdu_bcast: sock_buff size %zu is less than " @@ -291,12 +291,12 @@ int isis_send_pdu_bcast(struct isis_circuit *circuit, int level) /* * Then the LLC */ - sock_buff[ETHER_HDR_LEN] = ISO_SAP; - sock_buff[ETHER_HDR_LEN + 1] = ISO_SAP; - sock_buff[ETHER_HDR_LEN + 2] = 0x03; + sock_buff[ETH_ALEN] = ISO_SAP; + sock_buff[ETH_ALEN + 1] = ISO_SAP; + sock_buff[ETH_ALEN + 2] = 0x03; /* then we copy the data */ - memcpy(sock_buff + (LLC_LEN + ETHER_HDR_LEN), circuit->snd_stream->data, + memcpy(sock_buff + (LLC_LEN + ETH_ALEN), circuit->snd_stream->data, stream_get_endp(circuit->snd_stream)); /* now we can send this */ diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 9622dcdbc4..a1aa87e396 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1336,8 +1336,8 @@ int isis_if_delete_hook(struct interface *ifp) void isis_circuit_init() { /* Initialize Zebra interface data structure */ - if_add_hook(IF_NEW_HOOK, isis_if_new_hook); - if_add_hook(IF_DELETE_HOOK, isis_if_delete_hook); + hook_register_prio(if_add, 0, isis_if_new_hook); + hook_register_prio(if_del, 0, isis_if_delete_hook); /* Install interface node */ install_node(&interface_node, isis_interface_config_write); diff --git a/isisd/isis_vty.c b/isisd/isis_vty.c index 2a19465a01..17d8ad3c0b 100644 --- a/isisd/isis_vty.c +++ b/isisd/isis_vty.c @@ -181,7 +181,7 @@ DEFUN (no_isis_passive, if (if_is_loopback(circuit->interface)) { vty_out(vty, "Can't set no passive for loopback interface\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } isis_circuit_passive_set(circuit, 0); @@ -206,7 +206,7 @@ DEFUN (isis_circuit_type, is_type = string2circuit_t(argv[idx_level]->arg); if (!is_type) { vty_out(vty, "Unknown circuit-type \n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } if (circuit->state == C_STATE_UP @@ -214,7 +214,7 @@ DEFUN (isis_circuit_type, && circuit->area->is_type != is_type) { vty_out(vty, "Invalid circuit level for area %s.\n", circuit->area->area_tag); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } isis_circuit_is_type_set(circuit, is_type); @@ -262,7 +262,7 @@ DEFUN (isis_network, if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_P2P)) { vty_out(vty, "isis network point-to-point is valid only on broadcast interfaces\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } return CMD_SUCCESS; @@ -283,7 +283,7 @@ DEFUN (no_isis_network, if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_BROADCAST)) { vty_out(vty, "isis network point-to-point is valid only on broadcast interfaces\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } return CMD_SUCCESS; @@ -313,7 +313,7 @@ DEFUN (isis_passwd, argv[idx_word]->arg); if (rv) { vty_out(vty, "Too long circuit password (>254)\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } return CMD_SUCCESS; @@ -355,7 +355,7 @@ DEFUN (isis_priority, prio = atoi(argv[idx_number]->arg); if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) { vty_out(vty, "Invalid priority %d - should be <0-127>\n", prio); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->priority[0] = prio; @@ -400,7 +400,7 @@ DEFUN (isis_priority_l1, prio = atoi(argv[idx_number]->arg); if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) { vty_out(vty, "Invalid priority %d - should be <0-127>\n", prio); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->priority[0] = prio; @@ -444,7 +444,7 @@ DEFUN (isis_priority_l2, prio = atoi(argv[idx_number]->arg); if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) { vty_out(vty, "Invalid priority %d - should be <0-127>\n", prio); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->priority[1] = prio; @@ -494,7 +494,7 @@ DEFUN (isis_metric, "Invalid metric %d - should be <0-63> " "when narrow metric type enabled\n", met); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } /* RFC4444 */ @@ -504,7 +504,7 @@ DEFUN (isis_metric, "Invalid metric %d - should be <0-16777215> " "when wide metric type enabled\n", met); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } isis_circuit_metric_set(circuit, IS_LEVEL_1, met); @@ -554,7 +554,7 @@ DEFUN (isis_metric_l1, "Invalid metric %d - should be <0-63> " "when narrow metric type enabled\n", met); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } /* RFC4444 */ @@ -564,7 +564,7 @@ DEFUN (isis_metric_l1, "Invalid metric %d - should be <0-16777215> " "when wide metric type enabled\n", met); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } isis_circuit_metric_set(circuit, IS_LEVEL_1, met); @@ -613,7 +613,7 @@ DEFUN (isis_metric_l2, "Invalid metric %d - should be <0-63> " "when narrow metric type enabled\n", met); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } /* RFC4444 */ @@ -623,7 +623,7 @@ DEFUN (isis_metric_l2, "Invalid metric %d - should be <0-16777215> " "when wide metric type enabled\n", met); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } isis_circuit_metric_set(circuit, IS_LEVEL_2, met); @@ -667,7 +667,7 @@ DEFUN (isis_hello_interval, if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { vty_out(vty, "Invalid hello-interval %d - should be <1-600>\n", interval); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->hello_interval[0] = (u_int16_t)interval; @@ -714,7 +714,7 @@ DEFUN (isis_hello_interval_l1, if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { vty_out(vty, "Invalid hello-interval %ld - should be <1-600>\n", interval); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->hello_interval[0] = (u_int16_t)interval; @@ -760,7 +760,7 @@ DEFUN (isis_hello_interval_l2, if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { vty_out(vty, "Invalid hello-interval %ld - should be <1-600>\n", interval); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->hello_interval[1] = (u_int16_t)interval; @@ -806,7 +806,7 @@ DEFUN (isis_hello_multiplier, vty_out(vty, "Invalid hello-multiplier %d - should be <2-100>\n", mult); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->hello_multiplier[0] = (u_int16_t)mult; @@ -854,7 +854,7 @@ DEFUN (isis_hello_multiplier_l1, vty_out(vty, "Invalid hello-multiplier %d - should be <2-100>\n", mult); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->hello_multiplier[0] = (u_int16_t)mult; @@ -901,7 +901,7 @@ DEFUN (isis_hello_multiplier_l2, vty_out(vty, "Invalid hello-multiplier %d - should be <2-100>\n", mult); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->hello_multiplier[1] = (u_int16_t)mult; @@ -979,7 +979,7 @@ DEFUN (csnp_interval, if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) { vty_out(vty, "Invalid csnp-interval %lu - should be <1-600>\n", interval); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->csnp_interval[0] = (u_int16_t)interval; @@ -1026,7 +1026,7 @@ DEFUN (csnp_interval_l1, if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) { vty_out(vty, "Invalid csnp-interval %lu - should be <1-600>\n", interval); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->csnp_interval[0] = (u_int16_t)interval; @@ -1072,7 +1072,7 @@ DEFUN (csnp_interval_l2, if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) { vty_out(vty, "Invalid csnp-interval %lu - should be <1-600>\n", interval); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->csnp_interval[1] = (u_int16_t)interval; @@ -1117,7 +1117,7 @@ DEFUN (psnp_interval, if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) { vty_out(vty, "Invalid psnp-interval %lu - should be <1-120>\n", interval); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->psnp_interval[0] = (u_int16_t)interval; @@ -1164,7 +1164,7 @@ DEFUN (psnp_interval_l1, if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) { vty_out(vty, "Invalid psnp-interval %lu - should be <1-120>\n", interval); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->psnp_interval[0] = (u_int16_t)interval; @@ -1210,7 +1210,7 @@ DEFUN (psnp_interval_l2, if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) { vty_out(vty, "Invalid psnp-interval %lu - should be <1-120>\n", interval); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } circuit->psnp_interval[1] = (u_int16_t)interval; @@ -1253,12 +1253,12 @@ DEFUN (circuit_topology, if (circuit->area && circuit->area->oldmetric) { vty_out(vty, "Multi topology IS-IS can only be used with wide metrics\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } if (mtid == (uint16_t)-1) { vty_out(vty, "Don't know topology '%s'\n", arg); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } return isis_circuit_mt_enabled_set(circuit, mtid, true); @@ -1281,12 +1281,12 @@ DEFUN (no_circuit_topology, if (circuit->area && circuit->area->oldmetric) { vty_out(vty, "Multi topology IS-IS can only be used with wide metrics\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } if (mtid == (uint16_t)-1) { vty_out(vty, "Don't know topology '%s'\n", arg); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } return isis_circuit_mt_enabled_set(circuit, mtid, false); @@ -1298,11 +1298,11 @@ static int validate_metric_style_narrow(struct vty *vty, struct isis_area *area) struct listnode *node; if (!vty) - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; if (!area) { vty_out(vty, "ISIS area is invalid\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) { @@ -1311,14 +1311,14 @@ static int validate_metric_style_narrow(struct vty *vty, struct isis_area *area) && (circuit->te_metric[0] > MAX_NARROW_LINK_METRIC)) { vty_out(vty, "ISIS circuit %s metric is invalid\n", circuit->interface->name); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } if ((area->is_type & IS_LEVEL_2) && (circuit->is_type & IS_LEVEL_2) && (circuit->te_metric[1] > MAX_NARROW_LINK_METRIC)) { vty_out(vty, "ISIS circuit %s metric is invalid\n", circuit->interface->name); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } } @@ -1345,7 +1345,7 @@ DEFUN (metric_style, if (area_is_mt(area)) { vty_out(vty, "Narrow metrics cannot be used while multi topology IS-IS is active\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } ret = validate_metric_style_narrow(vty, area); @@ -1373,7 +1373,7 @@ DEFUN (no_metric_style, if (area_is_mt(area)) { vty_out(vty, "Narrow metrics cannot be used while multi topology IS-IS is active\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } ret = validate_metric_style_narrow(vty, area); @@ -1470,7 +1470,7 @@ static int area_lsp_mtu_set(struct vty *vty, unsigned int lsp_mtu) "ISIS area contains circuit %s, which has a maximum PDU size of %zu.\n", circuit->interface->name, isis_circuit_pdu_size(circuit)); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } } @@ -1568,7 +1568,7 @@ static int set_lsp_gen_interval(struct vty *vty, struct isis_area *area, "LSP gen interval %us must be less than " "the LSP refresh interval %us\n", interval, area->lsp_refresh[lvl - 1]); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } } @@ -1817,7 +1817,7 @@ static int area_max_lsp_lifetime_set(struct vty *vty, int level, "the configured LSP gen interval %us\n", refresh_interval, area->lsp_gen_interval[lvl - 1]); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } } } @@ -1890,14 +1890,14 @@ static int area_lsp_refresh_interval_set(struct vty *vty, int level, "LSP refresh interval %us must be greater than " "the configured LSP gen interval %us\n", interval, area->lsp_gen_interval[lvl - 1]); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } if (interval > (area->max_lsp_lifetime[lvl - 1] - 300)) { vty_out(vty, "LSP refresh interval %us must be less than " "the configured LSP lifetime %us less 300\n", interval, area->max_lsp_lifetime[lvl - 1]); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } } @@ -1961,7 +1961,7 @@ static int area_passwd_set(struct vty *vty, int level, if (passwd && strlen(passwd) > 254) { vty_out(vty, "Too long area password (>254)\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } type_set(area, level, passwd, snp_auth); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 8c6968f8ec..ed96bd31c2 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -245,260 +245,91 @@ static int isis_zebra_link_params(int command, struct zclient *zclient, return 0; } -static void isis_zebra_route_add_ipv4(struct prefix *prefix, - struct isis_route_info *route_info) +static void isis_zebra_route_add_route(struct prefix *prefix, + struct isis_route_info *route_info) { - u_char message; - u_int32_t flags; - int psize; - struct stream *stream; + struct zapi_route api; + struct zapi_nexthop *api_nh; struct isis_nexthop *nexthop; - struct listnode *node; - - if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) - return; - - if (vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_ISIS], - VRF_DEFAULT)) { - message = 0; - flags = 0; - - SET_FLAG(message, ZAPI_MESSAGE_NEXTHOP); - SET_FLAG(message, ZAPI_MESSAGE_METRIC); -#if 0 - SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); -#endif - - stream = zclient->obuf; - stream_reset(stream); - zclient_create_header(stream, ZEBRA_IPV4_ROUTE_ADD, - VRF_DEFAULT); - /* type */ - stream_putc(stream, ZEBRA_ROUTE_ISIS); - /* instance */ - stream_putw(stream, 0); - /* flags */ - stream_putl(stream, flags); - /* message */ - stream_putc(stream, message); - /* SAFI */ - stream_putw(stream, SAFI_UNICAST); - /* prefix information */ - psize = PSIZE(prefix->prefixlen); - stream_putc(stream, prefix->prefixlen); - stream_write(stream, (u_char *)&prefix->u.prefix4, psize); - - stream_putc(stream, listcount(route_info->nexthops)); - - /* Nexthop, ifindex, distance and metric information */ - for (ALL_LIST_ELEMENTS_RO(route_info->nexthops, node, - nexthop)) { - /* FIXME: can it be ? */ - if (nexthop->ip.s_addr != INADDR_ANY) { - stream_putc(stream, NEXTHOP_TYPE_IPV4_IFINDEX); - stream_put_in_addr(stream, &nexthop->ip); - stream_putl(stream, nexthop->ifindex); - } else { - stream_putc(stream, NEXTHOP_TYPE_IFINDEX); - stream_putl(stream, nexthop->ifindex); - } - } -#if 0 - if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) - stream_putc (stream, route_info->depth); -#endif - if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC)) - stream_putl(stream, route_info->cost); - - stream_putw_at(stream, 0, stream_get_endp(stream)); - zclient_send_message(zclient); - SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); - UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); - } -} - -static void isis_zebra_route_del_ipv4(struct prefix *prefix, - struct isis_route_info *route_info) -{ - struct zapi_ipv4 api; - struct prefix_ipv4 prefix4; - - if (vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_ISIS], - VRF_DEFAULT)) { - api.vrf_id = VRF_DEFAULT; - api.type = ZEBRA_ROUTE_ISIS; - api.instance = 0; - api.flags = 0; - api.message = 0; - api.safi = SAFI_UNICAST; - prefix4.family = AF_INET; - prefix4.prefixlen = prefix->prefixlen; - prefix4.prefix = prefix->u.prefix4; - zapi_ipv4_route(ZEBRA_IPV4_ROUTE_DELETE, zclient, &prefix4, - &api); - } - UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); - - return; -} - -static void isis_zebra_route_add_ipv6(struct prefix *prefix, - struct isis_route_info *route_info) -{ - struct zapi_ipv6 api; - struct in6_addr **nexthop_list; - ifindex_t *ifindex_list; struct isis_nexthop6 *nexthop6; - int i, size; struct listnode *node; - struct prefix_ipv6 prefix6; + int count = 0; if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; + memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_ISIS; - api.instance = 0; - api.flags = 0; - api.message = 0; api.safi = SAFI_UNICAST; + api.prefix = *prefix; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); api.metric = route_info->cost; #if 0 - SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); - api.distance = route_info->depth; + SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = route_info->depth; #endif - api.nexthop_num = listcount(route_info->nexthops6); - api.ifindex_num = listcount(route_info->nexthops6); - /* allocate memory for nexthop_list */ - size = sizeof(struct isis_nexthop6 *) - * listcount(route_info->nexthops6); - nexthop_list = (struct in6_addr **)XMALLOC(MTYPE_ISIS_TMP, size); - if (!nexthop_list) { - zlog_err("isis_zebra_add_route_ipv6: out of memory!"); - return; - } - - /* allocate memory for ifindex_list */ - size = sizeof(unsigned int) * listcount(route_info->nexthops6); - ifindex_list = (ifindex_t *)XMALLOC(MTYPE_ISIS_TMP, size); - if (!ifindex_list) { - zlog_err("isis_zebra_add_route_ipv6: out of memory!"); - XFREE(MTYPE_ISIS_TMP, nexthop_list); - return; - } - - /* for each nexthop */ - i = 0; - for (ALL_LIST_ELEMENTS_RO(route_info->nexthops6, node, nexthop6)) { - if (!IN6_IS_ADDR_LINKLOCAL(&nexthop6->ip6) - && !IN6_IS_ADDR_UNSPECIFIED(&nexthop6->ip6)) { - api.nexthop_num--; - api.ifindex_num--; - continue; + /* Nexthops */ + switch (prefix->family) { + case AF_INET: + for (ALL_LIST_ELEMENTS_RO(route_info->nexthops, node, + nexthop)) { + api_nh = &api.nexthops[count]; + /* FIXME: can it be ? */ + if (nexthop->ip.s_addr != INADDR_ANY) { + api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX; + api_nh->gate.ipv4 = nexthop->ip; + } else { + api_nh->type = NEXTHOP_TYPE_IFINDEX; + } + api_nh->ifindex = nexthop->ifindex; + count++; } + break; + case AF_INET6: + for (ALL_LIST_ELEMENTS_RO(route_info->nexthops6, node, + nexthop6)) { + if (!IN6_IS_ADDR_LINKLOCAL(&nexthop6->ip6) + && !IN6_IS_ADDR_UNSPECIFIED(&nexthop6->ip6)) { + continue; + } - nexthop_list[i] = &nexthop6->ip6; - ifindex_list[i] = nexthop6->ifindex; - i++; + api_nh = &api.nexthops[count]; + api_nh->gate.ipv6 = nexthop6->ip6; + api_nh->ifindex = nexthop6->ifindex; + api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; + count++; + } + break; } + if (!count) + return; - api.nexthop = nexthop_list; - api.ifindex = ifindex_list; + api.nexthop_num = count; - if (api.nexthop_num && api.ifindex_num) { - prefix6.family = AF_INET6; - prefix6.prefixlen = prefix->prefixlen; - memcpy(&prefix6.prefix, &prefix->u.prefix6, - sizeof(struct in6_addr)); - zapi_ipv6_route(ZEBRA_IPV6_ROUTE_ADD, zclient, &prefix6, NULL, - &api); - SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); - UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); - } - - XFREE(MTYPE_ISIS_TMP, nexthop_list); - XFREE(MTYPE_ISIS_TMP, ifindex_list); - - return; + zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); + SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); + UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); } -static void isis_zebra_route_del_ipv6(struct prefix *prefix, - struct isis_route_info *route_info) +static void isis_zebra_route_del_route(struct prefix *prefix, + struct isis_route_info *route_info) { - struct zapi_ipv6 api; - struct in6_addr **nexthop_list; - ifindex_t *ifindex_list; - struct isis_nexthop6 *nexthop6; - int i, size; - struct listnode *node; - struct prefix_ipv6 prefix6; + struct zapi_route api; if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; + memset(&api, 0, sizeof(api)); api.vrf_id = VRF_DEFAULT; api.type = ZEBRA_ROUTE_ISIS; - api.instance = 0; - api.flags = 0; - api.message = 0; api.safi = SAFI_UNICAST; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); - api.nexthop_num = listcount(route_info->nexthops6); - api.ifindex_num = listcount(route_info->nexthops6); + api.prefix = *prefix; - /* allocate memory for nexthop_list */ - size = sizeof(struct isis_nexthop6 *) - * listcount(route_info->nexthops6); - nexthop_list = (struct in6_addr **)XMALLOC(MTYPE_ISIS_TMP, size); - if (!nexthop_list) { - zlog_err("isis_zebra_route_del_ipv6: out of memory!"); - return; - } - - /* allocate memory for ifindex_list */ - size = sizeof(unsigned int) * listcount(route_info->nexthops6); - ifindex_list = (ifindex_t *)XMALLOC(MTYPE_ISIS_TMP, size); - if (!ifindex_list) { - zlog_err("isis_zebra_route_del_ipv6: out of memory!"); - XFREE(MTYPE_ISIS_TMP, nexthop_list); - return; - } - - /* for each nexthop */ - i = 0; - for (ALL_LIST_ELEMENTS_RO(route_info->nexthops6, node, nexthop6)) { - if (!IN6_IS_ADDR_LINKLOCAL(&nexthop6->ip6) - && !IN6_IS_ADDR_UNSPECIFIED(&nexthop6->ip6)) { - api.nexthop_num--; - api.ifindex_num--; - continue; - } - - nexthop_list[i] = &nexthop6->ip6; - ifindex_list[i] = nexthop6->ifindex; - i++; - } - - api.nexthop = nexthop_list; - api.ifindex = ifindex_list; - - if (api.nexthop_num && api.ifindex_num) { - prefix6.family = AF_INET6; - prefix6.prefixlen = prefix->prefixlen; - memcpy(&prefix6.prefix, &prefix->u.prefix6, - sizeof(struct in6_addr)); - zapi_ipv6_route(ZEBRA_IPV6_ROUTE_DELETE, zclient, &prefix6, - NULL, &api); - UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); - } - - XFREE(MTYPE_ISIS_TMP, nexthop_list); - XFREE(MTYPE_ISIS_TMP, ifindex_list); + zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); + UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); } void isis_zebra_route_update(struct prefix *prefix, @@ -507,144 +338,38 @@ void isis_zebra_route_update(struct prefix *prefix, if (zclient->sock < 0) return; - if ((prefix->family == AF_INET - && !vrf_bitmap_check(zclient->redist[AFI_IP][ZEBRA_ROUTE_ISIS], - VRF_DEFAULT)) - || (prefix->family == AF_INET6 - && !vrf_bitmap_check(zclient->redist[AFI_IP6][ZEBRA_ROUTE_ISIS], - VRF_DEFAULT))) - return; - - if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) { - if (prefix->family == AF_INET) - isis_zebra_route_add_ipv4(prefix, route_info); - else if (prefix->family == AF_INET6) - isis_zebra_route_add_ipv6(prefix, route_info); - } else { - if (prefix->family == AF_INET) - isis_zebra_route_del_ipv4(prefix, route_info); - else if (prefix->family == AF_INET6) - isis_zebra_route_del_ipv6(prefix, route_info); - } - return; -} - -static int isis_zebra_read_ipv4(int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf_id) -{ - struct stream *stream; - struct zapi_ipv4 api; - struct prefix_ipv4 p; - struct prefix *p_generic = (struct prefix *)&p; - - stream = zclient->ibuf; - memset(&api, 0, sizeof(api)); - memset(&p, 0, sizeof(struct prefix_ipv4)); - - api.type = stream_getc(stream); - api.instance = stream_getw(stream); - api.flags = stream_getl(stream); - api.message = stream_getc(stream); - - p.family = AF_INET; - p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc(stream)); - stream_get(&p.prefix, stream, PSIZE(p.prefixlen)); - - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { - api.nexthop_num = stream_getc(stream); - (void)stream_get_ipv4(stream); - } - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) { - api.ifindex_num = stream_getc(stream); - stream_getl(stream); - } - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc(stream); - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl(stream); - - /* - * Avoid advertising a false default reachability. (A default - * route installed by IS-IS gets redistributed from zebra back - * into IS-IS causing us to start advertising default reachabity - * without this check) - */ - if (p.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS) - command = ZEBRA_IPV4_ROUTE_DELETE; - - if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD) - isis_redist_add(api.type, p_generic, api.distance, api.metric); + if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) + isis_zebra_route_add_route(prefix, route_info); else - isis_redist_delete(api.type, p_generic); - - return 0; + isis_zebra_route_del_route(prefix, route_info); } -static int isis_zebra_read_ipv6(int command, struct zclient *zclient, - zebra_size_t length, vrf_id_t vrf_id) +static int isis_zebra_read(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) { - struct stream *stream; - struct zapi_ipv6 api; - struct prefix_ipv6 p; - struct prefix src_p; - struct prefix *p_generic = (struct prefix *)&p; - struct in6_addr nexthop; - unsigned long ifindex __attribute__((unused)); + struct zapi_route api; - stream = zclient->ibuf; - memset(&api, 0, sizeof(api)); - memset(&p, 0, sizeof(struct prefix_ipv6)); - memset(&nexthop, 0, sizeof(nexthop)); - ifindex = 0; + if (zapi_route_decode(zclient->ibuf, &api) < 0) + return -1; - api.type = stream_getc(stream); - api.instance = stream_getw(stream); - api.flags = stream_getl(stream); - api.message = stream_getc(stream); - - p.family = AF_INET6; - p.prefixlen = stream_getc(stream); - stream_get(&p.prefix, stream, PSIZE(p.prefixlen)); - - memset(&src_p, 0, sizeof(struct prefix)); - src_p.family = AF_INET6; - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) { - src_p.prefixlen = stream_getc(stream); - stream_get(&src_p.u.prefix6, stream, PSIZE(src_p.prefixlen)); - } - - if (src_p.prefixlen) - /* we completely ignore srcdest routes for now. */ + /* we completely ignore srcdest routes for now. */ + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) return 0; - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { - api.nexthop_num = stream_getc(stream); /* this is always 1 */ - stream_get(&nexthop, stream, sizeof(nexthop)); - } - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) { - api.ifindex_num = stream_getc(stream); - ifindex = stream_getl(stream); - } - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc(stream); - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl(stream); - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG)) - api.tag = stream_getl(stream); - /* * Avoid advertising a false default reachability. (A default * route installed by IS-IS gets redistributed from zebra back * into IS-IS causing us to start advertising default reachabity * without this check) */ - if (p.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS) - command = ZEBRA_IPV6_ROUTE_DELETE; + if (api.prefix.prefixlen == 0 && api.type == ZEBRA_ROUTE_ISIS) + command = ZEBRA_REDISTRIBUTE_ROUTE_DEL; - if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD) - isis_redist_add(api.type, p_generic, api.distance, api.metric); + if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) + isis_redist_add(api.type, &api.prefix, api.distance, + api.metric); else - isis_redist_delete(api.type, p_generic); + isis_redist_delete(api.type, &api.prefix); return 0; } @@ -692,10 +417,8 @@ void isis_zebra_init(struct thread_master *master) zclient->interface_address_add = isis_zebra_if_address_add; zclient->interface_address_delete = isis_zebra_if_address_del; zclient->interface_link_params = isis_zebra_link_params; - zclient->redistribute_route_ipv4_add = isis_zebra_read_ipv4; - zclient->redistribute_route_ipv4_del = isis_zebra_read_ipv4; - zclient->redistribute_route_ipv6_add = isis_zebra_read_ipv6; - zclient->redistribute_route_ipv6_del = isis_zebra_read_ipv6; + zclient->redistribute_route_add = isis_zebra_read; + zclient->redistribute_route_del = isis_zebra_read; return; } diff --git a/isisd/isisd.c b/isisd/isisd.c index e654f8557c..bdc1d836db 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -347,14 +347,14 @@ int area_net_title(struct vty *vty, const char *net_title) "area address must be at least 8..20 octets long (%d)\n", addr->addr_len); XFREE(MTYPE_ISIS_AREA_ADDR, addr); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } if (addr->area_addr[addr->addr_len - 1] != 0) { vty_out(vty, "nsel byte (last byte) in area address must be 0\n"); XFREE(MTYPE_ISIS_AREA_ADDR, addr); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } if (isis->sysid_set == 0) { @@ -374,7 +374,7 @@ int area_net_title(struct vty *vty, const char *net_title) vty_out(vty, "System ID must not change when defining additional area addresses\n"); XFREE(MTYPE_ISIS_AREA_ADDR, addr); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } /* now we see that we don't already have this address */ @@ -419,7 +419,7 @@ int area_clear_net_title(struct vty *vty, const char *net_title) vty_out(vty, "Unsupported area address length %d, should be 8...20 \n", addr.addr_len); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } memcpy(addr.area_addr, buff, (int)addr.addr_len); @@ -758,17 +758,18 @@ void print_debug(struct vty *vty, int flags, int onoff) vty_out(vty, "IS-IS LSP scheduling debugging is %s\n", onoffs); } -DEFUN (show_debugging, - show_debugging_isis_cmd, - "show debugging isis", - SHOW_STR - "State of each debugging option\n" - ISIS_STR) +DEFUN_NOSH (show_debugging, + show_debugging_isis_cmd, + "show debugging [isis]", + SHOW_STR + "State of each debugging option\n" + ISIS_STR) { - if (isis->debugs) { - vty_out(vty, "IS-IS:\n"); + vty_out (vty, "IS-IS debugging status:\n"); + + if (isis->debugs) print_debug(vty, isis->debugs, 1); - } + return CMD_SUCCESS; } @@ -1259,8 +1260,8 @@ DEFUN (show_isis_spf_ietf, if (area->spf_timer[level - 1]) { struct timeval remain = thread_timer_remain( area->spf_timer[level - 1]); - vty_out(vty, "Pending, due in %ld msec\n", - remain.tv_sec * 1000 + vty_out(vty, "Pending, due in %lld msec\n", + (long long)remain.tv_sec * 1000 + remain.tv_usec / 1000); } else { vty_out(vty, "Not scheduled\n"); @@ -1404,7 +1405,7 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level) (u_char)strtol((char *)number, NULL, 16); pos -= 4; if (strncmp(pos, ".", 1) != 0) - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING; } if (strncmp(pos, ".", 1) == 0) { memcpy(number, ++pos, 2); @@ -1569,16 +1570,16 @@ DEFUN (isis_topology, if (area->oldmetric) { vty_out(vty, "Multi topology IS-IS can only be used with wide metrics\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } if (mtid == (uint16_t)-1) { vty_out(vty, "Don't know topology '%s'\n", arg); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } if (mtid == ISIS_MT_IPV4_UNICAST) { vty_out(vty, "Cannot configure IPv4 unicast topology\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } area_set_mt_enabled(area, mtid, true); @@ -1602,16 +1603,16 @@ DEFUN (no_isis_topology, if (area->oldmetric) { vty_out(vty, "Multi topology IS-IS can only be used with wide metrics\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } if (mtid == (uint16_t)-1) { vty_out(vty, "Don't know topology '%s'\n", arg); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } if (mtid == ISIS_MT_IPV4_UNICAST) { vty_out(vty, "Cannot configure IPv4 unicast topology\n"); - return CMD_ERR_AMBIGUOUS; + return CMD_WARNING_CONFIG_FAILED; } area_set_mt_enabled(area, mtid, false); diff --git a/isisd/isisd.h b/isisd/isisd.h index da02854f5c..36fe0b5937 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -25,8 +25,6 @@ #include "vty.h" -#define ISISD_VERSION "0.0.7" - #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_redist.h" diff --git a/ldpd/control.h b/ldpd/control.h index 0e66a1636a..23edb5f24d 100644 --- a/ldpd/control.h +++ b/ldpd/control.h @@ -19,7 +19,7 @@ #ifndef _CONTROL_H_ #define _CONTROL_H_ -#include "openbsd-queue.h" +#include "queue.h" struct ctl_conn { TAILQ_ENTRY(ctl_conn) entry; diff --git a/ldpd/lde.h b/ldpd/lde.h index 43f1d36481..94077d1631 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -21,7 +21,7 @@ #ifndef _LDE_H_ #define _LDE_H_ -#include "openbsd-queue.h" +#include "queue.h" #include "openbsd-tree.h" #include "if.h" diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c index db92b93628..be473063cd 100644 --- a/ldpd/ldp_vty_cmds.c +++ b/ldpd/ldp_vty_cmds.c @@ -684,13 +684,13 @@ DEFPY (ldp_show_l2vpn_atom_vc, return (ldp_vty_show_atom_vc(vty, json)); } -DEFPY (ldp_show_debugging_mpls_ldp, - ldp_show_debugging_mpls_ldp_cmd, - "show debugging mpls ldp", - "Show running system information\n" - "Debugging functions\n" - "MPLS information\n" - "Label Distribution Protocol\n") +DEFUN_NOSH (ldp_show_debugging_mpls_ldp, + ldp_show_debugging_mpls_ldp_cmd, + "show debugging [mpls ldp]", + "Show running system information\n" + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n") { return (ldp_vty_show_debugging(vty)); } diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index ecc7db8f2e..c50cc0fda2 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -396,19 +396,34 @@ static int ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { - struct stream *s; - u_char type; - u_char message_flags; + struct zapi_route api; + struct zapi_nexthop *api_nh; struct kroute kr; - int nhnum = 0, nhlen; - size_t nhmark; - int add = 0; + int i, add = 0; + + if (zapi_route_decode(zclient->ibuf, &api) < 0) + return -1; + + /* we completely ignore srcdest routes for now. */ + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) + return (0); memset(&kr, 0, sizeof(kr)); - s = zclient->ibuf; + kr.af = api.prefix.family; + switch (kr.af) { + case AF_INET: + kr.prefix.v4 = api.prefix.u.prefix4; + break; + case AF_INET6: + kr.prefix.v6 = api.prefix.u.prefix6; + break; + default: + break; + } + kr.prefixlen = api.prefix.prefixlen; + kr.priority = api.distance; - type = stream_getc(s); - switch (type) { + switch (api.type) { case ZEBRA_ROUTE_CONNECT: kr.flags |= F_CONNECTED; break; @@ -419,84 +434,38 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, break; } - stream_getl(s); /* flags, unused */ - stream_getw(s); /* instance, unused */ - message_flags = stream_getc(s); - - switch (command) { - case ZEBRA_REDISTRIBUTE_IPV4_ADD: - case ZEBRA_REDISTRIBUTE_IPV4_DEL: - kr.af = AF_INET; - nhlen = sizeof(struct in_addr); - break; - case ZEBRA_REDISTRIBUTE_IPV6_ADD: - case ZEBRA_REDISTRIBUTE_IPV6_DEL: - kr.af = AF_INET6; - nhlen = sizeof(struct in6_addr); - break; - default: - fatalx("ldp_zebra_read_route: unknown command"); - } - kr.prefixlen = stream_getc(s); - stream_get(&kr.prefix, s, PSIZE(kr.prefixlen)); - if (bad_addr(kr.af, &kr.prefix) || (kr.af == AF_INET6 && IN6_IS_SCOPE_EMBED(&kr.prefix.v6))) return (0); - if (kr.af == AF_INET6 && - CHECK_FLAG(message_flags, ZAPI_MESSAGE_SRCPFX)) { - uint8_t src_prefixlen; - - src_prefixlen = stream_getc(s); - - /* we completely ignore srcdest routes for now. */ - if (src_prefixlen) - return (0); - } - - if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP)) { - nhnum = stream_getc(s); - nhmark = stream_get_getp(s); - stream_set_getp(s, nhmark + nhnum * (nhlen + 5)); - } - - if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_DISTANCE)) - kr.priority = stream_getc(s); - if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_METRIC)) - stream_getl(s); /* metric, not used */ - - if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP)) - stream_set_getp(s, nhmark); - - if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD || - command == ZEBRA_REDISTRIBUTE_IPV6_ADD) + if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) add = 1; - if (nhnum == 0) + if (api.nexthop_num == 0) debug_zebra_in("route %s %s/%d (%s)", (add) ? "add" : "delete", log_addr(kr.af, &kr.prefix), kr.prefixlen, - zebra_route_string(type)); + zebra_route_string(api.type)); /* loop through all the nexthops */ - for (; nhnum > 0; nhnum--) { + for (i = 0; i < api.nexthop_num; i++) { + api_nh = &api.nexthops[i]; + switch (kr.af) { case AF_INET: - kr.nexthop.v4.s_addr = stream_get_ipv4(s); + kr.nexthop.v4 = api_nh->gate.ipv4; break; case AF_INET6: - stream_get(&kr.nexthop.v6, s, sizeof(kr.nexthop.v6)); + kr.nexthop.v6 = api_nh->gate.ipv6; break; default: break; } - stream_getc(s); /* ifindex_num, unused. */ - kr.ifindex = stream_getl(s); + kr.ifindex = api_nh->ifindex;; debug_zebra_in("route %s %s/%d nexthop %s ifindex %u (%s)", (add) ? "add" : "delete", log_addr(kr.af, &kr.prefix), kr.prefixlen, log_addr(kr.af, &kr.nexthop), kr.ifindex, - zebra_route_string(type)); + zebra_route_string(api.type)); if (add) main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, &kr, @@ -553,10 +522,8 @@ ldp_zebra_init(struct thread_master *master) zclient->interface_down = ldp_interface_status_change; zclient->interface_address_add = ldp_interface_address_add; zclient->interface_address_delete = ldp_interface_address_delete; - zclient->redistribute_route_ipv4_add = ldp_zebra_read_route; - zclient->redistribute_route_ipv4_del = ldp_zebra_read_route; - zclient->redistribute_route_ipv6_add = ldp_zebra_read_route; - zclient->redistribute_route_ipv6_del = ldp_zebra_read_route; + zclient->redistribute_route_add = ldp_zebra_read_route; + zclient->redistribute_route_del = ldp_zebra_read_route; zclient->pw_status_update = ldp_zebra_read_pw_status_update; } diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 80af2b14e5..0a586ec1c5 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -392,6 +392,8 @@ ldpd_shutdown(void) pid_t pid; int status; + frr_early_fini(); + /* close pipes */ msgbuf_clear(&iev_ldpe->ibuf.w); close(iev_ldpe->ibuf.fd); @@ -423,13 +425,9 @@ ldpd_shutdown(void) vrf_terminate(); access_list_reset(); - cmd_terminate(); - vty_terminate(); ldp_zebra_destroy(); - zprivs_terminate(&ldpd_privs); - thread_master_free(master); - closezlog(); + frr_fini(); exit(0); } diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 31d0bc69b1..5580ea5d67 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -22,7 +22,7 @@ #ifndef _LDPD_H_ #define _LDPD_H_ -#include "openbsd-queue.h" +#include "queue.h" #include "openbsd-tree.h" #include "imsg.h" #include "thread.h" diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index 74f6b852b0..ccff1e803d 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -21,7 +21,7 @@ #ifndef _LDPE_H_ #define _LDPE_H_ -#include "openbsd-queue.h" +#include "queue.h" #include "openbsd-tree.h" #ifdef __OpenBSD__ #include diff --git a/lib/command.c b/lib/command.c index 9421fadc0b..24095de4f0 100644 --- a/lib/command.c +++ b/lib/command.c @@ -42,6 +42,7 @@ #include "command_graph.h" #include "qobj.h" #include "defaults.h" +#include "libfrr.h" DEFINE_MTYPE(LIB, HOST, "Host config") DEFINE_MTYPE(LIB, STRVEC, "String vector") @@ -376,21 +377,23 @@ void install_element(enum node_type ntype, struct cmd_element *cmd) return; } - cnode = vector_slot(cmdvec, ntype); + cnode = vector_lookup(cmdvec, ntype); if (cnode == NULL) { fprintf(stderr, - "Command node %d doesn't exist, please check it\n", - ntype); - fprintf(stderr, - "Have you called install_node before this install_element?\n"); + "%s[%s]:\n" + "\tnode %d (%s) does not exist.\n" + "\tplease call install_node() before install_element()\n", + cmd->name, cmd->string, ntype, node_names[ntype]); exit(EXIT_FAILURE); } if (hash_lookup(cnode->cmd_hash, cmd) != NULL) { fprintf(stderr, - "Multiple command installs to node %d of command:\n%s\n", - ntype, cmd->string); + "%s[%s]:\n" + "\tnode %d (%s) already has this command installed.\n" + "\tduplicate install_element call?\n", + cmd->name, cmd->string, ntype, node_names[ntype]); return; } @@ -423,21 +426,23 @@ void uninstall_element(enum node_type ntype, struct cmd_element *cmd) return; } - cnode = vector_slot(cmdvec, ntype); + cnode = vector_lookup(cmdvec, ntype); if (cnode == NULL) { fprintf(stderr, - "Command node %d doesn't exist, please check it\n", - ntype); - fprintf(stderr, - "Have you called install_node before this install_element?\n"); + "%s[%s]:\n" + "\tnode %d (%s) does not exist.\n" + "\tplease call install_node() before uninstall_element()\n", + cmd->name, cmd->string, ntype, node_names[ntype]); exit(EXIT_FAILURE); } if (hash_release(cnode->cmd_hash, cmd) == NULL) { fprintf(stderr, - "Trying to uninstall non-installed command (node %d):\n%s\n", - ntype, cmd->string); + "%s[%s]:\n" + "\tnode %d (%s) does not have this command installed.\n" + "\tduplicate uninstall_element call?\n", + cmd->name, cmd->string, ntype, node_names[ntype]); return; } @@ -572,6 +577,9 @@ static int config_write_host(struct vty *vty) else if (!host.motd) vty_out(vty, "no banner motd\n"); + if (debug_memstats_at_exit) + vty_out(vty, "!\ndebug memstats-at-exit\n"); + return 1; } @@ -2417,6 +2425,17 @@ DEFUN (no_config_log_timestamp_precision, return CMD_SUCCESS; } +DEFUN (debug_memstats, + debug_memstats_cmd, + "[no] debug memstats-at-exit", + NO_STR + DEBUG_STR + "Print memory type statistics at exit\n") +{ + debug_memstats_at_exit = !!strcmp(argv[0]->text, "no"); + return CMD_SUCCESS; +} + int cmd_banner_motd_file(const char *file) { int success = CMD_SUCCESS; @@ -2589,6 +2608,7 @@ void cmd_init(int terminal) /* Each node's basic commands. */ install_element(VIEW_NODE, &show_version_cmd); install_element(ENABLE_NODE, &show_startup_config_cmd); + install_element(ENABLE_NODE, &debug_memstats_cmd); if (terminal) { install_element(VIEW_NODE, &config_list_cmd); @@ -2624,6 +2644,7 @@ void cmd_init(int terminal) install_element(CONFIG_NODE, &domainname_cmd); install_element(CONFIG_NODE, &no_domainname_cmd); install_element(CONFIG_NODE, &frr_version_defaults_cmd); + install_element(CONFIG_NODE, &debug_memstats_cmd); if (terminal > 0) { install_element(CONFIG_NODE, &password_cmd); diff --git a/lib/command_match.c b/lib/command_match.c index f07448d716..ad3ec2492e 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -46,8 +46,9 @@ DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack") static int add_nexthops(struct list *, struct graph_node *, struct graph_node **, size_t); -static struct list *command_match_r(struct graph_node *, vector, unsigned int, - struct graph_node **); +static enum matcher_rv command_match_r(struct graph_node *, vector, + unsigned int, struct graph_node **, + struct list **); static int score_precedence(enum cmd_token_type); @@ -80,14 +81,12 @@ static enum match_type match_variable(struct cmd_token *, const char *); static enum match_type match_mac(const char *, bool); -/* matching functions */ -static enum matcher_rv matcher_rv; - enum matcher_rv command_match(struct graph *cmdgraph, vector vline, struct list **argv, const struct cmd_element **el) { struct graph_node *stack[MAXDEPTH]; - matcher_rv = MATCHER_NO_MATCH; + enum matcher_rv status; + *argv = NULL; // prepend a dummy token to match that pesky start node vector vvline = vector_init(vline->alloced + 1); @@ -97,9 +96,8 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline, vvline->active = vline->active + 1; struct graph_node *start = vector_slot(cmdgraph->nodes, 0); - if ((*argv = command_match_r(start, vvline, 0, - stack))) // successful match - { + status = command_match_r(start, vvline, 0, stack, argv); + if (status == MATCHER_OK) { // successful match struct listnode *head = listhead(*argv); struct listnode *tail = listtail(*argv); @@ -115,6 +113,9 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline, // input, with each cmd_token->arg holding the corresponding // input assert(*el); + } else if (*argv) { + del_arglist(*argv); + *argv = NULL; } if (!*el) { @@ -129,7 +130,7 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline, // free vector vector_free(vvline); - return matcher_rv; + return status; } /** @@ -183,11 +184,15 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline, * * If no match was found, the return value is NULL. */ -static struct list *command_match_r(struct graph_node *start, vector vline, - unsigned int n, struct graph_node **stack) +static enum matcher_rv command_match_r(struct graph_node *start, vector vline, + unsigned int n, + struct graph_node **stack, + struct list **currbest) { assert(n < vector_active(vline)); + enum matcher_rv status = MATCHER_NO_MATCH; + // get the minimum match level that can count as a full match struct cmd_token *token = start->data; enum match_type minmatch = min_match_level(token->type); @@ -196,11 +201,11 @@ static struct list *command_match_r(struct graph_node *start, vector vline, * this disallows matching the same one more than once if there is a * circle in the graph (used for keyword arguments) */ if (n == MAXDEPTH) - return NULL; + return MATCHER_NO_MATCH; if (!token->allowrepeat) for (size_t s = 0; s < n; s++) if (stack[s] == start) - return NULL; + return MATCHER_NO_MATCH; // get the current operating input token char *input_token = vector_slot(vline, n); @@ -231,7 +236,7 @@ static struct list *command_match_r(struct graph_node *start, vector vline, // if we don't match this node, die if (match_token(token, input_token) < minmatch) - return NULL; + return MATCHER_NO_MATCH; stack[n] = start; @@ -244,86 +249,92 @@ static struct list *command_match_r(struct graph_node *start, vector vline, add_nexthops(next, start, NULL, 0); // determine the best match - int ambiguous = 0; - struct list *currbest = NULL; for (ALL_LIST_ELEMENTS_RO(next, ln, gn)) { // if we've matched all input we're looking for END_TKN if (n + 1 == vector_active(vline)) { struct cmd_token *tok = gn->data; if (tok->type == END_TKN) { - if (currbest) // there is more than one END_TKN - // in the follow set - { - ambiguous = 1; + // if more than one END_TKN in the follow set + if (*currbest) { + status = MATCHER_AMBIGUOUS; break; + } else { + status = MATCHER_OK; } - currbest = list_new(); + *currbest = list_new(); // node should have one child node with the // element struct graph_node *leaf = vector_slot(gn->to, 0); // last node in the list will hold the - // cmd_element; - // this is important because list_delete() - // expects - // that all nodes have the same data type, so - // when - // deleting this list the last node must be - // manually deleted + // cmd_element; this is important because + // list_delete() expects that all nodes have + // the same data type, so when deleting this + // list the last node must be manually deleted struct cmd_element *el = leaf->data; - listnode_add(currbest, el); - currbest->del = + listnode_add(*currbest, el); + (*currbest)->del = (void (*)(void *)) & cmd_token_del; // do not break immediately; continue walking - // through the follow set - // to ensure that there is exactly one END_TKN + // through the follow set to ensure that there + // is exactly one END_TKN } continue; } // else recurse on candidate child node - struct list *result = command_match_r(gn, vline, n + 1, stack); + struct list *result = NULL; + enum matcher_rv rstat = + command_match_r(gn, vline, n + 1, stack, &result); // save the best match - if (result && currbest) { + if (result && *currbest) { // pick the best of two matches struct list *newbest = - disambiguate(currbest, result, vline, n + 1); - // set ambiguity flag - ambiguous = - !newbest || (ambiguous && newbest == currbest); + disambiguate(*currbest, result, vline, n + 1); + + // current best and result are ambiguous + if (!newbest) + status = MATCHER_AMBIGUOUS; + // current best is still the best, but ambiguous + else if (newbest == *currbest + && status == MATCHER_AMBIGUOUS) + status = MATCHER_AMBIGUOUS; + // result is better, but also ambiguous + else if (newbest == result + && rstat == MATCHER_AMBIGUOUS) + status = MATCHER_AMBIGUOUS; + // one or the other is superior and not ambiguous + else + status = MATCHER_OK; + // delete the unnecessary result struct list *todelete = - ((newbest && newbest == result) ? currbest + ((newbest && newbest == result) ? *currbest : result); del_arglist(todelete); - currbest = newbest ? newbest : currbest; - } else if (result) - currbest = result; - } - - if (currbest) { - if (ambiguous) { - del_arglist(currbest); - currbest = NULL; - matcher_rv = MATCHER_AMBIGUOUS; - } else { - // copy token, set arg and prepend to currbest - struct cmd_token *token = start->data; - struct cmd_token *copy = cmd_token_dup(token); - copy->arg = XSTRDUP(MTYPE_CMD_ARG, input_token); - listnode_add_before(currbest, currbest->head, copy); - matcher_rv = MATCHER_OK; + *currbest = newbest ? newbest : *currbest; + } else if (result) { + status = rstat; + *currbest = result; + } else if (!*currbest) { + status = MAX(rstat, status); } - } else if (n + 1 == vector_active(vline) - && matcher_rv == MATCHER_NO_MATCH) - matcher_rv = MATCHER_INCOMPLETE; + } + if (*currbest) { + // copy token, set arg and prepend to currbest + struct cmd_token *token = start->data; + struct cmd_token *copy = cmd_token_dup(token); + copy->arg = XSTRDUP(MTYPE_CMD_ARG, input_token); + listnode_add_before(*currbest, (*currbest)->head, copy); + } else if (n + 1 == vector_active(vline) && status == MATCHER_NO_MATCH) + status = MATCHER_INCOMPLETE; // cleanup list_delete(next); - return currbest; + return status; } static void stack_del(void *val) @@ -432,12 +443,12 @@ enum matcher_rv command_complete(struct graph *graph, vector vline, * next = set of all nodes reachable from all nodes in `matched` */ - matcher_rv = idx == vector_active(vline) && next->count - ? MATCHER_OK - : MATCHER_NO_MATCH; + enum matcher_rv mrv = idx == vector_active(vline) && next->count + ? MATCHER_OK + : MATCHER_NO_MATCH; *completions = NULL; - if (!MATCHER_ERROR(matcher_rv)) { + if (!MATCHER_ERROR(mrv)) { // extract cmd_token into list *completions = list_new(); for (ALL_LIST_ELEMENTS_RO(next, node, gstack)) { @@ -448,7 +459,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline, list_delete(current); list_delete(next); - return matcher_rv; + return mrv; } /** diff --git a/lib/compiler.h b/lib/compiler.h new file mode 100644 index 0000000000..49a2f2a422 --- /dev/null +++ b/lib/compiler.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015-2017 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _FRR_COMPILER_H +#define _FRR_COMPILER_H + +/* function attributes, use like + * void prototype(void) __attribute__((_CONSTRUCTOR(100))); + */ +#if defined(__clang__) +# if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5) +# define _RET_NONNULL , returns_nonnull +# endif +# define _CONSTRUCTOR(x) constructor(x) +#elif defined(__GNUC__) +# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) +# define _RET_NONNULL , returns_nonnull +# endif +# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) +# define _CONSTRUCTOR(x) constructor(x) +# define _DESTRUCTOR(x) destructor(x) +# define _ALLOC_SIZE(x) alloc_size(x) +# endif +#endif + +#ifdef __sun +/* Solaris doesn't do constructor priorities due to linker restrictions */ +# undef _CONSTRUCTOR +# undef _DESTRUCTOR +#endif + +/* fallback versions */ +#ifndef _RET_NONNULL +# define _RET_NONNULL +#endif +#ifndef _CONSTRUCTOR +# define _CONSTRUCTOR(x) constructor +#endif +#ifndef _DESTRUCTOR +# define _DESTRUCTOR(x) destructor +#endif +#ifndef _ALLOC_SIZE +# define _ALLOC_SIZE(x) +#endif + +/* + * for warnings on macros, put in the macro content like this: + * #define MACRO BLA CPP_WARN("MACRO has been deprecated") + */ +#define CPP_STR(X) #X + +#if defined(__ICC) +#define CPP_NOTICE(text) _Pragma(CPP_STR(message __FILE__ ": " text)) +#define CPP_WARN(text) CPP_NOTICE(text) + +#elif (defined(__GNUC__) \ + && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \ + || (defined(__clang__) \ + && (__clang_major__ >= 4 \ + || (__clang_major__ == 3 && __clang_minor__ >= 5))) +#define CPP_WARN(text) _Pragma(CPP_STR(GCC warning text)) +#define CPP_NOTICE(text) _Pragma(CPP_STR(message text)) + +#else +#define CPP_WARN(text) +#endif + +#endif /* _FRR_COMPILER_H */ diff --git a/lib/freebsd-queue.h b/lib/freebsd-queue.h new file mode 100644 index 0000000000..d198f5674f --- /dev/null +++ b/lib/freebsd-queue.h @@ -0,0 +1,679 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD$ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_AFTER + - + - + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * _SWAP + + + + + * + */ +#ifdef QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char *lastfile; + int lastline; + char *prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#define QMD_SAVELINK(name, link) void **name = (void *)&(link) + +#define QMD_TRACE_HEAD(head) \ + do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ + } while (0) + +#define QMD_TRACE_ELEM(elem) \ + do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ + } while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define QMD_SAVELINK(name, link) +#define TRACEBUF +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ + struct name { \ + struct type *slh_first; /* first element */ \ + } + +#define SLIST_HEAD_INITIALIZER(head) \ + { \ + NULL \ + } + +#define SLIST_ENTRY(type) \ + struct { \ + struct type *sle_next; /* next element */ \ + } + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) \ + do { \ + SLIST_FIRST((head)) = NULL; \ + } while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) \ + do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ + } while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) \ + do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ + } while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) \ + do { \ + QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_REMOVE_AFTER(curelm, field); \ + } \ + TRASHIT(*oldnext); \ + } while (0) + +#define SLIST_REMOVE_AFTER(elm, field) \ + do { \ + SLIST_NEXT(elm, field) = \ + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ + } while (0) + +#define SLIST_REMOVE_HEAD(head, field) \ + do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ + } while (0) + +#define SLIST_SWAP(head1, head2, type) \ + do { \ + struct type *swap_first = SLIST_FIRST(head1); \ + SLIST_FIRST(head1) = SLIST_FIRST(head2); \ + SLIST_FIRST(head2) = swap_first; \ + } while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ + struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ + } + +#define STAILQ_HEAD_INITIALIZER(head) \ + { \ + NULL, &(head).stqh_first \ + } + +#define STAILQ_ENTRY(type) \ + struct { \ + struct type *stqe_next; /* next element */ \ + } + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) \ + do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ + } while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = STAILQ_FIRST((head)); (var); \ + (var) = STAILQ_NEXT((var), field)) + + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); (var) = (tvar)) + +#define STAILQ_INIT(head) \ + do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ + } while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) \ + do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) \ + == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ + } while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) \ + do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) \ + == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ + } while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) \ + do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + } while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) \ + ? NULL \ + : ((struct type *)(void *)((char *)((head)->stqh_last) \ + - offsetof(struct type, \ + field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) \ + do { \ + QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + STAILQ_REMOVE_AFTER(head, curelm, field); \ + } \ + TRASHIT(*oldnext); \ + } while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) \ + do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) \ + == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + } while (0) + +#define STAILQ_REMOVE_HEAD(head, field) \ + do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) \ + == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ + } while (0) + +#define STAILQ_SWAP(head1, head2, type) \ + do { \ + struct type *swap_first = STAILQ_FIRST(head1); \ + struct type **swap_last = (head1)->stqh_last; \ + STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_FIRST(head2) = swap_first; \ + (head2)->stqh_last = swap_last; \ + if (STAILQ_EMPTY(head1)) \ + (head1)->stqh_last = &STAILQ_FIRST(head1); \ + if (STAILQ_EMPTY(head2)) \ + (head2)->stqh_last = &STAILQ_FIRST(head2); \ + } while (0) + + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ + struct name { \ + struct type *lh_first; /* first element */ \ + } + +#define LIST_HEAD_INITIALIZER(head) \ + { \ + NULL \ + } + +#define LIST_ENTRY(type) \ + struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ + } + +/* + * List functions. + */ + +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_LIST_CHECK_HEAD(head, field) \ + do { \ + if (LIST_FIRST((head)) != NULL \ + && LIST_FIRST((head))->field.le_prev \ + != &LIST_FIRST((head))) \ + panic("Bad list head %p first->prev != head", (head)); \ + } while (0) + +#define QMD_LIST_CHECK_NEXT(elm, field) \ + do { \ + if (LIST_NEXT((elm), field) != NULL \ + && LIST_NEXT((elm), field)->field.le_prev \ + != &((elm)->field.le_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ + } while (0) + +#define QMD_LIST_CHECK_PREV(elm, field) \ + do { \ + if (*(elm)->field.le_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ + } while (0) +#else +#define QMD_LIST_CHECK_HEAD(head, field) +#define QMD_LIST_CHECK_NEXT(elm, field) +#define QMD_LIST_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); (var); (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); (var) = (tvar)) + +#define LIST_INIT(head) \ + do { \ + LIST_FIRST((head)) = NULL; \ + } while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) \ + do { \ + QMD_LIST_CHECK_NEXT(listelm, field); \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) \ + != NULL) \ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ + } while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) \ + do { \ + QMD_LIST_CHECK_PREV(listelm, field); \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ + } while (0) + +#define LIST_INSERT_HEAD(head, elm, field) \ + do { \ + QMD_LIST_CHECK_HEAD((head), field); \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ + } while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) \ + do { \ + QMD_SAVELINK(oldnext, (elm)->field.le_next); \ + QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ + QMD_LIST_CHECK_NEXT(elm, field); \ + QMD_LIST_CHECK_PREV(elm, field); \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ + } while (0) + +#define LIST_SWAP(head1, head2, type, field) \ + do { \ + struct type *swap_tmp = LIST_FIRST((head1)); \ + LIST_FIRST((head1)) = LIST_FIRST((head2)); \ + LIST_FIRST((head2)) = swap_tmp; \ + if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ + if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ + } while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ + struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ + } + +#define TAILQ_HEAD_INITIALIZER(head) \ + { \ + NULL, &(head).tqh_first \ + } + +#define TAILQ_ENTRY(type) \ + struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ + } + +/* + * Tail queue functions. + */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_TAILQ_CHECK_HEAD(head, field) \ + do { \ + if (!TAILQ_EMPTY(head) \ + && TAILQ_FIRST((head))->field.tqe_prev \ + != &TAILQ_FIRST((head))) \ + panic("Bad tailq head %p first->prev != head", \ + (head)); \ + } while (0) + +#define QMD_TAILQ_CHECK_TAIL(head, field) \ + do { \ + if (*(head)->tqh_last != NULL) \ + panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ + } while (0) + +#define QMD_TAILQ_CHECK_NEXT(elm, field) \ + do { \ + if (TAILQ_NEXT((elm), field) != NULL \ + && TAILQ_NEXT((elm), field)->field.tqe_prev \ + != &((elm)->field.tqe_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ + } while (0) + +#define QMD_TAILQ_CHECK_PREV(elm, field) \ + do { \ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ + } while (0) +#else +#define QMD_TAILQ_CHECK_HEAD(head, field) +#define QMD_TAILQ_CHECK_TAIL(head, headname) +#define QMD_TAILQ_CHECK_NEXT(elm, field) +#define QMD_TAILQ_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define TAILQ_CONCAT(head1, head2, field) \ + do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = \ + (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head1); \ + QMD_TRACE_HEAD(head2); \ + } \ + } while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) \ + do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + } while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) \ + do { \ + QMD_TAILQ_CHECK_NEXT(listelm, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) \ + != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ + } while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) \ + do { \ + QMD_TAILQ_CHECK_PREV(listelm, field); \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ + } while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) \ + do { \ + QMD_TAILQ_CHECK_HEAD(head, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ + } while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) \ + do { \ + QMD_TAILQ_CHECK_TAIL(head, field); \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ + } while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) \ + do { \ + QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ + QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ + QMD_TAILQ_CHECK_NEXT(elm, field); \ + QMD_TAILQ_CHECK_PREV(elm, field); \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ + QMD_TRACE_ELEM(&(elm)->field); \ + } while (0) + +#define TAILQ_SWAP(head1, head2, type, field) \ + do { \ + struct type *swap_first = (head1)->tqh_first; \ + struct type **swap_last = (head1)->tqh_last; \ + (head1)->tqh_first = (head2)->tqh_first; \ + (head1)->tqh_last = (head2)->tqh_last; \ + (head2)->tqh_first = swap_first; \ + (head2)->tqh_last = swap_last; \ + if ((swap_first = (head1)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head1)->tqh_first; \ + else \ + (head1)->tqh_last = &(head1)->tqh_first; \ + if ((swap_first = (head2)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head2)->tqh_first; \ + else \ + (head2)->tqh_last = &(head2)->tqh_first; \ + } while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c new file mode 100644 index 0000000000..861f7a5f0c --- /dev/null +++ b/lib/frr_zmq.c @@ -0,0 +1,191 @@ +/* + * libzebra ZeroMQ bindings + * Copyright (C) 2015 David Lamparter + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#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); +} diff --git a/lib/frr_zmq.h b/lib/frr_zmq.h new file mode 100644 index 0000000000..69c6f8580d --- /dev/null +++ b/lib/frr_zmq.h @@ -0,0 +1,88 @@ +/* + * libzebra ZeroMQ bindings + * Copyright (C) 2015 David Lamparter + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _FRRZMQ_H +#define _FRRZMQ_H + +#include "thread.h" +#include + +/* 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 */ diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c index 96ecfa44d3..3c6396f347 100644 --- a/lib/grammar_sandbox.c +++ b/lib/grammar_sandbox.c @@ -404,7 +404,8 @@ DEFUN (grammar_findambig, nodegraph = cnode->cmdgraph; if (!nodegraph) continue; - vty_out(vty, "scanning node %d\n", scannode - 1); + vty_out(vty, "scanning node %d (%s)\n", + scannode - 1, node_names[scannode - 1]); } commands = cmd_graph_permutations(nodegraph); diff --git a/lib/hash.c b/lib/hash.c index 66341cf2f1..243521bef7 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -335,12 +335,13 @@ void hash_free(struct hash *hash) /* CLI commands ------------------------------------------------------------ */ -DEFUN(show_hash_stats, - show_hash_stats_cmd, - "show hashtable [statistics]", - SHOW_STR - "Statistics about hash tables\n" - "Statistics about hash tables\n") +DEFUN_NOSH(show_hash_stats, + show_hash_stats_cmd, + "show debugging hashtable [statistics]", + SHOW_STR + DEBUG_STR + "Statistics about hash tables\n" + "Statistics about hash tables\n") { struct hash *h; struct listnode *ln; diff --git a/lib/hook.c b/lib/hook.c index 2c877cbf45..1468c4d329 100644 --- a/lib/hook.c +++ b/lib/hook.c @@ -26,17 +26,25 @@ DEFINE_MTYPE_STATIC(LIB, HOOK_ENTRY, "Hook entry") void _hook_register(struct hook *hook, void *funcptr, void *arg, bool has_arg, - struct frrmod_runtime *module, const char *funcname) + struct frrmod_runtime *module, const char *funcname, + int priority) { - struct hookent *he = XCALLOC(MTYPE_HOOK_ENTRY, sizeof(*he)); + struct hookent *he = XCALLOC(MTYPE_HOOK_ENTRY, sizeof(*he)), **pos; he->hookfn = funcptr; he->hookarg = arg; he->has_arg = has_arg; he->module = module; he->fnname = funcname; + he->priority = priority; - he->next = hook->entries; - hook->entries = he; + for (pos = &hook->entries; *pos; pos = &(*pos)->next) + if (hook->reverse + ? (*pos)->priority < priority + : (*pos)->priority >= priority) + break; + + he->next = *pos; + *pos = he; } void _hook_unregister(struct hook *hook, void *funcptr, void *arg, bool has_arg) diff --git a/lib/hook.h b/lib/hook.h index 4a5cee2fd3..5f45e113e7 100644 --- a/lib/hook.h +++ b/lib/hook.h @@ -74,6 +74,29 @@ * hook_register_arg (some_update_event, event_handler, addonptr); * * (addonptr isn't typesafe, but that should be manageable.) + * + * Hooks also support a "priority" value for ordering registered calls + * relative to each other. The priority is a signed integer where lower + * values are called earlier. There is also "Koohs", which is hooks with + * reverse priority ordering (for cleanup/deinit hooks, so you can use the + * same priority value). + * + * Recommended priority value ranges are: + * + * -999 ... 0 ... 999 - main executable / daemon, or library + * -1999 ... -1000 - modules registering calls that should run before + * the daemon's bits + * 1000 ... 1999 - modules calls that should run after daemon's + * + * Note: the default value is 1000, based on the following 2 expectations: + * - most hook_register() usage will be in loadable modules + * - usage of hook_register() in the daemon itself may need relative ordering + * to itself, making an explicit value the expected case + * + * The priority value is passed as extra argument on hook_register_prio() / + * hook_register_arg_prio(). Whether a hook runs in reverse is determined + * solely by the code defining / calling the hook. (DECLARE_KOOH is actually + * the same thing as DECLARE_HOOK, it's just there to make it obvious.) */ /* TODO: @@ -94,6 +117,7 @@ struct hookent { void *hookfn; /* actually a function pointer */ void *hookarg; bool has_arg; + int priority; struct frrmod_runtime *module; const char *fnname; }; @@ -101,8 +125,11 @@ struct hookent { struct hook { const char *name; struct hookent *entries; + bool reverse; }; +#define HOOK_DEFAULT_PRIORITY 1000 + /* subscribe/add callback function to a hook * * always use hook_register(), which uses the static inline helper from @@ -110,14 +137,21 @@ struct hook { */ extern void _hook_register(struct hook *hook, void *funcptr, void *arg, bool has_arg, struct frrmod_runtime *module, - const char *funcname); + const char *funcname, int priority); #define hook_register(hookname, func) \ _hook_register(&_hook_##hookname, _hook_typecheck_##hookname(func), \ - NULL, false, THIS_MODULE, #func) + NULL, false, THIS_MODULE, #func, HOOK_DEFAULT_PRIORITY) #define hook_register_arg(hookname, func, arg) \ _hook_register(&_hook_##hookname, \ _hook_typecheck_arg_##hookname(func), arg, true, \ - THIS_MODULE, #func) + THIS_MODULE, #func, HOOK_DEFAULT_PRIORITY) +#define hook_register_prio(hookname, prio, func) \ + _hook_register(&_hook_##hookname, _hook_typecheck_##hookname(func), \ + NULL, false, THIS_MODULE, #func, prio) +#define hook_register_arg_prio(hookname, prio, func, arg) \ + _hook_register(&_hook_##hookname, \ + _hook_typecheck_arg_##hookname(func), \ + arg, true, THIS_MODULE, #func, prio) extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, bool has_arg); @@ -156,12 +190,14 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, { \ return (void *)funcptr; \ } +#define DECLARE_KOOH(hookname, arglist, passlist) \ + DECLARE_HOOK(hookname, arglist, passlist) /* use in source file - contains hook-related definitions. */ -#define DEFINE_HOOK(hookname, arglist, passlist) \ +#define DEFINE_HOOK_INT(hookname, arglist, passlist, rev) \ struct hook _hook_##hookname = { \ - .name = #hookname, .entries = NULL, \ + .name = #hookname, .entries = NULL, .reverse = rev, \ }; \ static int hook_call_##hookname arglist \ { \ @@ -184,4 +220,9 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, return hooksum; \ } +#define DEFINE_HOOK(hookname, arglist, passlist) \ + DEFINE_HOOK_INT(hookname, arglist, passlist, false) +#define DEFINE_KOOH(hookname, arglist, passlist) \ + DEFINE_HOOK_INT(hookname, arglist, passlist, true) + #endif /* _FRR_HOOK_H */ diff --git a/lib/if.c b/lib/if.c index 4e4534851c..43c382beaa 100644 --- a/lib/if.c +++ b/lib/if.c @@ -42,17 +42,12 @@ DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters") DEFINE_QOBJ_TYPE(interface) +DEFINE_HOOK(if_add, (struct interface *ifp), (ifp)) +DEFINE_KOOH(if_del, (struct interface *ifp), (ifp)) + /* List of interfaces in only the default VRF */ int ptm_enable = 0; -/* One for each program. This structure is needed to store hooks. */ -struct if_master { - int (*if_new_hook)(struct interface *); - int (*if_delete_hook)(struct interface *); -} if_master = { - 0, -}; - /* Compare interface names, returning an integer greater than, equal to, or * less than 0, (following the strcmp convention), according to the * relationship between ifp1 and ifp2. Interface names consist of an @@ -150,10 +145,7 @@ struct interface *if_create(const char *name, int namelen, vrf_id_t vrf_id) SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION); QOBJ_REG(ifp, interface); - - if (if_master.if_new_hook) - (*if_master.if_new_hook)(ifp); - + hook_call(if_add, ifp); return ifp; } @@ -182,9 +174,7 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id) /* Delete interface structure. */ void if_delete_retain(struct interface *ifp) { - if (if_master.if_delete_hook) - (*if_master.if_delete_hook)(ifp); - + hook_call(if_del, ifp); QOBJ_UNREG(ifp); /* Free connected address list */ @@ -209,21 +199,6 @@ void if_delete(struct interface *ifp) XFREE(MTYPE_IF, ifp); } -/* Add hook to interface master. */ -void if_add_hook(int type, int (*func)(struct interface *ifp)) -{ - switch (type) { - case IF_NEW_HOOK: - if_master.if_new_hook = func; - break; - case IF_DELETE_HOOK: - if_master.if_delete_hook = func; - break; - default: - break; - } -} - /* Interface existance check by index. */ struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id) { diff --git a/lib/if.h b/lib/if.h index f80ac19179..a592e0ff85 100644 --- a/lib/if.h +++ b/lib/if.h @@ -25,6 +25,7 @@ #include "linklist.h" #include "memory.h" #include "qobj.h" +#include "hook.h" DECLARE_MTYPE(IF) DECLARE_MTYPE(CONNECTED_LABEL) @@ -283,6 +284,17 @@ struct interface { }; DECLARE_QOBJ_TYPE(interface) +/* called from the library code whenever interfaces are created/deleted + * note: interfaces may not be fully realized at that point; also they + * may not exist in the system (ifindex = IFINDEX_INTERNAL) + * + * priority values are important here, daemons should be at 0 while modules + * can use 1000+ so they run after the daemon has initialised daemon-specific + * interface data + */ +DECLARE_HOOK(if_add, (struct interface *ifp), (ifp)) +DECLARE_KOOH(if_del, (struct interface *ifp), (ifp)) + /* Connected address structure. */ struct connected { /* Attached interface. */ @@ -355,10 +367,6 @@ struct nbr_connected { ? (C)->destination \ : (C)->address) -/* Interface hook sort. */ -#define IF_NEW_HOOK 0 -#define IF_DELETE_HOOK 1 - /* There are some interface flags which are only supported by some operating system. */ @@ -442,7 +450,6 @@ extern int if_is_loopback(struct interface *); extern int if_is_broadcast(struct interface *); extern int if_is_pointopoint(struct interface *); extern int if_is_multicast(struct interface *); -extern void if_add_hook(int, int (*)(struct interface *)); extern void if_init(struct list **); extern void if_cmd_init(void); extern void if_terminate(struct list **); diff --git a/lib/imsg-buffer.c b/lib/imsg-buffer.c index a486fc17c1..ae660504e4 100644 --- a/lib/imsg-buffer.c +++ b/lib/imsg-buffer.c @@ -18,7 +18,7 @@ #include -#include "openbsd-queue.h" +#include "queue.h" #include "imsg.h" int ibuf_realloc(struct ibuf *, size_t); diff --git a/lib/imsg.c b/lib/imsg.c index fc62c13734..999ab679b8 100644 --- a/lib/imsg.c +++ b/lib/imsg.c @@ -18,7 +18,7 @@ #include -#include "openbsd-queue.h" +#include "queue.h" #include "imsg.h" int imsg_fd_overhead = 0; diff --git a/lib/libfrr.c b/lib/libfrr.c index a5c87e6edc..9944fdd1e1 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -37,6 +37,8 @@ #include "network.h" DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)) +DEFINE_KOOH(frr_early_fini, (), ()) +DEFINE_KOOH(frr_fini, (), ()) const char frr_sysconfdir[] = SYSCONFDIR; const char frr_vtydir[] = DAEMON_VTY_DIR; @@ -50,6 +52,8 @@ char frr_zclientpath[256]; static char pidfile_default[256]; static char vtypath_default[256]; +bool debug_memstats_at_exit = 0; + static char comb_optstr[256]; static struct option comb_lo[64]; static struct option *comb_next_lo = &comb_lo[0]; @@ -637,7 +641,10 @@ static void frr_daemon_wait(int fd) exit(0); /* child failed one way or another ... */ - if (WIFEXITED(exitstat)) + if (WIFEXITED(exitstat) && WEXITSTATUS(exitstat) == 0) + /* can happen in --terminal case if exit is fast enough */ + (void)0; + else if (WIFEXITED(exitstat)) fprintf(stderr, "%s failed to start, exited %d\n", di->name, WEXITSTATUS(exitstat)); else if (WIFSIGNALED(exitstat)) @@ -831,3 +838,50 @@ void frr_run(struct thread_master *master) while (thread_fetch(master, &thread)) thread_call(&thread); } + +void frr_early_fini(void) +{ + hook_call(frr_early_fini); +} + +void frr_fini(void) +{ + FILE *fp; + char filename[128]; + int have_leftovers; + + hook_call(frr_fini); + + /* memory_init -> nothing needed */ + vty_terminate(); + cmd_terminate(); + zprivs_terminate(di->privs); + /* signal_init -> nothing needed */ + thread_master_free(master); + closezlog(); + /* frrmod_init -> nothing needed / hooks */ + + if (!debug_memstats_at_exit) + return; + + have_leftovers = log_memstats(stderr, di->name); + + /* in case we decide at runtime that we want exit-memstats for + * a daemon, but it has no stderr because it's daemonized + * (only do this if we actually have something to print though) + */ + if (!have_leftovers) + return; + + snprintf(filename, sizeof(filename), + "/tmp/frr-memstats-%s-%llu-%llu", + di->name, + (unsigned long long)getpid(), + (unsigned long long)time(NULL)); + + fp = fopen(filename, "w"); + if (fp) { + log_memstats(fp, di->name); + fclose(fp); + } +} diff --git a/lib/libfrr.h b/lib/libfrr.h index 1710fc9a84..f7d69eecb3 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -104,6 +104,14 @@ extern void frr_run(struct thread_master *master); extern bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len, const char *path); +/* these two are before the protocol daemon does its own shutdown + * it's named this way being the counterpart to frr_late_init */ +DECLARE_KOOH(frr_early_fini, (), ()) +extern void frr_early_fini(void); +/* and these two are after the daemon did its own cleanup */ +DECLARE_KOOH(frr_fini, (), ()) +extern void frr_fini(void); + extern char config_default[256]; extern char frr_zclientpath[256]; extern const char frr_sysconfdir[]; @@ -113,4 +121,6 @@ extern const char frr_moduledir[]; extern char frr_protoname[]; extern char frr_protonameinst[]; +extern bool debug_memstats_at_exit; + #endif /* _ZEBRA_FRR_H */ diff --git a/lib/log.c b/lib/log.c index 5c89e7080e..ea2e804cda 100644 --- a/lib/log.c +++ b/lib/log.c @@ -701,7 +701,7 @@ void _zlog_assert_failed(const char *assertion, const char *file, assertion, file, line, (function ? function : "?")); zlog_backtrace(LOG_CRIT); zlog_thread_info(LOG_CRIT); - log_memstats_stderr("log"); + log_memstats(stderr, "log"); abort(); } @@ -867,6 +867,8 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_INTERFACE_UP), DESC_ENTRY(ZEBRA_INTERFACE_DOWN), DESC_ENTRY(ZEBRA_INTERFACE_SET_MASTER), + DESC_ENTRY(ZEBRA_ROUTE_ADD), + DESC_ENTRY(ZEBRA_ROUTE_DELETE), DESC_ENTRY(ZEBRA_IPV4_ROUTE_ADD), DESC_ENTRY(ZEBRA_IPV4_ROUTE_DELETE), DESC_ENTRY(ZEBRA_IPV6_ROUTE_ADD), @@ -893,10 +895,8 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_BFD_DEST_DEREGISTER), DESC_ENTRY(ZEBRA_BFD_DEST_UPDATE), DESC_ENTRY(ZEBRA_BFD_DEST_REPLAY), - DESC_ENTRY(ZEBRA_REDISTRIBUTE_IPV4_ADD), - DESC_ENTRY(ZEBRA_REDISTRIBUTE_IPV4_DEL), - DESC_ENTRY(ZEBRA_REDISTRIBUTE_IPV6_ADD), - DESC_ENTRY(ZEBRA_REDISTRIBUTE_IPV6_DEL), + DESC_ENTRY(ZEBRA_REDISTRIBUTE_ROUTE_ADD), + DESC_ENTRY(ZEBRA_REDISTRIBUTE_ROUTE_DEL), DESC_ENTRY(ZEBRA_VRF_UNREGISTER), DESC_ENTRY(ZEBRA_VRF_ADD), DESC_ENTRY(ZEBRA_VRF_DELETE), @@ -908,10 +908,6 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_INTERFACE_LINK_PARAMS), DESC_ENTRY(ZEBRA_MPLS_LABELS_ADD), DESC_ENTRY(ZEBRA_MPLS_LABELS_DELETE), - DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_ADD), - DESC_ENTRY(ZEBRA_IPV4_NEXTHOP_DELETE), - DESC_ENTRY(ZEBRA_IPV6_NEXTHOP_ADD), - DESC_ENTRY(ZEBRA_IPV6_NEXTHOP_DELETE), DESC_ENTRY(ZEBRA_IPMR_ROUTE_STATS), DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT), DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK), diff --git a/lib/memory.c b/lib/memory.c index 0ccc204002..c684c7605c 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -104,6 +104,7 @@ int qmem_walk(qmem_walk_fn *func, void *arg) } struct exit_dump_args { + FILE *fp; const char *prefix; int error; }; @@ -113,7 +114,7 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt) struct exit_dump_args *eda = arg; if (!mt) { - fprintf(stderr, + fprintf(eda->fp, "%s: showing active allocations in " "memory group %s\n", eda->prefix, mg->name); @@ -122,15 +123,16 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt) char size[32]; eda->error++; snprintf(size, sizeof(size), "%10zu", mt->size); - fprintf(stderr, "%s: memstats: %-30s: %6zu * %s\n", + fprintf(eda->fp, "%s: memstats: %-30s: %6zu * %s\n", eda->prefix, mt->name, mt->n_alloc, mt->size == SIZE_VAR ? "(variably sized)" : size); } return 0; } -void log_memstats_stderr(const char *prefix) +int log_memstats(FILE *fp, const char *prefix) { - struct exit_dump_args eda = {.prefix = prefix, .error = 0}; + struct exit_dump_args eda = { .fp = fp, .prefix = prefix, .error = 0 }; qmem_walk(qmem_exit_walker, &eda); + return eda.error; } diff --git a/lib/memory.h b/lib/memory.h index d5facad583..6de370514a 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -18,7 +18,9 @@ #define _QUAGGA_MEMORY_H #include +#include #include +#include "compiler.h" #define array_size(ar) (sizeof(ar) / sizeof(ar[0])) @@ -36,41 +38,6 @@ struct memgroup { const char *name; }; -#if defined(__clang__) -#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5) -# define _RET_NONNULL , returns_nonnull -#endif -# define _CONSTRUCTOR(x) constructor(x) -#elif defined(__GNUC__) -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) -# define _RET_NONNULL , returns_nonnull -#endif -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) -# define _CONSTRUCTOR(x) constructor(x) -# define _DESTRUCTOR(x) destructor(x) -# define _ALLOC_SIZE(x) alloc_size(x) -#endif -#endif - -#ifdef __sun -/* Solaris doesn't do constructor priorities due to linker restrictions */ -#undef _CONSTRUCTOR -#undef _DESTRUCTOR -#endif - -#ifndef _RET_NONNULL -# define _RET_NONNULL -#endif -#ifndef _CONSTRUCTOR -# define _CONSTRUCTOR(x) constructor -#endif -#ifndef _DESTRUCTOR -# define _DESTRUCTOR(x) destructor -#endif -#ifndef _ALLOC_SIZE -# define _ALLOC_SIZE(x) -#endif - /* macro usage: * * mydaemon.h @@ -194,7 +161,8 @@ static inline size_t mtype_stats_alloc(struct memtype *mt) * last value from qmem_walk_fn. */ typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt); extern int qmem_walk(qmem_walk_fn *func, void *arg); -extern void log_memstats_stderr(const char *); +extern int log_memstats(FILE *fp, const char *); +#define log_memstats_stderr(prefix) log_memstats(stderr, prefix) extern void memory_oom(size_t size, const char *name); diff --git a/lib/module.c b/lib/module.c index beef791093..b3ab91c4ea 100644 --- a/lib/module.c +++ b/lib/module.c @@ -42,8 +42,10 @@ static struct frrmod_info frrmod_default_info = { .description = "libfrr core module", }; union _frrmod_runtime_u frrmod_default = { - .r.info = &frrmod_default_info, - .r.finished_loading = 1, + .r = { + .info = &frrmod_default_info, + .finished_loading = 1, + }, }; // if defined(HAVE_SYS_WEAK_ALIAS_ATTRIBUTE) diff --git a/lib/mpls.h b/lib/mpls.h index 025770d479..bf98eecd81 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -44,6 +44,9 @@ #define MPLS_DEFAULT_MIN_SRGB_LABEL 16000 #define MPLS_DEFAULT_MAX_SRGB_LABEL 23999 +/* Maximum # labels that can be pushed. */ +#define MPLS_MAX_LABELS 16 + #define IS_MPLS_RESERVED_LABEL(label) \ (label >= MPLS_MIN_RESERVED_LABEL && label <= MPLS_MAX_RESERVED_LABEL) diff --git a/lib/plist.c b/lib/plist.c index b0cf42ca49..ebd628d724 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -122,6 +122,14 @@ const char *prefix_list_name(struct prefix_list *plist) return plist->name; } +afi_t prefix_list_afi(struct prefix_list *plist) +{ + if (plist->master == &prefix_master_ipv4 + || plist->master == &prefix_master_orf_v4) + return AFI_IP; + return AFI_IP6; +} + /* Lookup prefix_list from list of prefix_list by name. */ static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf, const char *name) diff --git a/lib/plist.h b/lib/plist.h index 73d8da509a..3eba3046ae 100644 --- a/lib/plist.h +++ b/lib/plist.h @@ -48,6 +48,7 @@ extern void prefix_list_add_hook(void (*func)(struct prefix_list *)); extern void prefix_list_delete_hook(void (*func)(struct prefix_list *)); extern const char *prefix_list_name(struct prefix_list *); +extern afi_t prefix_list_afi(struct prefix_list *); extern struct prefix_list *prefix_list_lookup(afi_t, const char *); extern enum prefix_list_type prefix_list_apply(struct prefix_list *, void *); diff --git a/lib/prefix.c b/lib/prefix.c index de521b2e3e..10f77bda87 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -497,8 +497,7 @@ int prefix_same(const struct prefix *p1, const struct prefix *p2) if (p1->family == p2->family && p1->prefixlen == p2->prefixlen) { if (p1->family == AF_INET) - if (IPV4_ADDR_SAME(&p1->u.prefix4.s_addr, - &p2->u.prefix4.s_addr)) + if (IPV4_ADDR_SAME(&p1->u.prefix4, &p2->u.prefix4)) return 1; if (p1->family == AF_INET6) if (IPV6_ADDR_SAME(&p1->u.prefix6.s6_addr, @@ -1264,5 +1263,6 @@ unsigned prefix_hash_key(void *pp) * padding and unused prefix bytes. */ memset(©, 0, sizeof(copy)); prefix_copy(©, (struct prefix *)pp); - return jhash(©, sizeof(copy), 0x55aa5a5a); + return jhash(©, offsetof(struct prefix, u.prefix) + + PSIZE(copy.prefixlen), 0x55aa5a5a); } diff --git a/lib/prefix.h b/lib/prefix.h index f0644ea88e..a27f46ba0a 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -33,28 +33,13 @@ #endif #include "sockunion.h" #include "ipaddr.h" +#include "compiler.h" #ifndef ETH_ALEN #define ETH_ALEN 6 #endif /* for compatibility */ -#if defined(__ICC) -#define CPP_WARN_STR(X) #X -#define CPP_WARN(text) _Pragma(CPP_WARN_STR(message __FILE__ ": " text)) - -#elif (defined(__GNUC__) \ - && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \ - || (defined(__clang__) \ - && (__clang_major__ >= 4 \ - || (__clang_major__ == 3 && __clang_minor__ >= 5))) -#define CPP_WARN_STR(X) #X -#define CPP_WARN(text) _Pragma(CPP_WARN_STR(GCC warning text)) - -#else -#define CPP_WARN(text) -#endif - #ifdef ETHER_ADDR_LEN #undef ETHER_ADDR_LEN #endif @@ -140,7 +125,7 @@ struct prefix { struct in_addr adv_router; } lp; struct ethaddr prefix_eth; /* AF_ETHERNET */ - u_char val[8]; + u_char val[16]; uintptr_t ptr; struct evpn_addr prefix_evpn; /* AF_EVPN */ } u __attribute__((aligned(8))); @@ -241,8 +226,20 @@ union prefixconstptr { #define IPV4_MAX_BITLEN 32 #define IPV4_MAX_PREFIXLEN 32 #define IPV4_ADDR_CMP(D,S) memcmp ((D), (S), IPV4_MAX_BYTELEN) -#define IPV4_ADDR_SAME(D,S) (memcmp ((D), (S), IPV4_MAX_BYTELEN) == 0) -#define IPV4_ADDR_COPY(D,S) memcpy ((D), (S), IPV4_MAX_BYTELEN) + +static inline bool ipv4_addr_same(const struct in_addr *a, + const struct in_addr *b) +{ + return (a->s_addr == b->s_addr); +} +#define IPV4_ADDR_SAME(A,B) ipv4_addr_same((A), (B)) + +static inline void ipv4_addr_copy(struct in_addr *dst, + const struct in_addr *src) +{ + dst->s_addr = src->s_addr; +} +#define IPV4_ADDR_COPY(D,S) ipv4_addr_copy((D), (S)) #define IPV4_NET0(a) ((((u_int32_t) (a)) & 0xff000000) == 0x00000000) #define IPV4_NET127(a) ((((u_int32_t) (a)) & 0xff000000) == 0x7f000000) diff --git a/lib/privs.c b/lib/privs.c index eda3fb02d4..cfe7d6d6f8 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -856,7 +856,9 @@ void zprivs_terminate(struct zebra_privs_t *zprivs) } #ifdef HAVE_CAPABILITIES - zprivs_caps_terminate(); + if (zprivs->user || zprivs->group || zprivs->cap_num_p + || zprivs->cap_num_i) + zprivs_caps_terminate(); #else /* !HAVE_CAPABILITIES */ /* only change uid if we don't have the correct one */ if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid)) { diff --git a/lib/queue.h b/lib/queue.h index 658b602ba3..29b67a26e6 100644 --- a/lib/queue.h +++ b/lib/queue.h @@ -1,679 +1,76 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - * $FreeBSD$ - */ - -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ - /* - * This file defines four types of data structures: singly-linked lists, - * singly-linked tail queues, lists and tail queues. + * lists and queues implementations * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. * - * A singly-linked tail queue is headed by a pair of pointers, one to the - * head of the list and the other to the tail of the list. The elements are - * singly linked for minimum space and pointer manipulation overhead at the - * expense of O(n) removal for arbitrary elements. New elements can be added - * to the list after an existing element, at the head of the list, or at the - * end of the list. Elements being removed from the head of the tail queue - * should use the explicit macro for this purpose for optimum efficiency. - * A singly-linked tail queue may only be traversed in the forward direction. - * Singly-linked tail queues are ideal for applications with large datasets - * and few or no removals or for implementing a FIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * For details on the use of these macros, see the queue(3) manual page. - * - * - * SLIST LIST STAILQ TAILQ - * _HEAD + + + + - * _HEAD_INITIALIZER + + + + - * _ENTRY + + + + - * _INIT + + + + - * _EMPTY + + + + - * _FIRST + + + + - * _NEXT + + + + - * _PREV - - - + - * _LAST - - + + - * _FOREACH + + + + - * _FOREACH_SAFE + + + + - * _FOREACH_REVERSE - - - + - * _FOREACH_REVERSE_SAFE - - - + - * _INSERT_HEAD + + + + - * _INSERT_BEFORE - + - + - * _INSERT_AFTER + + + + - * _INSERT_TAIL - - + + - * _CONCAT - - + + - * _REMOVE_AFTER + - + - - * _REMOVE_HEAD + - + - - * _REMOVE + + + + - * _SWAP + + + + + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifdef QUEUE_MACRO_DEBUG -/* Store the last 2 places the queue element or head was altered */ -struct qm_trace { - char *lastfile; - int lastline; - char *prevfile; - int prevline; -}; -#define TRACEBUF struct qm_trace trace; -#define TRASHIT(x) do {(x) = (void *)-1;} while (0) -#define QMD_SAVELINK(name, link) void **name = (void *)&(link) +#ifndef _FRR_QUEUE_H +#define _FRR_QUEUE_H -#define QMD_TRACE_HEAD(head) \ - do { \ - (head)->trace.prevline = (head)->trace.lastline; \ - (head)->trace.prevfile = (head)->trace.lastfile; \ - (head)->trace.lastline = __LINE__; \ - (head)->trace.lastfile = __FILE__; \ - } while (0) +#if defined(__OpenBSD__) && !defined(STAILQ_HEAD) +#include "openbsd-queue.h" -#define QMD_TRACE_ELEM(elem) \ - do { \ - (elem)->trace.prevline = (elem)->trace.lastline; \ - (elem)->trace.prevfile = (elem)->trace.lastfile; \ - (elem)->trace.lastline = __LINE__; \ - (elem)->trace.lastfile = __FILE__; \ - } while (0) - -#else -#define QMD_TRACE_ELEM(elem) -#define QMD_TRACE_HEAD(head) -#define QMD_SAVELINK(name, link) -#define TRACEBUF -#define TRASHIT(x) -#endif /* QUEUE_MACRO_DEBUG */ - -/* - * Singly-linked List declarations. - */ -#define SLIST_HEAD(name, type) \ - struct name { \ - struct type *slh_first; /* first element */ \ - } - -#define SLIST_HEAD_INITIALIZER(head) \ - { \ - NULL \ - } - -#define SLIST_ENTRY(type) \ - struct { \ - struct type *sle_next; /* next element */ \ - } - -/* - * Singly-linked List functions. - */ -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) - -#define SLIST_FIRST(head) ((head)->slh_first) - -#define SLIST_FOREACH(var, head, field) \ - for ((var) = SLIST_FIRST((head)); (var); \ - (var) = SLIST_NEXT((var), field)) - -#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = SLIST_FIRST((head)); \ - (var) && ((tvar) = SLIST_NEXT((var), field), 1); (var) = (tvar)) - -#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ - for ((varp) = &SLIST_FIRST((head)); ((var) = *(varp)) != NULL; \ - (varp) = &SLIST_NEXT((var), field)) - -#define SLIST_INIT(head) \ - do { \ - SLIST_FIRST((head)) = NULL; \ - } while (0) - -#define SLIST_INSERT_AFTER(slistelm, elm, field) \ - do { \ - SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ - SLIST_NEXT((slistelm), field) = (elm); \ - } while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) \ - do { \ - SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ - SLIST_FIRST((head)) = (elm); \ - } while (0) - -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_REMOVE(head, elm, type, field) \ - do { \ - QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ - if (SLIST_FIRST((head)) == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } else { \ - struct type *curelm = SLIST_FIRST((head)); \ - while (SLIST_NEXT(curelm, field) != (elm)) \ - curelm = SLIST_NEXT(curelm, field); \ - SLIST_REMOVE_AFTER(curelm, field); \ - } \ - TRASHIT(*oldnext); \ - } while (0) - -#define SLIST_REMOVE_AFTER(elm, field) \ - do { \ - SLIST_NEXT(elm, field) = \ - SLIST_NEXT(SLIST_NEXT(elm, field), field); \ - } while (0) - -#define SLIST_REMOVE_HEAD(head, field) \ - do { \ - SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ - } while (0) - -#define SLIST_SWAP(head1, head2, type) \ - do { \ - struct type *swap_first = SLIST_FIRST(head1); \ - SLIST_FIRST(head1) = SLIST_FIRST(head2); \ - SLIST_FIRST(head2) = swap_first; \ - } while (0) - -/* - * Singly-linked Tail queue declarations. - */ -#define STAILQ_HEAD(name, type) \ - struct name { \ - struct type *stqh_first; /* first element */ \ - struct type **stqh_last; /* addr of last next element */ \ - } - -#define STAILQ_HEAD_INITIALIZER(head) \ - { \ - NULL, &(head).stqh_first \ - } - -#define STAILQ_ENTRY(type) \ - struct { \ - struct type *stqe_next; /* next element */ \ - } - -/* - * Singly-linked Tail queue functions. - */ -#define STAILQ_CONCAT(head1, head2) \ - do { \ - if (!STAILQ_EMPTY((head2))) { \ - *(head1)->stqh_last = (head2)->stqh_first; \ - (head1)->stqh_last = (head2)->stqh_last; \ - STAILQ_INIT((head2)); \ - } \ - } while (0) - -#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) - -#define STAILQ_FIRST(head) ((head)->stqh_first) - -#define STAILQ_FOREACH(var, head, field) \ - for ((var) = STAILQ_FIRST((head)); (var); \ - (var) = STAILQ_NEXT((var), field)) - - -#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = STAILQ_FIRST((head)); \ - (var) && ((tvar) = STAILQ_NEXT((var), field), 1); (var) = (tvar)) - -#define STAILQ_INIT(head) \ - do { \ - STAILQ_FIRST((head)) = NULL; \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ - } while (0) - -#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) \ - do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) \ - == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_NEXT((tqelm), field) = (elm); \ - } while (0) - -#define STAILQ_INSERT_HEAD(head, elm, field) \ - do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) \ - == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_FIRST((head)) = (elm); \ - } while (0) - -#define STAILQ_INSERT_TAIL(head, elm, field) \ - do { \ - STAILQ_NEXT((elm), field) = NULL; \ - *(head)->stqh_last = (elm); \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - } while (0) +/* Try to map FreeBSD implementation to OpenBSD one. */ +#define STAILQ_HEAD(name, type) SIMPLEQ_HEAD(name, type) +#define STAILQ_HEAD_INITIALIZER(head) SIMPLEQ_HEAD_INITIALIZER(head) +#define STAILQ_ENTRY(entry) SIMPLEQ_ENTRY(entry) +#define STAILQ_CONCAT(head1, head2) SIMPLEQ_CONCAT(head1, head2) +#define STAILQ_EMPTY(head) SIMPLEQ_EMPTY(head) +#define STAILQ_FIRST(head) SIMPLEQ_FIRST(head) +#define STAILQ_FOREACH(var, head, field) SIMPLEQ_FOREACH(var, head, field) +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) +#define STAILQ_INIT(head) SIMPLEQ_INIT(head) +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) SIMPLEQ_INSERT_AFTER(head, tqelm, elm, field) +#define STAILQ_INSERT_HEAD(head, elm, field) SIMPLEQ_INSERT_HEAD(head, elm, field) +#define STAILQ_INSERT_TAIL(head, elm, field) SIMPLEQ_INSERT_TAIL(head, elm, field) #define STAILQ_LAST(head, type, field) \ - (STAILQ_EMPTY((head)) \ + (SIMPLEQ_EMPTY((head)) \ ? NULL \ - : ((struct type *)(void *)((char *)((head)->stqh_last) \ - - __offsetof(struct type, \ + : ((struct type *)(void *)((char *)((head)->sqh_last) \ + - offsetof(struct type, \ field)))) - -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) - +#define STAILQ_NEXT(elm, field) SIMPLEQ_NEXT(elm, field) #define STAILQ_REMOVE(head, elm, type, field) \ do { \ - QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ - if (STAILQ_FIRST((head)) == (elm)) { \ - STAILQ_REMOVE_HEAD((head), field); \ + if (SIMPLEQ_FIRST((head)) == (elm)) { \ + SIMPLEQ_REMOVE_HEAD((head), field); \ } else { \ - struct type *curelm = STAILQ_FIRST((head)); \ - while (STAILQ_NEXT(curelm, field) != (elm)) \ - curelm = STAILQ_NEXT(curelm, field); \ - STAILQ_REMOVE_AFTER(head, curelm, field); \ + struct type *curelm = SIMPLEQ_FIRST((head)); \ + while (SIMPLEQ_NEXT(curelm, field) != (elm)) \ + curelm = SIMPLEQ_NEXT(curelm, field); \ + SIMPLEQ_REMOVE_AFTER(head, curelm, field); \ } \ - TRASHIT(*oldnext); \ } while (0) - -#define STAILQ_REMOVE_AFTER(head, elm, field) \ - do { \ - if ((STAILQ_NEXT(elm, field) = \ - STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) \ - == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - } while (0) - -#define STAILQ_REMOVE_HEAD(head, field) \ - do { \ - if ((STAILQ_FIRST((head)) = \ - STAILQ_NEXT(STAILQ_FIRST((head)), field)) \ - == NULL) \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ - } while (0) - +#define STAILQ_REMOVE_AFTER(head, elm, field) SIMPLEQ_REMOVE_AFTER(head, elm, field) +#define STAILQ_REMOVE_HEAD(head, field) SIMPLEQ_REMOVE_HEAD(head, field) #define STAILQ_SWAP(head1, head2, type) \ do { \ struct type *swap_first = STAILQ_FIRST(head1); \ - struct type **swap_last = (head1)->stqh_last; \ + struct type **swap_last = (head1)->sqh_last; \ STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ - (head1)->stqh_last = (head2)->stqh_last; \ + (head1)->sqh_last = (head2)->sqh_last; \ STAILQ_FIRST(head2) = swap_first; \ - (head2)->stqh_last = swap_last; \ + (head2)->sqh_last = swap_last; \ if (STAILQ_EMPTY(head1)) \ - (head1)->stqh_last = &STAILQ_FIRST(head1); \ + (head1)->sqh_last = &STAILQ_FIRST(head1); \ if (STAILQ_EMPTY(head2)) \ - (head2)->stqh_last = &STAILQ_FIRST(head2); \ - } while (0) - - -/* - * List declarations. - */ -#define LIST_HEAD(name, type) \ - struct name { \ - struct type *lh_first; /* first element */ \ - } - -#define LIST_HEAD_INITIALIZER(head) \ - { \ - NULL \ - } - -#define LIST_ENTRY(type) \ - struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ - } - -/* - * List functions. - */ - -#if (defined(_KERNEL) && defined(INVARIANTS)) -#define QMD_LIST_CHECK_HEAD(head, field) \ - do { \ - if (LIST_FIRST((head)) != NULL \ - && LIST_FIRST((head))->field.le_prev \ - != &LIST_FIRST((head))) \ - panic("Bad list head %p first->prev != head", (head)); \ - } while (0) - -#define QMD_LIST_CHECK_NEXT(elm, field) \ - do { \ - if (LIST_NEXT((elm), field) != NULL \ - && LIST_NEXT((elm), field)->field.le_prev \ - != &((elm)->field.le_next)) \ - panic("Bad link elm %p next->prev != elm", (elm)); \ - } while (0) - -#define QMD_LIST_CHECK_PREV(elm, field) \ - do { \ - if (*(elm)->field.le_prev != (elm)) \ - panic("Bad link elm %p prev->next != elm", (elm)); \ + (head2)->sqh_last = &STAILQ_FIRST(head2); \ } while (0) #else -#define QMD_LIST_CHECK_HEAD(head, field) -#define QMD_LIST_CHECK_NEXT(elm, field) -#define QMD_LIST_CHECK_PREV(elm, field) -#endif /* (_KERNEL && INVARIANTS) */ +#include "freebsd-queue.h" +#endif /* defined(__OpenBSD__) && !defined(STAILQ_HEAD) */ -#define LIST_EMPTY(head) ((head)->lh_first == NULL) - -#define LIST_FIRST(head) ((head)->lh_first) - -#define LIST_FOREACH(var, head, field) \ - for ((var) = LIST_FIRST((head)); (var); (var) = LIST_NEXT((var), field)) - -#define LIST_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = LIST_FIRST((head)); \ - (var) && ((tvar) = LIST_NEXT((var), field), 1); (var) = (tvar)) - -#define LIST_INIT(head) \ - do { \ - LIST_FIRST((head)) = NULL; \ - } while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) \ - do { \ - QMD_LIST_CHECK_NEXT(listelm, field); \ - if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) \ - != NULL) \ - LIST_NEXT((listelm), field)->field.le_prev = \ - &LIST_NEXT((elm), field); \ - LIST_NEXT((listelm), field) = (elm); \ - (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ - } while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) \ - do { \ - QMD_LIST_CHECK_PREV(listelm, field); \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - LIST_NEXT((elm), field) = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ - } while (0) - -#define LIST_INSERT_HEAD(head, elm, field) \ - do { \ - QMD_LIST_CHECK_HEAD((head), field); \ - if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ - LIST_FIRST((head))->field.le_prev = \ - &LIST_NEXT((elm), field); \ - LIST_FIRST((head)) = (elm); \ - (elm)->field.le_prev = &LIST_FIRST((head)); \ - } while (0) - -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_REMOVE(elm, field) \ - do { \ - QMD_SAVELINK(oldnext, (elm)->field.le_next); \ - QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ - QMD_LIST_CHECK_NEXT(elm, field); \ - QMD_LIST_CHECK_PREV(elm, field); \ - if (LIST_NEXT((elm), field) != NULL) \ - LIST_NEXT((elm), field)->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = LIST_NEXT((elm), field); \ - TRASHIT(*oldnext); \ - TRASHIT(*oldprev); \ - } while (0) - -#define LIST_SWAP(head1, head2, type, field) \ - do { \ - struct type *swap_tmp = LIST_FIRST((head1)); \ - LIST_FIRST((head1)) = LIST_FIRST((head2)); \ - LIST_FIRST((head2)) = swap_tmp; \ - if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ - swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ - if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ - swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ - } while (0) - -/* - * Tail queue declarations. - */ -#define TAILQ_HEAD(name, type) \ - struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ - TRACEBUF \ - } - -#define TAILQ_HEAD_INITIALIZER(head) \ - { \ - NULL, &(head).tqh_first \ - } - -#define TAILQ_ENTRY(type) \ - struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ - TRACEBUF \ - } - -/* - * Tail queue functions. - */ -#if (defined(_KERNEL) && defined(INVARIANTS)) -#define QMD_TAILQ_CHECK_HEAD(head, field) \ - do { \ - if (!TAILQ_EMPTY(head) \ - && TAILQ_FIRST((head))->field.tqe_prev \ - != &TAILQ_FIRST((head))) \ - panic("Bad tailq head %p first->prev != head", \ - (head)); \ - } while (0) - -#define QMD_TAILQ_CHECK_TAIL(head, field) \ - do { \ - if (*(head)->tqh_last != NULL) \ - panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ - } while (0) - -#define QMD_TAILQ_CHECK_NEXT(elm, field) \ - do { \ - if (TAILQ_NEXT((elm), field) != NULL \ - && TAILQ_NEXT((elm), field)->field.tqe_prev \ - != &((elm)->field.tqe_next)) \ - panic("Bad link elm %p next->prev != elm", (elm)); \ - } while (0) - -#define QMD_TAILQ_CHECK_PREV(elm, field) \ - do { \ - if (*(elm)->field.tqe_prev != (elm)) \ - panic("Bad link elm %p prev->next != elm", (elm)); \ - } while (0) -#else -#define QMD_TAILQ_CHECK_HEAD(head, field) -#define QMD_TAILQ_CHECK_TAIL(head, headname) -#define QMD_TAILQ_CHECK_NEXT(elm, field) -#define QMD_TAILQ_CHECK_PREV(elm, field) -#endif /* (_KERNEL && INVARIANTS) */ - -#define TAILQ_CONCAT(head1, head2, field) \ - do { \ - if (!TAILQ_EMPTY(head2)) { \ - *(head1)->tqh_last = (head2)->tqh_first; \ - (head2)->tqh_first->field.tqe_prev = \ - (head1)->tqh_last; \ - (head1)->tqh_last = (head2)->tqh_last; \ - TAILQ_INIT((head2)); \ - QMD_TRACE_HEAD(head1); \ - QMD_TRACE_HEAD(head2); \ - } \ - } while (0) - -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) - -#define TAILQ_FIRST(head) ((head)->tqh_first) - -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = TAILQ_FIRST((head)); (var); \ - (var) = TAILQ_NEXT((var), field)) - -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = TAILQ_FIRST((head)); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); (var) = (tvar)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = TAILQ_LAST((head), headname); (var); \ - (var) = TAILQ_PREV((var), headname, field)) - -#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ - (var) = (tvar)) - -#define TAILQ_INIT(head) \ - do { \ - TAILQ_FIRST((head)) = NULL; \ - (head)->tqh_last = &TAILQ_FIRST((head)); \ - QMD_TRACE_HEAD(head); \ - } while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) \ - do { \ - QMD_TAILQ_CHECK_NEXT(listelm, field); \ - if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) \ - != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else { \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_HEAD(head); \ - } \ - TAILQ_NEXT((listelm), field) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ - QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&listelm->field); \ - } while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) \ - do { \ - QMD_TAILQ_CHECK_PREV(listelm, field); \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - TAILQ_NEXT((elm), field) = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&listelm->field); \ - } while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) \ - do { \ - QMD_TAILQ_CHECK_HEAD(head, field); \ - if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ - TAILQ_FIRST((head))->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - TAILQ_FIRST((head)) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ - QMD_TRACE_HEAD(head); \ - QMD_TRACE_ELEM(&(elm)->field); \ - } while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) \ - do { \ - QMD_TAILQ_CHECK_TAIL(head, field); \ - TAILQ_NEXT((elm), field) = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - QMD_TRACE_HEAD(head); \ - QMD_TRACE_ELEM(&(elm)->field); \ - } while (0) - -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) - -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) - -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) - -#define TAILQ_REMOVE(head, elm, field) \ - do { \ - QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ - QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ - QMD_TAILQ_CHECK_NEXT(elm, field); \ - QMD_TAILQ_CHECK_PREV(elm, field); \ - if ((TAILQ_NEXT((elm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else { \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - QMD_TRACE_HEAD(head); \ - } \ - *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ - TRASHIT(*oldnext); \ - TRASHIT(*oldprev); \ - QMD_TRACE_ELEM(&(elm)->field); \ - } while (0) - -#define TAILQ_SWAP(head1, head2, type, field) \ - do { \ - struct type *swap_first = (head1)->tqh_first; \ - struct type **swap_last = (head1)->tqh_last; \ - (head1)->tqh_first = (head2)->tqh_first; \ - (head1)->tqh_last = (head2)->tqh_last; \ - (head2)->tqh_first = swap_first; \ - (head2)->tqh_last = swap_last; \ - if ((swap_first = (head1)->tqh_first) != NULL) \ - swap_first->field.tqe_prev = &(head1)->tqh_first; \ - else \ - (head1)->tqh_last = &(head1)->tqh_first; \ - if ((swap_first = (head2)->tqh_first) != NULL) \ - swap_first->field.tqe_prev = &(head2)->tqh_first; \ - else \ - (head2)->tqh_last = &(head2)->tqh_first; \ - } while (0) - -#endif /* !_SYS_QUEUE_H_ */ +#endif /* _FRR_QUEUE_H */ diff --git a/lib/sigevent.c b/lib/sigevent.c index 2a04fa23cb..d55f368dfb 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -245,7 +245,7 @@ core_handler(int signo #endif ); /* dump memory stats on core */ - log_memstats_stderr("core_handler"); + log_memstats(stderr, "core_handler"); abort(); } diff --git a/lib/spf_backoff.c b/lib/spf_backoff.c index d075e70d4e..92b7620eda 100644 --- a/lib/spf_backoff.c +++ b/lib/spf_backoff.c @@ -226,8 +226,9 @@ void spf_backoff_show(struct spf_backoff *backoff, struct vty *vty, if (backoff->t_holddown) { struct timeval remain = thread_timer_remain(backoff->t_holddown); - vty_out(vty, "%s Still runs for %ld msec\n", - prefix, remain.tv_sec * 1000 + remain.tv_usec / 1000); + vty_out(vty, "%s Still runs for %lld msec\n", + prefix, (long long)remain.tv_sec * 1000 + + remain.tv_usec / 1000); } else { vty_out(vty, "%s Inactive\n", prefix); } @@ -237,8 +238,9 @@ void spf_backoff_show(struct spf_backoff *backoff, struct vty *vty, if (backoff->t_timetolearn) { struct timeval remain = thread_timer_remain(backoff->t_timetolearn); - vty_out(vty, "%s Still runs for %ld msec\n", - prefix, remain.tv_sec * 1000 + remain.tv_usec / 1000); + vty_out(vty, "%s Still runs for %lld msec\n", + prefix, (long long)remain.tv_sec * 1000 + + remain.tv_usec / 1000); } else { vty_out(vty, "%s Inactive\n", prefix); } diff --git a/lib/subdir.am b/lib/subdir.am index 6a62cbb678..5f38cc7a14 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -85,11 +85,13 @@ pkginclude_HEADERS += \ lib/command.h \ lib/command_graph.h \ lib/command_match.h \ + lib/compiler.h \ lib/csv.h \ lib/distribute.h \ lib/event_counter.h \ lib/fifo.h \ lib/filter.h \ + lib/freebsd-queue.h \ lib/frr_pthread.h \ lib/frratomic.h \ lib/getopt.h \ @@ -125,6 +127,7 @@ pkginclude_HEADERS += \ lib/ptm_lib.h \ lib/pw.h \ lib/qobj.h \ + lib/queue.h \ lib/routemap.h \ lib/sbuf.h \ lib/sha256.h \ @@ -180,6 +183,21 @@ lib_libfrrsnmp_la_SOURCES = \ lib/snmp.c \ # end +# +# ZeroMQ support +# +if ZEROMQ +lib_LTLIBRARIES += lib/libfrrzmq.la +pkginclude_HEADERS += lib/frr_zmq.h +endif + +lib_libfrrzmq_la_CFLAGS = $(WERROR) $(ZEROMQ_CFLAGS) +lib_libfrrzmq_la_LDFLAGS = -version-info 0:0:0 +lib_libfrrzmq_la_LIBADD = lib/libfrr.la $(ZEROMQ_LIBS) +lib_libfrrzmq_la_SOURCES = \ + lib/frr_zmq.c \ + #end + # # CLI utilities # @@ -222,7 +240,6 @@ EXTRA_DIST += \ lib/command_lex.h \ lib/command_parse.h \ lib/gitversion.pl \ - lib/queue.h \ lib/route_types.pl \ lib/route_types.txt \ # end diff --git a/lib/table.c b/lib/table.c index 833adb9a37..67cf6aeec3 100644 --- a/lib/table.c +++ b/lib/table.c @@ -31,7 +31,6 @@ DEFINE_MTYPE(LIB, ROUTE_TABLE, "Route table") DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node") -static void route_node_delete(struct route_node *); static void route_table_free(struct route_table *); static int route_table_hash_cmp(const void *a, const void *b) @@ -187,23 +186,6 @@ static void set_link(struct route_node *node, struct route_node *new) new->parent = node; } -/* Lock node. */ -struct route_node *route_lock_node(struct route_node *node) -{ - node->lock++; - return node; -} - -/* Unlock node. */ -void route_unlock_node(struct route_node *node) -{ - assert(node->lock > 0); - node->lock--; - - if (node->lock == 0) - route_node_delete(node); -} - /* Find matched prefix. */ struct route_node *route_node_match(const struct route_table *table, union prefixconstptr pu) @@ -348,7 +330,7 @@ struct route_node *route_node_get(struct route_table *const table, } /* Delete node from the routing table. */ -static void route_node_delete(struct route_node *node) +void route_node_delete(struct route_node *node) { struct route_node *child; struct route_node *parent; diff --git a/lib/table.h b/lib/table.h index b7b402a591..9637fec149 100644 --- a/lib/table.h +++ b/lib/table.h @@ -182,7 +182,6 @@ route_table_init_with_delegate(route_table_delegate_t *); extern route_table_delegate_t *route_table_get_default_delegate(void); extern void route_table_finish(struct route_table *); -extern void route_unlock_node(struct route_node *node); extern struct route_node *route_top(struct route_table *); extern struct route_node *route_next(struct route_node *); extern struct route_node *route_next_until(struct route_node *, @@ -193,7 +192,6 @@ extern struct route_node *route_node_lookup(const struct route_table *, union prefixconstptr); extern struct route_node *route_node_lookup_maynull(const struct route_table *, union prefixconstptr); -extern struct route_node *route_lock_node(struct route_node *node); extern struct route_node *route_node_match(const struct route_table *, union prefixconstptr); extern struct route_node *route_node_match_ipv4(const struct route_table *, @@ -205,6 +203,7 @@ extern unsigned long route_table_count(const struct route_table *); extern struct route_node *route_node_create(route_table_delegate_t *, struct route_table *); +extern void route_node_delete(struct route_node *); extern void route_node_destroy(route_table_delegate_t *, struct route_table *, struct route_node *); @@ -225,6 +224,23 @@ extern void route_table_iter_cleanup(route_table_iter_t *iter); * Inline functions. */ +/* Lock node. */ +static inline struct route_node *route_lock_node(struct route_node *node) +{ + (*(unsigned *)&node->lock)++; + return node; +} + +/* Unlock node. */ +static inline void route_unlock_node(struct route_node *node) +{ + assert(node->lock > 0); + (*(unsigned *)&node->lock)--; + + if (node->lock == 0) + route_node_delete(node); +} + /* * route_table_iter_next * diff --git a/lib/termtable.c b/lib/termtable.c index f7aec43118..ba85962cc9 100644 --- a/lib/termtable.c +++ b/lib/termtable.c @@ -31,48 +31,60 @@ struct ttable_style ttable_styles[] = { .corner = '+', .rownums_on = false, .indent = 1, - .border.top = '-', - .border.bottom = '-', - .border.left = '|', - .border.right = '|', - .border.top_on = true, - .border.bottom_on = true, - .border.left_on = true, - .border.right_on = true, - .cell.lpad = 1, - .cell.rpad = 1, - .cell.align = LEFT, - .cell.border.bottom = '-', - .cell.border.bottom_on = true, - .cell.border.top = '-', - .cell.border.top_on = false, - .cell.border.right = '|', - .cell.border.right_on = true, - .cell.border.left = '|', - .cell.border.left_on = false, + .border = { + .top = '-', + .bottom = '-', + .left = '|', + .right = '|', + .top_on = true, + .bottom_on = true, + .left_on = true, + .right_on = true, + }, + .cell = { + .lpad = 1, + .rpad = 1, + .align = LEFT, + .border = { + .bottom = '-', + .bottom_on = true, + .top = '-', + .top_on = false, + .right = '|', + .right_on = true, + .left = '|', + .left_on = false, + }, + }, }, { // blank, suitable for plaintext alignment .corner = ' ', .rownums_on = false, .indent = 1, - .border.top = ' ', - .border.bottom = ' ', - .border.left = ' ', - .border.right = ' ', - .border.top_on = false, - .border.bottom_on = false, - .border.left_on = false, - .border.right_on = false, - .cell.lpad = 0, - .cell.rpad = 3, - .cell.align = LEFT, - .cell.border.bottom = ' ', - .cell.border.bottom_on = false, - .cell.border.top = ' ', - .cell.border.top_on = false, - .cell.border.right = ' ', - .cell.border.right_on = false, - .cell.border.left = ' ', - .cell.border.left_on = false, + .border = { + .top = ' ', + .bottom = ' ', + .left = ' ', + .right = ' ', + .top_on = false, + .bottom_on = false, + .left_on = false, + .right_on = false, + }, + .cell = { + .lpad = 0, + .rpad = 3, + .align = LEFT, + .border = { + .bottom = ' ', + .bottom_on = false, + .top = ' ', + .top_on = false, + .right = ' ', + .right_on = false, + .left = ' ', + .left_on = false, + }, + } } }; /* clang-format on */ diff --git a/lib/vty.h b/lib/vty.h index dcb8da225d..9acd62af3c 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -25,6 +25,7 @@ #include "log.h" #include "sockunion.h" #include "qobj.h" +#include "compiler.h" #define VTY_BUFSIZ 4096 #define VTY_MAXHIST 20 @@ -182,23 +183,11 @@ struct vty_arg { /* 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.") diff --git a/lib/workqueue.c b/lib/workqueue.c index 612421c80b..b76b73b367 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -72,14 +72,7 @@ struct work_queue *work_queue_new(struct thread_master *m, 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); @@ -97,8 +90,6 @@ void work_queue_free(struct work_queue *wq) 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); @@ -114,8 +105,8 @@ bool work_queue_is_scheduled(struct work_queue *wq) 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); @@ -139,33 +130,35 @@ void work_queue_add(struct work_queue *wq, void *data) } 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, @@ -186,7 +179,7 @@ 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) @@ -233,16 +226,15 @@ void work_queue_unplug(struct work_queue *wq) 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 @@ -266,7 +258,7 @@ int work_queue_run(struct thread *thread) 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 */ @@ -274,7 +266,7 @@ int work_queue_run(struct thread *thread) /* 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; } @@ -298,7 +290,7 @@ int work_queue_run(struct thread *thread) } 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 @@ -309,8 +301,8 @@ int work_queue_run(struct thread *thread) * 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: @@ -323,7 +315,7 @@ int work_queue_run(struct thread *thread) /* fallthru */ case WQ_SUCCESS: default: { - work_queue_item_remove(wq, node); + work_queue_item_remove(wq, item); break; } } @@ -376,7 +368,7 @@ stats: #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); diff --git a/lib/workqueue.h b/lib/workqueue.h index ff7f57690d..df35d44fbc 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -24,6 +24,7 @@ #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 */ @@ -43,6 +44,7 @@ typedef enum { /* 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 */ }; @@ -91,7 +93,8 @@ struct work_queue { } 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 */ @@ -107,6 +110,37 @@ struct work_queue { /* 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 diff --git a/lib/zclient.c b/lib/zclient.c index 24cb699196..72fa2679b3 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -352,10 +352,6 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id) int i; afi_t afi; - /* zclient is disabled. */ - if (!zclient->enable) - return; - /* If not connected to the zebra yet. */ if (zclient->sock < 0) return; @@ -418,10 +414,6 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id) int i; afi_t afi; - /* zclient is disabled. */ - if (!zclient->enable) - return; - /* If not connected to the zebra yet. */ if (zclient->sock < 0) return; @@ -485,10 +477,6 @@ void zclient_send_interface_radv_req(struct zclient *zclient, vrf_id_t vrf_id, { struct stream *s; - /* zclient is disabled. */ - if (!zclient->enable) - return; - /* If not connected to the zebra yet. */ if (zclient->sock < 0) return; @@ -516,10 +504,6 @@ int zclient_start(struct zclient *zclient) 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; @@ -564,9 +548,6 @@ void zclient_init(struct zclient *zclient, int redist_default, u_short instance) { int afi, i; - /* Enable zebra client connection by default. */ - zclient->enable = 1; - /* Set -1 to the default socket value. */ zclient->sock = -1; @@ -911,24 +892,23 @@ int zapi_ipv6_route(u_char cmd, struct zclient *zclient, struct prefix_ipv6 *p, 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); @@ -936,72 +916,84 @@ int zapi_route(u_char cmd, struct zclient *zclient, struct prefix *p, 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)) @@ -1014,7 +1006,110 @@ int zapi_route(u_char cmd, struct zclient *zclient, struct prefix *p, /* 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; } /* @@ -2017,25 +2112,15 @@ static int zclient_read(struct thread *thread) (*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) diff --git a/lib/zclient.h b/lib/zclient.h index 15d1858d84..7c4780201e 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -21,7 +21,7 @@ #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. */ @@ -59,6 +59,8 @@ typedef enum { 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, @@ -85,10 +87,8 @@ typedef enum { 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, @@ -100,10 +100,6 @@ typedef enum { 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, @@ -141,10 +137,6 @@ struct zclient { /* 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; @@ -194,14 +186,10 @@ struct zclient { 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); @@ -212,13 +200,12 @@ struct zclient { /* 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 { @@ -232,6 +219,16 @@ 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; @@ -242,8 +239,11 @@ struct zapi_route { 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; @@ -369,7 +369,7 @@ extern struct interface *zebra_interface_vrf_update_read(struct stream *s, 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 *, @@ -420,11 +420,13 @@ struct zapi_ipv6 { 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 */ diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index 58ad167549..a46962c91a 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -48,8 +48,8 @@ static int nhrp_if_delete_hook(struct interface *ifp) 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) diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index 012d5cd87c..3a7186c1d7 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -81,6 +81,7 @@ static void nhrp_sigusr1(void) static void nhrp_request_stop(void) { debugf(NHRP_DEBUG_COMMON, "Exiting..."); + frr_early_fini(); nhrp_shortcut_terminate(); nhrp_nhs_terminate(); @@ -89,15 +90,9 @@ static void nhrp_request_stop(void) 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); } diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index 76c591fd79..0bada33502 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -171,7 +171,7 @@ static int nhrp_reg_send_req(struct thread *t) 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); diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index c8a608c657..4b86bca5f7 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -86,14 +86,20 @@ void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp) 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: @@ -102,158 +108,106 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix * 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); + SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL); - if (p->family == AF_INET) { - struct in_addr *nexthop_ipv4; - struct zapi_ipv4 api; + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api_nh = &api.nexthops[0]; - memset(&api, 0, sizeof(api)); - api.flags = flags; - api.type = ZEBRA_ROUTE_NHRP; - api.safi = SAFI_UNICAST; - - 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])) : "", - 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; + 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; } - 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])) : "", - api.metric, api.nexthop_num, ifp->name); - } - - zapi_ipv6_route( - add ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE, - zclient, (struct prefix_ipv6 *) p, NULL, &api); + break; } + if (mtu) { + SET_FLAG(api.message, ZAPI_MESSAGE_MTU); + api.mtu = mtu; + } + + if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) { + char buf[2][PREFIX_STRLEN]; + + 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])) : "", + 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; - s = zclient->ibuf; - memset(&prefix, 0, sizeof(prefix)); - sockunion_family(&nexthop_addr) = AF_UNSPEC; - - /* 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: + if (zapi_route_decode(zclient->ibuf, &api) < 0) 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); - } - } - if (CHECK_FLAG(message, ZAPI_MESSAGE_DISTANCE)) - /*distance =*/ stream_getc(s); - if (CHECK_FLAG(message, ZAPI_MESSAGE_METRIC)) - /*metric =*/ stream_getl(s); + /* we completely ignore srcdest routes for now. */ + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) + return 0; - added = (cmd == ZEBRA_REDISTRIBUTE_IPV4_ADD || cmd == ZEBRA_REDISTRIBUTE_IPV6_ADD); + sockunion_family(&nexthop_addr) = AF_UNSPEC; + if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { + api_nh = &api.nexthops[0]; + + 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); + } + + 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; } @@ -366,10 +320,8 @@ void nhrp_zebra_init(void) 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); } @@ -381,4 +333,3 @@ void nhrp_zebra_terminate(void) route_table_finish(zebra_rib[AFI_IP]); route_table_finish(zebra_rib[AFI_IP6]); } - diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index 20ef17de00..6d78fc1d2b 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -110,11 +110,11 @@ static int toggle_flag( #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; diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index f198ac4af6..36528d063c 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -386,27 +386,20 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, } /* 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 */ @@ -873,22 +866,16 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) } /* 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 diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index a4cc0bf420..649d7a1000 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -45,6 +45,8 @@ #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; @@ -579,17 +581,15 @@ DEFUN (area_filter_list, 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); } @@ -622,27 +622,34 @@ DEFUN (no_area_filter_list, 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", diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index 4bc24a6dd8..d212d92387 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -122,6 +122,7 @@ extern void ospf6_area_disable(struct ospf6_area *); 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); diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 1d17a1c233..bb63fb966e 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -1171,8 +1171,7 @@ DEFUN (ipv6_ospf6_cost, 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; @@ -1206,12 +1205,12 @@ DEFUN (ipv6_ospf6_cost, 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; @@ -1292,8 +1291,7 @@ DEFUN (ipv6_ospf6_hellointerval, IP6_STR OSPF6_STR "Time between HELLO packets\n" - SECONDS_STR - ) + SECONDS_STR) { VTY_DECLVAR_CONTEXT(interface, ifp); int idx_number = 3; @@ -1305,10 +1303,21 @@ DEFUN (ipv6_ospf6_hellointerval, 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, @@ -1316,8 +1325,7 @@ DEFUN (ipv6_ospf6_deadinterval, 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; @@ -1329,10 +1337,21 @@ DEFUN (ipv6_ospf6_deadinterval, 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, @@ -1352,10 +1371,21 @@ DEFUN (ipv6_ospf6_transmitdelay, 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, @@ -1363,8 +1393,7 @@ DEFUN (ipv6_ospf6_retransmitinterval, 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; @@ -1376,10 +1405,21 @@ DEFUN (ipv6_ospf6_retransmitinterval, 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, @@ -1387,8 +1427,7 @@ DEFUN (ipv6_ospf6_priority, IP6_STR OSPF6_STR "Router priority\n" - "Priority value\n" - ) + "Priority value\n") { VTY_DECLVAR_CONTEXT(interface, ifp); int idx_number = 3; @@ -1400,7 +1439,9 @@ DEFUN (ipv6_ospf6_priority, 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 @@ -1410,14 +1451,22 @@ DEFUN (ipv6_ospf6_priority, 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; @@ -1429,10 +1478,21 @@ DEFUN (ipv6_ospf6_instance, 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", @@ -1576,13 +1636,13 @@ DEFUN (ipv6_ospf6_advertise_prefix_list, 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; @@ -1593,10 +1653,8 @@ DEFUN (no_ipv6_ospf6_advertise_prefix_list, 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); @@ -1654,11 +1712,13 @@ DEFUN (ipv6_ospf6_network, DEFUN (no_ipv6_ospf6_network, no_ipv6_ospf6_network_cmd, - "no ipv6 ospf6 network", + "no ipv6 ospf6 network []", 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; @@ -1772,12 +1832,19 @@ void ospf6_interface_init(void) 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); diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 28bb956c40..e582737f94 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -82,6 +82,8 @@ static void __attribute__((noreturn)) ospf6_exit(int status) struct listnode *node; struct interface *ifp; + frr_early_fini(); + if (ospf6) ospf6_delete(ospf6); @@ -96,19 +98,13 @@ static void __attribute__((noreturn)) ospf6_exit(int status) 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); } diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index bfe583a911..e58eab2b15 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -285,8 +285,7 @@ void ospf6_add_nexthop(struct list *nh_list, int ifindex, struct in6_addr *addr) } 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; @@ -306,13 +305,16 @@ void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route, 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++; } } } diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index 166074fb70..9eacadbdb7 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -22,6 +22,7 @@ #define OSPF6_ROUTE_H #include "command.h" +#include "zclient.h" #define OSPF6_MULTI_PATH_LIMIT 4 @@ -266,8 +267,7 @@ extern int ospf6_num_nexthops(struct list *nh_list); 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); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 387690bc8a..dc5792aa17 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -308,19 +308,24 @@ DEFUN (no_router_ospf6, /* 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; } @@ -331,6 +336,40 @@ DEFUN (ospf6_router_id, 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", @@ -974,7 +1013,7 @@ static int config_write_ospf6(struct vty *vty) 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)) { @@ -1032,6 +1071,9 @@ void ospf6_top_init(void) 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); diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index d33f41730e..3443bc47b6 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -207,75 +207,30 @@ static int ospf6_zebra_if_address_update_delete(int command, 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)); + if (zapi_route_decode(zclient->ibuf, &api) < 0) + return -1; - /* Type, flags, message. */ - api.type = stream_getc(s); - api.instance = stream_getw(s); - api.flags = stream_getl(s); - api.message = stream_getc(s); - - /* 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 (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)); @@ -284,20 +239,17 @@ static int ospf6_zebra_read_ipv6(int command, struct zclient *zclient, 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; } @@ -317,7 +269,7 @@ DEFUN (show_zebra, } 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:"); @@ -329,38 +281,15 @@ DEFUN (show_zebra, 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)); @@ -408,36 +337,16 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request) 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); @@ -446,195 +355,99 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request) 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; + struct zapi_route api; char buf[INET6_ADDRSTRLEN]; - struct prefix_ipv6 *dest; + struct prefix *dest = &request->prefix; - 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; + 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; - dest = (struct prefix_ipv6 *)&request->prefix; + zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); - 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->u.prefix6, buf, + INET6_ADDRSTRLEN), + dest->prefixlen); - 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); - } + 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); } } 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; + struct prefix *dest = &request->prefix; - 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; + 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; - dest = (struct prefix_ipv6 *)&request->prefix; + zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); - 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->u.prefix6, buf, + INET6_ADDRSTRLEN), + dest->prefixlen); - 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); - } + 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); } } -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); - - if (ospf6 == NULL) - return CMD_SUCCESS; - - /* 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); - - ospf6->route_table->hook_add = ospf6_zebra_route_update_add; - ospf6->route_table->hook_remove = ospf6_zebra_route_update_remove; - - return CMD_SUCCESS; -} - -DEFUN (no_redistribute_ospf6, - no_redistribute_ospf6_cmd, - "no redistribute ospf6", - NO_STR - "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_unset(zclient->redist[AFI_IP6][ZEBRA_ROUTE_OSPF6], - VRF_DEFAULT); - - 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); - - return CMD_SUCCESS; -} - static struct ospf6_distance *ospf6_distance_new(void) { return XCALLOC(MTYPE_OSPF6_DISTANCE, sizeof(struct ospf6_distance)); @@ -785,24 +598,11 @@ void ospf6_zebra_init(struct thread_master *master) 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 */ diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index 6b47fca578..84a56fb505 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -24,6 +24,7 @@ #include "linklist.h" #include "vty.h" #include "command.h" +#include "plist.h" #include "ospf6_proto.h" #include "ospf6_network.h" @@ -44,8 +45,6 @@ #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; @@ -70,21 +69,6 @@ struct route_node *route_prev(struct route_node *node) 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 */ }; @@ -102,10 +86,24 @@ static int config_write_ospf6_debug(struct vty *vty) 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 \ @@ -1142,6 +1140,20 @@ DEFUN (show_ipv6_ospf6_linkstate_detail, 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) { @@ -1157,6 +1169,9 @@ 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); @@ -1174,7 +1189,7 @@ void ospf6_init(void) 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); diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h index 1515c3ad0c..77a40eac63 100644 --- a/ospf6d/ospf6d.h +++ b/ospf6d/ospf6d.h @@ -21,8 +21,6 @@ #ifndef OSPF6D_H #define OSPF6D_H -#define OSPF6_DAEMON_VERSION "0.9.7r" - #include "libospf.h" #include "thread.h" diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index d3d1ffed5e..619bd4e5f5 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -1597,12 +1597,12 @@ static int show_debugging_ospf_common(struct vty *vty, struct ospf *ospf) 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; @@ -1612,13 +1612,13 @@ DEFUN (show_debugging_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; diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 4ea8ec26f2..54639afd6c 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -1163,6 +1163,6 @@ void ospf_if_init() { /* 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); } diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index ac2406ec2d..36f9a6757a 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -3938,7 +3938,7 @@ void ospf_ls_upd_send(struct ospf_neighbor *nbr, struct list *update, int flag) 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."); } diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index d9354e0cb1..c52790a839 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -1897,7 +1897,8 @@ DEFUN (no_ospf_area_filter_list, DEFUN (ospf_area_authentication_message_digest, ospf_area_authentication_message_digest_cmd, - "area authentication message-digest", + "[no] area 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" @@ -1914,7 +1915,7 @@ DEFUN (ospf_area_authentication_message_digest, 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; } @@ -2267,7 +2268,9 @@ DEFUN (no_ospf_timers_lsa_min_arrival, 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)", @@ -2276,7 +2279,9 @@ ALIAS_HIDDEN (ospf_timers_lsa_min_arrival, "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)", @@ -4032,12 +4037,13 @@ DEFUN (show_ip_ospf_neighbor_int, 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, @@ -4052,6 +4058,7 @@ 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); @@ -4064,7 +4071,7 @@ DEFUN (show_ip_ospf_instance_neighbor_int, 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, @@ -4422,12 +4429,13 @@ DEFUN (show_ip_ospf_neighbor_id, 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, @@ -4442,6 +4450,7 @@ 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); @@ -4454,7 +4463,7 @@ DEFUN (show_ip_ospf_instance_neighbor_id, 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, @@ -4725,12 +4734,13 @@ DEFUN (show_ip_ospf_neighbor_int_detail, 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, @@ -4746,6 +4756,7 @@ 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); @@ -4758,7 +4769,7 @@ DEFUN (show_ip_ospf_instance_neighbor_int_detail, 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 */ @@ -6881,10 +6892,12 @@ DEFUN (no_ip_ospf_transmit_delay, 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); } diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index d615afc072..dcb392f1ad 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -333,272 +333,144 @@ static int ospf_interface_link_params(int command, struct zclient *zclient, 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; - 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; + memset(&api, 0, sizeof(api)); + api.vrf_id = VRF_DEFAULT; + api.type = ZEBRA_ROUTE_OSPF; + api.instance = ospf->instance; + api.safi = SAFI_UNICAST; - /* OSPF pass nexthop and metric */ - SET_FLAG(message, ZAPI_MESSAGE_NEXTHOP); - SET_FLAG(message, ZAPI_MESSAGE_METRIC); + memcpy(&api.prefix, p, sizeof(*p)); + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = or->paths->count; - /* Distance value. */ - distance = ospf_distance_apply(p, or); - if (distance) - SET_FLAG(message, ZAPI_MESSAGE_DISTANCE); + /* 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(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)) { -#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); - } -#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); - } -#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); - } - } - - 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 (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); + /* 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; } + + /* 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)) { +#else /* HAVE_NETLINK */ + if (path->nexthop.s_addr != INADDR_ANY && path->ifindex != 0) { +#endif /* HAVE_NETLINK */ + 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 (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); + } + } + + 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); + 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)); - /* 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); + 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; + 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)); - zapi_ipv4_route(ZEBRA_IPV4_ROUTE_ADD, zclient, p, &api); + 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); - } + 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; + 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)); - zapi_ipv4_route(ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api); + 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); - } + 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) @@ -1001,61 +873,32 @@ void ospf_routemap_unset(struct ospf_redist *red) } /* 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; - - /* 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)); - - 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 (zapi_route_decode(zclient->ibuf, &api) < 0) + return -1; + + 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; + + if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) { /* XXX|HACK|TODO|FIXME: * Maybe we should ignore reject/blackhole routes? Testing shows * that @@ -1070,7 +913,7 @@ static int ospf_zebra_read_ipv4(int command, struct zclient *zclient, * 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]; @@ -1112,7 +955,7 @@ static int ospf_zebra_read_ipv4(int command, struct zclient *zclient, 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( @@ -1122,7 +965,7 @@ static int ospf_zebra_read_ipv4(int command, struct zclient *zclient, } } } - } 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)) @@ -1538,8 +1381,8 @@ void ospf_zebra_init(struct thread_master *master, u_short instance) 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); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index db24aef423..ae509f4a9b 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1666,7 +1666,7 @@ static void pim_show_join_helper(struct vty *vty, 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, @@ -1690,7 +1690,7 @@ static void pim_show_join(struct pim_instance *pim, struct vty *vty, u_char uj) 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; @@ -5066,7 +5066,7 @@ static int pim_rp_cmd_worker(struct pim_instance *pim, struct vty *vty, 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) { @@ -7254,14 +7254,17 @@ DEFUN (no_debug_msdp_packets, 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; } diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 39f5f2cc4b..b5d6f04948 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -42,6 +42,7 @@ #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); @@ -348,7 +349,7 @@ const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state, 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; @@ -356,16 +357,28 @@ const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state, 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; } @@ -628,33 +641,34 @@ static int on_ifjoin_prune_pending_timer(struct thread *t) 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 (!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; + 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); - } - /* 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)) { + rpf.source_nexthop.interface = ifp; + rpf.rpf_addr.u.prefix4 = + pim_ifp->primary_address; + pim_jp_agg_single_upstream_send(&rpf, + ch->upstream, + 0); + } + + 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( @@ -1104,7 +1118,6 @@ void pim_ifchannel_local_membership_del(struct interface *ifp, orig = ch = pim_ifchannel_find(ifp, sg); if (!ch) return; - ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO); if (sg->src.s_addr == INADDR_ANY) { @@ -1311,11 +1324,12 @@ void pim_ifchannel_scan_forward_start(struct interface *new_ifp) * 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( @@ -1326,33 +1340,6 @@ void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom, 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; @@ -1371,8 +1358,30 @@ void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom, 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; } } diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h index cef431c30d..0b1a8ea0e8 100644 --- a/pimd/pim_ifchannel.h +++ b/pimd/pim_ifchannel.h @@ -151,8 +151,7 @@ void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch); void pim_ifchannel_scan_forward_start(struct interface *new_ifp); void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom, - 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); diff --git a/pimd/pim_join.c b/pimd/pim_join.c index c60e5a65aa..4f5e534010 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -231,7 +231,6 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, 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); @@ -289,12 +288,10 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, 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); } } @@ -307,7 +304,6 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, } buf += addr_offset; - starg_alone = 0; recv_prune(ifp, neigh, msg_holdtime, msg_upstream_addr.u.prefix4, &sg, msg_source_flags); @@ -340,8 +336,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, } } 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 */ @@ -419,7 +414,7 @@ int pim_joinprune_send(struct pim_rpf *rpf, struct list *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; diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 751611479e..96b9568c61 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -698,6 +698,8 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, if (up->sources) list_delete(up->sources); + list_delete(up->ifchannels); + hash_release(pim->upstream_hash, up); XFREE(MTYPE_PIM_UPSTREAM, up); return NULL; @@ -1622,8 +1624,9 @@ static void pim_upstream_sg_running(void *arg) // 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; } diff --git a/python/clidef.py b/python/clidef.py index 8e3c7595b7..6a69986323 100644 --- a/python/clidef.py +++ b/python/clidef.py @@ -36,12 +36,14 @@ class RenderHandler(object): 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' @@ -130,6 +132,10 @@ handlers = { } # 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(\\ @@ -140,20 +146,31 @@ DEFUN_CMD_FUNC_DECL($fnname) 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); } @@ -196,6 +213,7 @@ def process_file(fn, ofd, dumpfd, all_defun): arglist = [] argblocks = [] doc = [] + canfail = 0 def do_add(handler, varname, attr = ''): argdefs.append(',\\\n\t%s %s%s' % (handler.argtype, varname, attr)) @@ -213,6 +231,8 @@ def process_file(fn, ofd, dumpfd, all_defun): 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))') @@ -229,6 +249,8 @@ def process_file(fn, ofd, dumpfd, all_defun): 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__': @@ -257,4 +279,4 @@ 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__)]) diff --git a/python/clippy/__init__.py b/python/clippy/__init__.py index 82aa9495d4..41aeae6b4d 100644 --- a/python/clippy/__init__.py +++ b/python/clippy/__init__.py @@ -16,6 +16,7 @@ # 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 @@ -47,7 +48,7 @@ def dump(graph): 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 = '' @@ -57,8 +58,16 @@ def wrdiff(filename, buf): 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) diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 12cdcf04fe..cc0632b562 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -13,7 +13,6 @@ %{!?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 } @@ -221,6 +220,7 @@ developing OSPF-API and frr applications. --libexecdir=%{_libexecdir} \ --localstatedir=%{_localstatedir} \ --disable-werror \ + --enable-irdp \ %if !%{with_shared} --disable-shared \ %endif @@ -238,11 +238,6 @@ developing OSPF-API and frr applications. %else --enable-ospfapi=no \ %endif -%if %{with_irdp} - --enable-irdp=yes \ -%else - --enable-irdp=no \ -%endif %if %{with_rtadv} --enable-rtadv=yes \ %else @@ -325,6 +320,9 @@ rm -rf %{buildroot}/usr/share/info/dir # 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} @@ -554,6 +552,7 @@ rm -rf %{buildroot} %{_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 diff --git a/ripd/rip_debug.c b/ripd/rip_debug.c index 492d036991..56ba8e7f3e 100644 --- a/ripd/rip_debug.c +++ b/ripd/rip_debug.c @@ -27,12 +27,12 @@ unsigned long rip_debug_event = 0; 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"); diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index a170471123..00b6d1cadd 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -1877,8 +1877,8 @@ static int rip_interface_delete_hook(struct interface *ifp) 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); diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 961a846db2..2140e8b110 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -39,155 +39,107 @@ struct zclient *zclient = NULL; /* 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; + memset(&api, 0, sizeof(api)); + api.vrf_id = VRF_DEFAULT; + api.type = ZEBRA_ROUTE_RIP; + 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; - - rinfo = listgetdata(listhead(list)); - - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = rinfo->metric; - - if (rinfo->distance - && rinfo->distance != ZEBRA_RIP_DISTANCE_DEFAULT) { - SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); - api.distance = rinfo->distance; - } - - if (rinfo->tag) { - SET_FLAG(api.message, ZAPI_MESSAGE_TAG); - api.tag = rinfo->tag; - } - - 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); - } - - rip_global_route_changes++; + 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++; } + + api.prefix = rp->p; + api.nexthop_num = count; + + rinfo = listgetdata(listhead(list)); + + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); + api.metric = rinfo->metric; + + if (rinfo->distance && rinfo->distance != ZEBRA_RIP_DISTANCE_DEFAULT) { + SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); + api.distance = rinfo->distance; + } + + if (rinfo->tag) { + SET_FLAG(api.message, ZAPI_MESSAGE_TAG); + api.tag = rinfo->tag; + } + + 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; + if (zapi_route_decode(zclient->ibuf, &api) < 0) + return -1; - /* Type, flags, message. */ - api.type = stream_getc(s); - api.instance = stream_getw(s); - api.flags = stream_getl(s); - api.message = stream_getc(s); - - /* 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; + 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; @@ -298,27 +250,6 @@ void rip_redistribute_clean(void) } } -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, @@ -604,66 +535,46 @@ DEFUN (no_rip_default_information_originate, 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); @@ -681,16 +592,8 @@ void rip_zclient_init(struct thread_master *master) 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); diff --git a/ripngd/ripng_debug.c b/ripngd/ripng_debug.c index d56161d39e..9ebc302b1b 100644 --- a/ripngd/ripng_debug.c +++ b/ripngd/ripng_debug.c @@ -28,12 +28,12 @@ unsigned long ripng_debug_event = 0; 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"); diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index c762d8ace7..02fab68254 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -1121,8 +1121,8 @@ static struct cmd_node interface_node = { 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(); diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index 386bee43b8..283d8691a3 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -39,162 +39,101 @@ struct zclient *zclient = NULL; /* 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; + memset(&api, 0, sizeof(api)); + api.vrf_id = VRF_DEFAULT; + api.type = ZEBRA_ROUTE_RIPNG; + api.safi = SAFI_UNICAST; + api.prefix = rp->p; - 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); + 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); + } - 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); - } + api.nexthop_num = count; - api.nexthop = nexthops; - api.nexthop_num = count; - api.ifindex = ifindexes; - api.ifindex_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; - } + zclient_route_send(cmd, zclient, &api); - 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); - } + 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; + unsigned long ifindex; - s = zclient->ibuf; - ifindex = 0; - memset(&nexthop, 0, sizeof(struct in6_addr)); + if (zapi_route_decode(zclient->ibuf, &api) < 0) + return -1; - /* Type, flags, message. */ - api.type = stream_getc(s); - api.instance = stream_getw(s); - api.flags = stream_getl(s); - api.message = stream_getc(s); - - /* 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. */ + /* 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); - 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; + nexthop = api.nexthops[0].gate.ipv6; + ifindex = api.nexthops[0].ifindex; - if (CHECK_FLAG(api.message, ZAPI_MESSAGE_TAG)) - api.tag = stream_getl(s); - else - api.tag = 0; - - 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; } @@ -294,29 +233,6 @@ void ripng_redistribute_clean() } } -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, @@ -452,64 +368,40 @@ void ripng_redistribute_write(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_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); @@ -529,16 +421,8 @@ void zebra_init(struct thread_master *master) 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); diff --git a/tests/.gitignore b/tests/.gitignore index 604ffaa8b6..41349cce24 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -45,4 +45,5 @@ __pycache__ /lib/test_timer_correctness /lib/test_timer_performance /lib/test_ttable +/lib/test_zmq /ospf6d/test_lsdb diff --git a/tests/Makefile.am b/tests/Makefile.am index 59ea3c4c69..8a8918dcb4 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -72,6 +72,12 @@ check_PROGRAMS = \ $(TESTS_OSPF6D) \ # end +if ZEROMQ +check_PROGRAMS += \ + lib/test_zmq \ + # end +endif + ../vtysh/vtysh_cmd.c: $(MAKE) -C ../vtysh vtysh_cmd.c @@ -112,6 +118,8 @@ lib_test_timer_correctness_SOURCES = lib/test_timer_correctness.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 \ @@ -147,6 +155,7 @@ lib_test_table_LDADD = $(ALL_TESTS_LDADD) -lm 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) diff --git a/tests/isisd/test_fuzz_isis_tlv.c b/tests/isisd/test_fuzz_isis_tlv.c index 6727e663f5..e61e9639ee 100644 --- a/tests/isisd/test_fuzz_isis_tlv.c +++ b/tests/isisd/test_fuzz_isis_tlv.c @@ -23,7 +23,7 @@ static bool atexit_registered; 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) diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c index 77f1610fe2..0fd2f80a39 100644 --- a/tests/lib/cli/common_cli.c +++ b/tests/lib/cli/common_cli.c @@ -53,7 +53,7 @@ static void vty_do_exit(int isexit) thread_master_free(master); closezlog(); - log_memstats_stderr("testcli"); + log_memstats(stderr, "testcli"); if (!isexit) exit(0); } diff --git a/tests/lib/cli/test_commands.py b/tests/lib/cli/test_commands.py index bda0bbac44..d55345186a 100644 --- a/tests/lib/cli/test_commands.py +++ b/tests/lib/cli/test_commands.py @@ -8,4 +8,4 @@ class TestCommands(frrtest.TestRefOut): @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() diff --git a/tests/lib/test_zmq.c b/tests/lib/test_zmq.c new file mode 100644 index 0000000000..c270ec3d18 --- /dev/null +++ b/tests/lib/test_zmq.c @@ -0,0 +1,212 @@ +/* + * 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 +#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); +} diff --git a/tests/lib/test_zmq.py b/tests/lib/test_zmq.py new file mode 100644 index 0000000000..1f8ee54169 --- /dev/null +++ b/tests/lib/test_zmq.py @@ -0,0 +1,11 @@ +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() diff --git a/tests/lib/test_zmq.refout b/tests/lib/test_zmq.refout new file mode 100644 index 0000000000..61f45f02b1 --- /dev/null +++ b/tests/lib/test_zmq.refout @@ -0,0 +1,50 @@ +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. diff --git a/tools/frr b/tools/frr index 0bea3ee81d..4eb4a5c28c 100755 --- a/tools/frr +++ b/tools/frr @@ -72,6 +72,11 @@ vtysh_b () # 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 @@ -80,9 +85,6 @@ check_daemon() # 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 diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 43496d4cbf..8556f0b46e 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -1162,19 +1162,11 @@ if __name__ == '__main__': 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 diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 9939a7fae9..34d66735df 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -752,6 +752,7 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp) lineno, cmd_stat, vtysh_client[i].name, vty->buf); + retcode = cmd_stat; break; } } @@ -1914,6 +1915,28 @@ static int show_per_daemon(const char *line, const char *headline) 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, @@ -1921,7 +1944,8 @@ DEFUN (vtysh_show_memory, 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, @@ -1941,20 +1965,8 @@ DEFUN (vtysh_show_logging, 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", @@ -3220,6 +3232,8 @@ void vtysh_init_vty(void) 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); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 1ce065fccf..d7e79d6b2c 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -245,7 +245,10 @@ void vtysh_config_parse_line(void *arg, const char *line) == 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); diff --git a/zebra/debug.c b/zebra/debug.c index 25f47bc51a..afeba1c6de 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -34,12 +34,12 @@ unsigned long zebra_debug_mpls; 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"); diff --git a/zebra/interface.c b/zebra/interface.c index 8456984330..a03b7f9615 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -52,11 +52,10 @@ #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); @@ -998,74 +997,6 @@ static void nbr_connected_dump_vty(struct vty *vty, 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) { @@ -1279,12 +1210,8 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) 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)) @@ -2913,13 +2840,7 @@ static int if_config_write(struct vty *vty) : "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); @@ -2932,8 +2853,8 @@ static int if_config_write(struct vty *vty) 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); diff --git a/zebra/interface.h b/zebra/interface.h index 970c3c5292..7b56dcd4a4 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -23,10 +23,7 @@ #include "redistribute.h" #include "vrf.h" - -#ifdef HAVE_IRDP -#include "zebra/irdp.h" -#endif +#include "hook.h" #include "zebra/zebra_l2.h" @@ -202,6 +199,8 @@ typedef enum { 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. */ @@ -227,9 +226,7 @@ struct zebra_if { 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 { @@ -273,6 +270,11 @@ struct zebra_if { 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) diff --git a/zebra/irdp.h b/zebra/irdp.h index 01308b915b..ea190b574d 100644 --- a/zebra/irdp.h +++ b/zebra/irdp.h @@ -138,10 +138,9 @@ struct Adv { 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); diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c index 5682e12e6f..34c78e2a48 100644 --- a/zebra/irdp_interface.c +++ b/zebra/irdp_interface.c @@ -35,8 +35,6 @@ #include -#ifdef HAVE_IRDP - #include "if.h" #include "vty.h" #include "sockunion.h" @@ -63,6 +61,25 @@ 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, @@ -117,10 +134,13 @@ static int if_group(struct interface *ifp, int sock, u_int32_t group, 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; @@ -135,10 +155,13 @@ static int if_add_group(struct interface *ifp) 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) @@ -150,11 +173,8 @@ static int if_drop_group(struct interface *ifp) 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; @@ -176,11 +196,13 @@ static void irdp_if_start(struct interface *ifp, int multicast, 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; @@ -215,7 +237,7 @@ static void irdp_if_start(struct interface *ifp, int multicast, } if (set_defaults) - if_set_defaults(ifp); + if_set_defaults(irdp); irdp->irdp_sent = 0; @@ -254,7 +276,7 @@ static void irdp_if_start(struct interface *ifp, int multicast, 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); @@ -281,8 +303,10 @@ static void irdp_if_stop(struct interface *ifp) 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; @@ -300,8 +324,7 @@ static void irdp_if_shutdown(struct interface *ifp) 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); @@ -316,14 +339,17 @@ static void irdp_if_no_shutdown(struct interface *ifp) /* 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) @@ -348,6 +374,7 @@ void irdp_config_write(struct vty *vty, struct interface *ifp) vty_out(vty, " ip irdp maxadvertinterval %ld\n", irdp->MaxAdvertInterval); } + return 0; } @@ -359,6 +386,7 @@ DEFUN (ip_irdp_multicast, "Use multicast mode\n") { VTY_DECLVAR_CONTEXT(interface, ifp); + irdp_if_get(ifp); irdp_if_start(ifp, TRUE, TRUE); return CMD_SUCCESS; @@ -372,6 +400,7 @@ DEFUN (ip_irdp_broadcast, "Use broadcast mode\n") { VTY_DECLVAR_CONTEXT(interface, ifp); + irdp_if_get(ifp); irdp_if_start(ifp, FALSE, TRUE); return CMD_SUCCESS; @@ -427,11 +456,7 @@ DEFUN (ip_irdp_holdtime, { 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; @@ -447,11 +472,7 @@ DEFUN (ip_irdp_minadvertinterval, { 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); @@ -474,11 +495,7 @@ DEFUN (ip_irdp_maxadvertinterval, { 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); @@ -506,11 +523,7 @@ DEFUN (ip_irdp_preference, { 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; @@ -529,17 +542,13 @@ DEFUN (ip_irdp_address_preference, 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; @@ -571,16 +580,12 @@ DEFUN (no_ip_irdp_address_preference, { 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; @@ -604,11 +609,7 @@ DEFUN (ip_irdp_debug_messages, "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; @@ -624,11 +625,7 @@ DEFUN (ip_irdp_debug_misc, "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; @@ -644,11 +641,7 @@ DEFUN (ip_irdp_debug_packet, "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; @@ -665,11 +658,7 @@ DEFUN (ip_irdp_debug_disable, "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; @@ -678,8 +667,11 @@ DEFUN (ip_irdp_debug_disable, 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); @@ -697,5 +689,3 @@ void irdp_init() install_element(INTERFACE_NODE, &ip_irdp_debug_packet_cmd); install_element(INTERFACE_NODE, &ip_irdp_debug_disable_cmd); } - -#endif /* HAVE_IRDP */ diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c index 6220c9d81b..9dfa854725 100644 --- a/zebra/irdp_main.c +++ b/zebra/irdp_main.c @@ -35,8 +35,6 @@ #include -#ifdef HAVE_IRDP - #include "if.h" #include "vty.h" #include "sockunion.h" @@ -52,6 +50,8 @@ #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" @@ -143,7 +143,7 @@ static int make_advertisement_packet(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; int size; int pref; u_int16_t checksum; @@ -175,11 +175,13 @@ static int make_advertisement_packet(struct interface *ifp, struct prefix *p, 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; @@ -211,11 +213,14 @@ int irdp_send_thread(struct thread *t_advert) 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) @@ -250,12 +255,15 @@ int irdp_send_thread(struct thread *t_advert) 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; @@ -279,9 +287,12 @@ void irdp_advert_off(struct interface *ifp) 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. */ @@ -301,7 +312,7 @@ void process_solicit(struct interface *ifp) &irdp->t_advertise); } -void irdp_finish() +static int irdp_finish(void) { struct vrf *vrf; struct listnode *node, *nnode; @@ -317,7 +328,7 @@ void irdp_finish() if (!zi) continue; - irdp = &zi->irdp; + irdp = zi->irdp; if (!irdp) continue; @@ -326,6 +337,26 @@ void irdp_finish() irdp_advert_off(ifp); } } + return 0; } -#endif /* HAVE_IRDP */ +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; +} + +FRR_MODULE_SETUP( + .name = "zebra_irdp", + .version = FRR_VERSION, + .description = "zebra IRDP module", + .init = irdp_module_init, +) diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index 3bd093d97b..0832245536 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -36,8 +36,6 @@ #include -#ifdef HAVE_IRDP - #include "if.h" #include "vty.h" #include "sockunion.h" @@ -84,7 +82,7 @@ static void parse_irdp_packet(char *p, int len, struct interface *ifp) if (!zi) return; - irdp = &zi->irdp; + irdp = zi->irdp; if (!irdp) return; @@ -240,7 +238,7 @@ int irdp_read_raw(struct thread *r) if (!zi) return ret; - irdp = &zi->irdp; + irdp = zi->irdp; if (!irdp) return ret; @@ -353,6 +351,3 @@ void send_packet(struct interface *ifp, struct stream *s, u_int32_t dst, } /* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */ } - - -#endif /* HAVE_IRDP */ diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 84d01bca6f..e2a1deb9ac 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -88,13 +88,10 @@ extern struct zebra_privs_t zserv_privs; #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__ diff --git a/zebra/main.c b/zebra/main.c index 538c2f0663..bc7276817d 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -125,9 +125,7 @@ static void sigint(void) zlog_notice("Terminating on signal"); -#ifdef HAVE_IRDP - irdp_finish(); -#endif + frr_early_fini(); zebra_ptm_finish(); list_delete_all_node(zebrad.client_list); @@ -147,17 +145,14 @@ static void sigint(void) 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); } @@ -297,9 +292,6 @@ int main(int argc, char **argv) #if defined(HAVE_RTADV) rtadv_cmd_init(); #endif -#ifdef HAVE_IRDP - irdp_init(); -#endif /* PTM socket */ #ifdef ZEBRA_PTM_SUPPORT zebra_ptm_init(); diff --git a/zebra/redistribute.c b/zebra/redistribute.c index ed27dc3e83..9b21eb4d8c 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -95,8 +95,8 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id) 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); } @@ -114,7 +114,7 @@ static void zebra_redistribute(struct zserv *client, int type, u_short instance, 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; @@ -141,8 +141,8 @@ static void zebra_redistribute(struct zserv *client, int type, u_short instance, 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); } } @@ -191,7 +191,8 @@ void redistribute_update(struct prefix *p, struct prefix *src_p, 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( @@ -201,7 +202,8 @@ void redistribute_update(struct prefix *p, struct prefix *src_p, || 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); } } } @@ -242,7 +244,8 @@ void redistribute_delete(struct prefix *p, struct prefix *src_p, 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); } } } diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 4e4d726b46..32ae41b917 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -71,6 +71,27 @@ static int sin_masklen(struct in_addr mask) } #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) @@ -150,15 +171,11 @@ 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( @@ -266,6 +283,10 @@ static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct route_entry *re) { 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; @@ -338,10 +359,17 @@ static int kernel_rtm_ipv6(int cmd, struct prefix *p, struct route_entry *re) 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) diff --git a/zebra/rtadv.c b/zebra/rtadv.c index b8cf2d490a..2182d6618c 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -62,6 +62,10 @@ extern struct zebra_privs_t zserv_privs; #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, @@ -1456,9 +1460,76 @@ DEFUN (no_ipv6_nd_mtu, 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; @@ -1539,6 +1610,7 @@ void rtadv_config_write(struct vty *vty, struct interface *ifp) vty_out(vty, " router-address"); vty_out(vty, "\n"); } + return 0; } @@ -1600,6 +1672,9 @@ void rtadv_terminate(struct zebra_ns *zns) 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); diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 029c97cddc..dcaeb3ed28 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -55,8 +55,6 @@ struct rtadv_prefix { #endif }; -extern void rtadv_config_write(struct vty *, struct interface *); - /* RFC4584 Extension to Sockets API for Mobile IPv6 */ #ifndef ND_OPT_ADV_INTERVAL diff --git a/zebra/subdir.am b/zebra/subdir.am index 0391cab9fd..3474823623 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -6,6 +6,9 @@ if ZEBRA 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 @@ -30,9 +33,6 @@ zebra_zebra_SOURCES = \ 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 \ @@ -106,6 +106,13 @@ noinst_HEADERS += \ 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 diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index b88bce9e82..8c0700ac8b 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -1589,8 +1589,10 @@ static int fpm_remote_srv_write(struct vty *vty) 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); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 47cf7a3cbf..cee3a03858 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -1671,27 +1671,20 @@ int mpls_str2label(const char *label_str, u_int8_t *num_labels, char *mpls_label2str(u_int8_t num_labels, mpls_label_t *labels, char *buf, int len, int pretty) { - char *buf_ptr = buf; + char label_buf[BUFSIZ]; + int i; + 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); - - 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]); + 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; } diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h index c8dab39210..c8df8670f4 100644 --- a/zebra/zebra_mpls.h +++ b/zebra/zebra_mpls.h @@ -37,8 +37,6 @@ /* 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) \ diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c index 119cd5b700..33f0d49d4d 100644 --- a/zebra/zebra_mpls_openbsd.c +++ b/zebra/zebra_mpls_openbsd.c @@ -256,6 +256,15 @@ static int kernel_lsp_cmd(int action, zebra_lsp_t *lsp) || (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)) { diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index 4f1d8b0915..0b6263fac5 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -434,8 +434,9 @@ DEFUN (pseudowire_control_word, DEFUN (show_pseudowires, show_pseudowires_cmd, - "show pseudowires", + "show mpls pseudowires", SHOW_STR + MPLS_STR "Pseudowires") { struct zebra_vrf *zvrf; diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index ed53554265..dc61ea5e40 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1820,7 +1820,7 @@ void rib_queue_add(struct route_node *rn) * 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); @@ -2352,7 +2352,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, 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; diff --git a/zebra/zebra_static.c b/zebra/zebra_static.c index dba228ea35..6815916faf 100644 --- a/zebra/zebra_static.c +++ b/zebra/zebra_static.c @@ -398,7 +398,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, 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))) { @@ -515,7 +515,7 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p, 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)) diff --git a/zebra/zebra_static.h b/zebra/zebra_static.h index 6ab47094a1..ff9f0f59e7 100644 --- a/zebra/zebra_static.h +++ b/zebra/zebra_static.h @@ -22,11 +22,13 @@ #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 { diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index f01f037ed5..9f887e8401 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1705,16 +1705,14 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi, 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; } diff --git a/zebra/zserv.c b/zebra/zserv.c index cd893b5670..0e0cc78bbe 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -592,193 +592,76 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp) 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; + int count = 0; - 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)); - - 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); + if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + continue; - 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 */ + 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; } - - 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); - - /* ldpd needs all nexthops */ - if (client->proto != ZEBRA_ROUTE_LDP) - break; - } + 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); } @@ -1157,6 +1040,145 @@ void zserv_nexthop_num_warn(const char *caller, const struct prefix *p, } } +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 @@ -1176,6 +1198,7 @@ static int zread_ipv4_add(struct zserv *client, u_short length, ifindex_t ifindex; safi_t safi; int ret; + enum lsp_types_t label_type = ZEBRA_LSP_NONE; mpls_label_t label; struct nexthop *nexthop; @@ -1208,6 +1231,9 @@ static int zread_ipv4_add(struct zserv *client, u_short length, 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); @@ -1224,9 +1250,8 @@ static int zread_ipv4_add(struct zserv *client, u_short length, * 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: @@ -1281,21 +1306,12 @@ static int zread_ipv4_add(struct zserv *client, u_short length, 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); @@ -1310,63 +1326,10 @@ static int zread_ipv4_delete(struct zserv *client, u_short length, 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; } @@ -1401,6 +1364,7 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, 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; @@ -1441,6 +1405,10 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, 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); @@ -1485,9 +1453,8 @@ static int zread_ipv4_route_ipv6_nexthop_add(struct zserv *client, 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( @@ -1534,6 +1501,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length, 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; @@ -1545,6 +1513,7 @@ static int zread_ipv6_add(struct zserv *client, u_short length, 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; @@ -1591,6 +1560,10 @@ static int zread_ipv6_add(struct zserv *client, u_short length, 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); @@ -1609,6 +1582,12 @@ static int zread_ipv6_add(struct zserv *client, u_short length, 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); @@ -1633,9 +1612,8 @@ static int zread_ipv6_add(struct zserv *client, u_short length, 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( @@ -1681,18 +1659,12 @@ static int zread_ipv6_add(struct zserv *client, u_short length, 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); @@ -1716,59 +1688,8 @@ static int zread_ipv6_delete(struct zserv *client, u_short length, } 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; @@ -2435,6 +2356,12 @@ static int zebra_client_read(struct thread *thread) 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; @@ -2444,14 +2371,6 @@ static int zebra_client_read(struct thread *thread) 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;