mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 08:50:26 +00:00
Merge branch 'master' into dev-master
This commit is contained in:
commit
09fdc88c8c
10
Makefile.am
10
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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
165
babeld/kernel.c
165
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
|
||||
|
@ -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.",
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
325
bgpd/bgp_route.c
325
bgpd/bgp_route.c
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "prefix.h"
|
||||
#include "linklist.h"
|
||||
@ -2001,18 +2002,15 @@ int bgp_zebra_has_route_changed(struct bgp_node *rn, struct bgp_info *selected)
|
||||
|
||||
struct bgp_process_queue {
|
||||
struct bgp *bgp;
|
||||
struct bgp_node *rn;
|
||||
afi_t afi;
|
||||
safi_t safi;
|
||||
STAILQ_HEAD(, bgp_node)pqueue;
|
||||
#define BGP_PROCESS_QUEUE_EOIU_MARKER (1 << 0)
|
||||
unsigned int flags;
|
||||
unsigned int queued;
|
||||
};
|
||||
|
||||
static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
|
||||
static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
|
||||
afi_t afi, safi_t safi)
|
||||
{
|
||||
struct bgp_process_queue *pq = data;
|
||||
struct bgp *bgp = pq->bgp;
|
||||
struct bgp_node *rn = pq->rn;
|
||||
afi_t afi = pq->afi;
|
||||
safi_t safi = pq->safi;
|
||||
struct prefix *p = &rn->p;
|
||||
struct bgp_info *new_select;
|
||||
struct bgp_info *old_select;
|
||||
@ -2033,7 +2031,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
|
||||
bgp->main_peers_update_hold = 0;
|
||||
|
||||
bgp_start_routeadv(bgp);
|
||||
return WQ_SUCCESS;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Best path selection. */
|
||||
@ -2045,11 +2043,9 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
|
||||
/* Do we need to allocate or free labels?
|
||||
* Right now, since we only deal with per-prefix labels, it is not
|
||||
* necessary to do this upon changes to best path except if the label
|
||||
* index changes.
|
||||
* NOTE: This is only relevant for the default instance.
|
||||
* index changes
|
||||
*/
|
||||
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
|
||||
&& safi == SAFI_UNICAST) {
|
||||
if (bgp->allocate_mpls_labels[afi][safi]) {
|
||||
if (new_select) {
|
||||
if (!old_select
|
||||
|| bgp_label_index_differs(new_select, old_select)
|
||||
@ -2070,8 +2066,11 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
|
||||
} else
|
||||
bgp_register_for_label(rn, new_select);
|
||||
}
|
||||
} else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL))
|
||||
} else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
|
||||
bgp_unregister_for_label(rn);
|
||||
}
|
||||
} else if (CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) {
|
||||
bgp_unregister_for_label(rn);
|
||||
}
|
||||
|
||||
/* If best route remains the same and this is not due to user-initiated
|
||||
@ -2115,7 +2114,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
|
||||
}
|
||||
|
||||
UNSET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
|
||||
return WQ_SUCCESS;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the user did "clear ip bgp prefix x.x.x.x" this flag will be set
|
||||
@ -2193,21 +2192,42 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
|
||||
bgp_info_reap(rn, old_select);
|
||||
|
||||
UNSET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
|
||||
return;
|
||||
}
|
||||
|
||||
static wq_item_status bgp_process_wq(struct work_queue *wq, void *data)
|
||||
{
|
||||
struct bgp_process_queue *pqnode = data;
|
||||
struct bgp *bgp = pqnode->bgp;
|
||||
struct bgp_table *table;
|
||||
struct bgp_node *rn, *nrn;
|
||||
|
||||
/* eoiu marker */
|
||||
if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER)) {
|
||||
bgp_process_main_one(bgp, NULL, 0, 0);
|
||||
|
||||
return WQ_SUCCESS;
|
||||
}
|
||||
|
||||
STAILQ_FOREACH_SAFE(rn, &pqnode->pqueue, pq, nrn) {
|
||||
table = bgp_node_table(rn);
|
||||
|
||||
bgp_process_main_one(bgp, rn, table->afi, table->safi);
|
||||
|
||||
bgp_unlock_node(rn);
|
||||
bgp_table_unlock(table);
|
||||
}
|
||||
|
||||
return WQ_SUCCESS;
|
||||
}
|
||||
|
||||
static void bgp_processq_del(struct work_queue *wq, void *data)
|
||||
{
|
||||
struct bgp_process_queue *pq = data;
|
||||
struct bgp_table *table;
|
||||
struct bgp_process_queue *pqnode = data;
|
||||
|
||||
bgp_unlock(pq->bgp);
|
||||
if (pq->rn) {
|
||||
table = bgp_node_table(pq->rn);
|
||||
bgp_unlock_node(pq->rn);
|
||||
bgp_table_unlock(table);
|
||||
}
|
||||
XFREE(MTYPE_BGP_PROCESS_QUEUE, pq);
|
||||
bgp_unlock(pqnode->bgp);
|
||||
|
||||
XFREE(MTYPE_BGP_PROCESS_QUEUE, pqnode);
|
||||
}
|
||||
|
||||
void bgp_process_queue_init(void)
|
||||
@ -2222,7 +2242,7 @@ void bgp_process_queue_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
bm->process_main_queue->spec.workfunc = &bgp_process_main;
|
||||
bm->process_main_queue->spec.workfunc = &bgp_process_wq;
|
||||
bm->process_main_queue->spec.del_item_data = &bgp_processq_del;
|
||||
bm->process_main_queue->spec.max_retries = 0;
|
||||
bm->process_main_queue->spec.hold = 50;
|
||||
@ -2230,31 +2250,56 @@ void bgp_process_queue_init(void)
|
||||
bm->process_main_queue->spec.yield = 50 * 1000L;
|
||||
}
|
||||
|
||||
static struct bgp_process_queue *bgp_process_queue_work(struct work_queue *wq,
|
||||
struct bgp *bgp)
|
||||
{
|
||||
struct bgp_process_queue *pqnode;
|
||||
|
||||
pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE, sizeof(struct bgp_process_queue));
|
||||
|
||||
/* unlocked in bgp_processq_del */
|
||||
pqnode->bgp = bgp_lock(bgp);
|
||||
STAILQ_INIT(&pqnode->pqueue);
|
||||
|
||||
work_queue_add(wq, pqnode);
|
||||
|
||||
return pqnode;
|
||||
}
|
||||
|
||||
void bgp_process(struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
|
||||
{
|
||||
#define ARBITRARY_PROCESS_QLEN 10000
|
||||
struct work_queue *wq = bm->process_main_queue;
|
||||
struct bgp_process_queue *pqnode;
|
||||
|
||||
/* already scheduled for processing? */
|
||||
if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED))
|
||||
return;
|
||||
|
||||
if (bm->process_main_queue == NULL)
|
||||
if (wq == NULL)
|
||||
return;
|
||||
|
||||
pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE,
|
||||
sizeof(struct bgp_process_queue));
|
||||
if (!pqnode)
|
||||
return;
|
||||
/* Add route nodes to an existing work queue item until reaching the
|
||||
limit only if is from the same BGP view and it's not an EOIU marker */
|
||||
if (work_queue_item_count(wq)) {
|
||||
struct work_queue_item *item = work_queue_last_item(wq);
|
||||
pqnode = item->data;
|
||||
|
||||
/* all unlocked in bgp_processq_del */
|
||||
if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) ||
|
||||
pqnode->bgp != bgp || pqnode->queued >= ARBITRARY_PROCESS_QLEN)
|
||||
pqnode = bgp_process_queue_work(wq, bgp);
|
||||
} else
|
||||
pqnode = bgp_process_queue_work(wq, bgp);
|
||||
|
||||
/* all unlocked in bgp_process_wq */
|
||||
bgp_table_lock(bgp_node_table(rn));
|
||||
pqnode->rn = bgp_lock_node(rn);
|
||||
pqnode->bgp = bgp;
|
||||
bgp_lock(bgp);
|
||||
pqnode->afi = afi;
|
||||
pqnode->safi = safi;
|
||||
work_queue_add(bm->process_main_queue, pqnode);
|
||||
|
||||
SET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
|
||||
bgp_lock_node(rn);
|
||||
|
||||
STAILQ_INSERT_TAIL(&pqnode->pqueue, rn, pq);
|
||||
pqnode->queued++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2265,15 +2310,9 @@ void bgp_add_eoiu_mark(struct bgp *bgp)
|
||||
if (bm->process_main_queue == NULL)
|
||||
return;
|
||||
|
||||
pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE,
|
||||
sizeof(struct bgp_process_queue));
|
||||
if (!pqnode)
|
||||
return;
|
||||
pqnode = bgp_process_queue_work(bm->process_main_queue, bgp);
|
||||
|
||||
pqnode->rn = NULL;
|
||||
pqnode->bgp = bgp;
|
||||
bgp_lock(bgp);
|
||||
work_queue_add(bm->process_main_queue, pqnode);
|
||||
SET_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER);
|
||||
}
|
||||
|
||||
static int bgp_maximum_prefix_restart_timer(struct thread *thread)
|
||||
@ -6050,8 +6089,7 @@ DEFUN (no_ipv6_aggregate_address,
|
||||
|
||||
/* Redistribute route treatment. */
|
||||
void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
|
||||
const struct in_addr *nexthop,
|
||||
const struct in6_addr *nexthop6, unsigned int ifindex,
|
||||
const union g_addr *nexthop, unsigned int ifindex,
|
||||
u_int32_t metric, u_char type, u_short instance,
|
||||
route_tag_t tag)
|
||||
{
|
||||
@ -6067,14 +6105,17 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
|
||||
|
||||
/* Make default attribute. */
|
||||
bgp_attr_default_set(&attr, BGP_ORIGIN_INCOMPLETE);
|
||||
if (nexthop)
|
||||
attr.nexthop = *nexthop;
|
||||
attr.nh_ifindex = ifindex;
|
||||
|
||||
if (nexthop6) {
|
||||
attr.mp_nexthop_global = *nexthop6;
|
||||
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
|
||||
if (nexthop) {
|
||||
switch (p->family) {
|
||||
case AF_INET:
|
||||
attr.nexthop = nexthop->ipv4;
|
||||
break;
|
||||
case AF_INET6:
|
||||
attr.mp_nexthop_global = nexthop->ipv6;
|
||||
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
|
||||
}
|
||||
}
|
||||
attr.nh_ifindex = ifindex;
|
||||
|
||||
attr.med = metric;
|
||||
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
|
||||
@ -8002,7 +8043,8 @@ static int bgp_show_community_list(struct vty *vty, struct bgp *bgp,
|
||||
static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
|
||||
const char *prefix, afi_t afi, safi_t safi,
|
||||
enum bgp_show_type type);
|
||||
static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi,
|
||||
static int bgp_show_regexp(struct vty *vty, struct bgp *bgp,
|
||||
const char *regstr, afi_t afi,
|
||||
safi_t safi, enum bgp_show_type type);
|
||||
static int bgp_show_community(struct vty *vty, struct bgp *bgp, int argc,
|
||||
struct cmd_token **argv, int exact, afi_t afi,
|
||||
@ -8820,32 +8862,28 @@ DEFUN (show_ip_bgp_large_community,
|
||||
static int bgp_table_stats(struct vty *vty, struct bgp *bgp, afi_t afi,
|
||||
safi_t safi);
|
||||
|
||||
/* BGP route print out function. */
|
||||
|
||||
/* BGP route print out function without JSON */
|
||||
DEFUN (show_ip_bgp,
|
||||
show_ip_bgp_cmd,
|
||||
"show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]\
|
||||
[<\
|
||||
cidr-only\
|
||||
|dampening <flap-statistics|dampened-paths|parameters>\
|
||||
|route-map WORD\
|
||||
|prefix-list WORD\
|
||||
|filter-list WORD\
|
||||
|statistics\
|
||||
|community [<AA:NN|local-AS|no-advertise|no-export> [exact-match]]\
|
||||
|community-list <(1-500)|WORD> [exact-match]\
|
||||
|A.B.C.D/M longer-prefixes\
|
||||
|X:X::X:X/M longer-prefixes>\
|
||||
] [json]",
|
||||
<dampening <parameters>\
|
||||
|route-map WORD\
|
||||
|prefix-list WORD\
|
||||
|filter-list WORD\
|
||||
|statistics\
|
||||
|community <AA:NN|local-AS|no-advertise|no-export> [exact-match]\
|
||||
|community-list <(1-500)|WORD> [exact-match]\
|
||||
|A.B.C.D/M longer-prefixes\
|
||||
|X:X::X:X/M longer-prefixes\
|
||||
>",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
BGP_INSTANCE_HELP_STR
|
||||
BGP_AFI_HELP_STR
|
||||
BGP_SAFI_WITH_LABEL_HELP_STR
|
||||
"Display only routes with non-natural netmasks\n"
|
||||
"Display detailed information about dampening\n"
|
||||
"Display flap statistics of routes\n"
|
||||
"Display paths suppressed due to dampening\n"
|
||||
"Display detail of configured dampening parameters\n"
|
||||
"Display routes matching the route-map\n"
|
||||
"A route-map to match on\n"
|
||||
@ -8867,13 +8905,11 @@ DEFUN (show_ip_bgp,
|
||||
"IPv4 prefix\n"
|
||||
"Display route and more specific routes\n"
|
||||
"IPv6 prefix\n"
|
||||
"Display route and more specific routes\n"
|
||||
JSON_STR)
|
||||
"Display route and more specific routes\n")
|
||||
{
|
||||
afi_t afi = AFI_IP6;
|
||||
safi_t safi = SAFI_UNICAST;
|
||||
int exact_match = 0;
|
||||
enum bgp_show_type sh_type = bgp_show_type_normal;
|
||||
struct bgp *bgp = NULL;
|
||||
int idx = 0;
|
||||
|
||||
@ -8882,23 +8918,8 @@ DEFUN (show_ip_bgp,
|
||||
if (!idx)
|
||||
return CMD_WARNING;
|
||||
|
||||
int uj = use_json(argc, argv);
|
||||
if (uj)
|
||||
argc--;
|
||||
|
||||
if (argv_find(argv, argc, "cidr-only", &idx))
|
||||
return bgp_show(vty, bgp, afi, safi, bgp_show_type_cidr_only,
|
||||
NULL, uj);
|
||||
|
||||
if (argv_find(argv, argc, "dampening", &idx)) {
|
||||
if (argv_find(argv, argc, "dampened-paths", &idx))
|
||||
return bgp_show(vty, bgp, afi, safi,
|
||||
bgp_show_type_dampend_paths, NULL, uj);
|
||||
else if (argv_find(argv, argc, "flap-statistics", &idx))
|
||||
return bgp_show(vty, bgp, afi, safi,
|
||||
bgp_show_type_flap_statistics, NULL,
|
||||
uj);
|
||||
else if (argv_find(argv, argc, "parameters", &idx))
|
||||
if (argv_find(argv, argc, "parameters", &idx))
|
||||
return bgp_show_dampening_parameters(vty, afi, safi);
|
||||
}
|
||||
|
||||
@ -8927,10 +8948,6 @@ DEFUN (show_ip_bgp,
|
||||
return bgp_show_community(vty, bgp, argc, argv,
|
||||
exact_match, afi, safi);
|
||||
}
|
||||
/* show all communities */
|
||||
else
|
||||
return bgp_show(vty, bgp, afi, safi,
|
||||
bgp_show_type_community_all, NULL, uj);
|
||||
}
|
||||
|
||||
if (argv_find(argv, argc, "community-list", &idx)) {
|
||||
@ -8947,6 +8964,66 @@ DEFUN (show_ip_bgp,
|
||||
safi,
|
||||
bgp_show_type_prefix_longer);
|
||||
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
/* BGP route print out function with JSON */
|
||||
DEFUN (show_ip_bgp_json,
|
||||
show_ip_bgp_json_cmd,
|
||||
"show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]\
|
||||
[<\
|
||||
cidr-only\
|
||||
|dampening <flap-statistics|dampened-paths>\
|
||||
|community \
|
||||
>] [json]",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
BGP_STR
|
||||
BGP_INSTANCE_HELP_STR
|
||||
BGP_AFI_HELP_STR
|
||||
BGP_SAFI_WITH_LABEL_HELP_STR
|
||||
"Display only routes with non-natural netmasks\n"
|
||||
"Display detailed information about dampening\n"
|
||||
"Display flap statistics of routes\n"
|
||||
"Display paths suppressed due to dampening\n"
|
||||
"Display routes matching the communities\n"
|
||||
JSON_STR)
|
||||
{
|
||||
afi_t afi = AFI_IP6;
|
||||
safi_t safi = SAFI_UNICAST;
|
||||
enum bgp_show_type sh_type = bgp_show_type_normal;
|
||||
struct bgp *bgp = NULL;
|
||||
int idx = 0;
|
||||
|
||||
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
|
||||
&bgp);
|
||||
if (!idx)
|
||||
return CMD_WARNING;
|
||||
|
||||
int uj = use_json(argc, argv);
|
||||
if (uj)
|
||||
argc--;
|
||||
|
||||
if (argv_find(argv, argc, "cidr-only", &idx))
|
||||
return bgp_show(vty, bgp, afi, safi, bgp_show_type_cidr_only,
|
||||
NULL, uj);
|
||||
|
||||
if (argv_find(argv, argc, "dampening", &idx)) {
|
||||
if (argv_find(argv, argc, "dampened-paths", &idx))
|
||||
return bgp_show(vty, bgp, afi, safi,
|
||||
bgp_show_type_dampend_paths, NULL, uj);
|
||||
else if (argv_find(argv, argc, "flap-statistics", &idx))
|
||||
return bgp_show(vty, bgp, afi, safi,
|
||||
bgp_show_type_flap_statistics, NULL,
|
||||
uj);
|
||||
}
|
||||
|
||||
if (argv_find(argv, argc, "community", &idx)) {
|
||||
/* show all communities */
|
||||
return bgp_show(vty, bgp, afi, safi,
|
||||
bgp_show_type_community_all, NULL, uj);
|
||||
}
|
||||
|
||||
if (safi == SAFI_MPLS_VPN)
|
||||
return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_normal,
|
||||
NULL, 0, uj);
|
||||
@ -9056,7 +9133,7 @@ DEFUN (show_ip_bgp_regexp,
|
||||
idx++;
|
||||
|
||||
char *regstr = argv_concat(argv, argc, idx);
|
||||
int rc = bgp_show_regexp(vty, (const char *)regstr, afi, safi,
|
||||
int rc = bgp_show_regexp(vty, bgp, (const char *)regstr, afi, safi,
|
||||
bgp_show_type_regexp);
|
||||
XFREE(MTYPE_TMP, regstr);
|
||||
return rc;
|
||||
@ -9091,7 +9168,8 @@ DEFUN (show_ip_bgp_instance_all,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi,
|
||||
static int bgp_show_regexp(struct vty *vty, struct bgp *bgp,
|
||||
const char *regstr, afi_t afi,
|
||||
safi_t safi, enum bgp_show_type type)
|
||||
{
|
||||
regex_t *regex;
|
||||
@ -9103,7 +9181,7 @@ static int bgp_show_regexp(struct vty *vty, const char *regstr, afi_t afi,
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
rc = bgp_show(vty, NULL, afi, safi, type, regex, 0);
|
||||
rc = bgp_show(vty, bgp, afi, safi, type, regex, 0);
|
||||
bgp_regex_free(regex);
|
||||
return rc;
|
||||
}
|
||||
@ -9332,6 +9410,7 @@ static const char *table_stats_strs[] = {
|
||||
struct bgp_table_stats {
|
||||
struct bgp_table *table;
|
||||
unsigned long long counts[BGP_STATS_MAX];
|
||||
double total_space;
|
||||
};
|
||||
|
||||
#if 0
|
||||
@ -9400,8 +9479,8 @@ static int bgp_table_stats_walker(struct thread *t)
|
||||
ts->counts[BGP_STATS_UNAGGREGATEABLE]++;
|
||||
/* announced address space */
|
||||
if (space)
|
||||
ts->counts[BGP_STATS_SPACE] +=
|
||||
1 << (space - rn->p.prefixlen);
|
||||
ts->total_space += pow(2.0,
|
||||
space - rn->p.prefixlen);
|
||||
} else if (prn->info)
|
||||
ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++;
|
||||
|
||||
@ -9511,31 +9590,26 @@ static int bgp_table_stats(struct vty *vty, struct bgp *bgp, afi_t afi,
|
||||
break;
|
||||
case BGP_STATS_SPACE:
|
||||
vty_out(vty, "%-30s: ", table_stats_strs[i]);
|
||||
vty_out(vty, "%12llu\n", ts.counts[i]);
|
||||
if (ts.counts[BGP_STATS_MAXBITLEN] < 9)
|
||||
break;
|
||||
vty_out(vty, "%30s: ", "%% announced ");
|
||||
vty_out(vty, "%12.2f\n",
|
||||
100 * (float)ts.counts[BGP_STATS_SPACE]
|
||||
/ (float)((uint64_t)1UL
|
||||
<< ts.counts
|
||||
[BGP_STATS_MAXBITLEN]));
|
||||
vty_out(vty, "%30s: ", "/8 equivalent ");
|
||||
vty_out(vty, "%12.2f\n",
|
||||
(float)ts.counts[BGP_STATS_SPACE]
|
||||
/ (float)(1UL
|
||||
<< (ts.counts
|
||||
[BGP_STATS_MAXBITLEN]
|
||||
- 8)));
|
||||
if (ts.counts[BGP_STATS_MAXBITLEN] < 25)
|
||||
break;
|
||||
vty_out(vty, "%30s: ", "/24 equivalent ");
|
||||
vty_out(vty, "%12.2f",
|
||||
(float)ts.counts[BGP_STATS_SPACE]
|
||||
/ (float)(1UL
|
||||
<< (ts.counts
|
||||
[BGP_STATS_MAXBITLEN]
|
||||
- 24)));
|
||||
vty_out(vty, "%12g\n", ts.total_space);
|
||||
|
||||
if (afi == AFI_IP6) {
|
||||
vty_out(vty, "%30s: ", "/32 equivalent ");
|
||||
vty_out(vty, "%12g\n",
|
||||
ts.total_space * pow(2.0, -128+32));
|
||||
vty_out(vty, "%30s: ", "/48 equivalent ");
|
||||
vty_out(vty, "%12g\n",
|
||||
ts.total_space * pow(2.0, -128+48));
|
||||
} else {
|
||||
vty_out(vty, "%30s: ", "% announced ");
|
||||
vty_out(vty, "%12.2f\n",
|
||||
ts.total_space * 100. * pow(2.0, -32));
|
||||
vty_out(vty, "%30s: ", "/8 equivalent ");
|
||||
vty_out(vty, "%12.2f\n",
|
||||
ts.total_space * pow(2.0, -32+8));
|
||||
vty_out(vty, "%30s: ", "/24 equivalent ");
|
||||
vty_out(vty, "%12.2f\n",
|
||||
ts.total_space * pow(2.0, -32+24));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vty_out(vty, "%-30s: ", table_stats_strs[i]);
|
||||
@ -11265,6 +11339,7 @@ void bgp_route_init(void)
|
||||
/* IPv4 labeled-unicast configuration. */
|
||||
install_element(VIEW_NODE, &show_ip_bgp_instance_all_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_bgp_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_bgp_json_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_bgp_route_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_bgp_regexp_cmd);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
/*
|
||||
|
721
bgpd/bgp_zebra.c
721
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);
|
||||
|
116
bgpd/bgpd.c
116
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;
|
||||
|
27
bgpd/bgpd.h
27
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. */
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
58
configure.ac
58
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 ----------
|
||||
|
3
doc/code/.gitignore
vendored
Normal file
3
doc/code/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/_templates
|
||||
/_build
|
||||
!/Makefile
|
216
doc/code/Makefile
Normal file
216
doc/code/Makefile
Normal file
@ -0,0 +1,216 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# User-friendly check for sphinx-build
|
||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
||||
endif
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " applehelp to make an Apple Help Book"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " xml to make Docutils-native XML files"
|
||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
@echo " coverage to run coverage check of the documentation (if enabled)"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)/*
|
||||
|
||||
.PHONY: html
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
.PHONY: dirhtml
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
.PHONY: singlehtml
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
.PHONY: pickle
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
.PHONY: json
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
.PHONY: htmlhelp
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
.PHONY: qthelp
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/FRR.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/FRR.qhc"
|
||||
|
||||
.PHONY: applehelp
|
||||
applehelp:
|
||||
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
|
||||
@echo
|
||||
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
|
||||
@echo "N.B. You won't be able to view it unless you put it in" \
|
||||
"~/Library/Documentation/Help or install it in your application" \
|
||||
"bundle."
|
||||
|
||||
.PHONY: devhelp
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/FRR"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/FRR"
|
||||
@echo "# devhelp"
|
||||
|
||||
.PHONY: epub
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
.PHONY: latex
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
.PHONY: latexpdf
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
.PHONY: latexpdfja
|
||||
latexpdfja:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
.PHONY: text
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
.PHONY: man
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
.PHONY: texinfo
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
.PHONY: info
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
.PHONY: gettext
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
.PHONY: changes
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
.PHONY: linkcheck
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
.PHONY: doctest
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
|
||||
@echo "Testing of coverage in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/coverage/python.txt."
|
||||
|
||||
.PHONY: xml
|
||||
xml:
|
||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||
@echo
|
||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||
|
||||
.PHONY: pseudoxml
|
||||
pseudoxml:
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
293
doc/code/conf.py
Normal file
293
doc/code/conf.py
Normal file
@ -0,0 +1,293 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# FRR documentation build configuration file, created by
|
||||
# sphinx-quickstart on Tue Jan 31 16:00:52 2017.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['sphinx.ext.todo']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'FRR'
|
||||
copyright = u'2017, FRR'
|
||||
author = u'FRR'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
|
||||
# The short X.Y version.
|
||||
version = u'?.?'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'?.?-?'
|
||||
|
||||
val = re.compile('^S\["([^"]+)"\]="(.*)"$')
|
||||
with open('../../config.status', 'r') as cfgstatus:
|
||||
for ln in cfgstatus.readlines():
|
||||
m = val.match(ln)
|
||||
if m is None: continue
|
||||
if m.group(1) == 'PACKAGE_VERSION':
|
||||
release = m.group(2)
|
||||
version = release.split('-')[0]
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
#keep_warnings = False
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
#html_extra_path = []
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Language to be used for generating the HTML full-text search index.
|
||||
# Sphinx supports the following languages:
|
||||
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
|
||||
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
|
||||
#html_search_language = 'en'
|
||||
|
||||
# A dictionary with options for the search language support, empty by default.
|
||||
# Now only 'ja' uses this config value
|
||||
#html_search_options = {'type': 'default'}
|
||||
|
||||
# The name of a javascript file (relative to the configuration directory) that
|
||||
# implements a search results scorer. If empty, the default will be used.
|
||||
#html_search_scorer = 'scorer.js'
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'FRRdoc'
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'FRR.tex', u'FRR Documentation',
|
||||
u'FRR', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'frr', u'FRR Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'FRR', u'FRR Documentation',
|
||||
author, 'FRR', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
171
doc/code/hooks.rst
Normal file
171
doc/code/hooks.rst
Normal file
@ -0,0 +1,171 @@
|
||||
.. highlight:: c
|
||||
|
||||
Hooks
|
||||
=====
|
||||
|
||||
Libfrr provides type-safe subscribable hook points where other pieces of
|
||||
code can add one or more callback functions. "type-safe" in this case
|
||||
applies to the function pointers used for subscriptions. The
|
||||
implementations checks (at compile-time) wheter a callback to be added has
|
||||
the appropriate function signature (parameters) for the hook.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: c
|
||||
:caption: mydaemon.h
|
||||
|
||||
#include "hook.h"
|
||||
DECLARE_HOOK(some_update_event, (struct eventinfo *info), (info))
|
||||
|
||||
.. code-block:: c
|
||||
:caption: mydaemon.c
|
||||
|
||||
#include "mydaemon.h"
|
||||
DEFINE_HOOK(some_update_event, (struct eventinfo *info), (info))
|
||||
...
|
||||
hook_call(some_update_event, info);
|
||||
|
||||
.. code-block:: c
|
||||
:caption: mymodule.c
|
||||
|
||||
#include "mydaemon.h"
|
||||
static int event_handler(struct eventinfo *info);
|
||||
...
|
||||
hook_register(some_update_event, event_handler);
|
||||
|
||||
Do not use parameter names starting with "hook", these can collide with
|
||||
names used by the hook code itself.
|
||||
|
||||
|
||||
Return values
|
||||
-------------
|
||||
|
||||
Callbacks to be placed on hooks always return "int" for now; hook_call will
|
||||
sum up the return values from each called function. (The default is 0 if no
|
||||
callbacks are registered.)
|
||||
|
||||
There are no pre-defined semantics for the value, in most cases it is
|
||||
ignored. For success/failure indication, 0 should be success, and
|
||||
handlers should make sure to only return 0 or 1 (not -1 or other values).
|
||||
|
||||
There is no built-in way to abort executing a chain after a failure of one
|
||||
of the callbacks. If this is needed, the hook can use an extra
|
||||
``bool *aborted`` argument.
|
||||
|
||||
|
||||
Priorities
|
||||
----------
|
||||
|
||||
Hooks support a "priority" value for ordering registered calls
|
||||
relative to each other. The priority is a signed integer where lower
|
||||
values are called earlier. There are also "Koohs", which is hooks with
|
||||
reverse priority ordering (for cleanup/deinit hooks, so you can use the
|
||||
same priority value).
|
||||
|
||||
Recommended priority value ranges are:
|
||||
|
||||
======================== ===================================================
|
||||
Range Usage
|
||||
------------------------ ---------------------------------------------------
|
||||
-999 ... 0 ... 999 main executable / daemon, or library
|
||||
|
||||
-1999 ... -1000 modules registering calls that should run before
|
||||
the daemon's bits
|
||||
|
||||
1000 ... 1999 modules' calls that should run after daemon's
|
||||
(includes default value: 1000)
|
||||
======================== ===================================================
|
||||
|
||||
Note: the default value is 1000, based on the following 2 expectations:
|
||||
|
||||
- most hook_register() usage will be in loadable modules
|
||||
- usage of hook_register() in the daemon itself may need relative ordering
|
||||
to itself, making an explicit value the expected case
|
||||
|
||||
The priority value is passed as extra argument on hook_register_prio() /
|
||||
hook_register_arg_prio(). Whether a hook runs in reverse is determined
|
||||
solely by the code defining / calling the hook. (DECLARE_KOOH is actually
|
||||
the same thing as DECLARE_HOOK, it's just there to make it obvious.)
|
||||
|
||||
|
||||
Definition
|
||||
----------
|
||||
|
||||
.. c:macro:: DECLARE_HOOK(name, arglist, passlist)
|
||||
.. c:macro:: DECLARE_KOOH(name, arglist, passlist)
|
||||
|
||||
:param name: Name of the hook to be defined
|
||||
:param arglist: Function definition style parameter list in braces.
|
||||
:param passlist: List of the same parameters without their types.
|
||||
|
||||
Note: the second and third macro args must be the hook function's
|
||||
parameter list, with the same names for each parameter. The second
|
||||
macro arg is with types (used for defining things), the third arg is
|
||||
just the names (used for passing along parameters).
|
||||
|
||||
This macro must be placed in a header file; this header file must be
|
||||
included to register a callback on the hook.
|
||||
|
||||
Examples:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
DECLARE_HOOK(foo, (), ())
|
||||
DECLARE_HOOK(bar, (int arg), (arg))
|
||||
DECLARE_HOOK(baz, (const void *x, in_addr_t y), (x, y))
|
||||
|
||||
.. c:macro:: DEFINE_HOOK(name, arglist, passlist)
|
||||
|
||||
Implements an hook. Each ``DECLARE_HOOK`` must have be accompanied by
|
||||
exactly one ``DEFINE_HOOK``, which needs to be placed in a source file.
|
||||
**The hook can only be called from this source file.** This is intentional
|
||||
to avoid overloading and/or misusing hooks for distinct purposes.
|
||||
|
||||
The compiled source file will include a global symbol with the name of the
|
||||
hook prefixed by `_hook_`. Trying to register a callback for a hook that
|
||||
doesn't exist will therefore result in a linker error, or a module
|
||||
load-time error for dynamic modules.
|
||||
|
||||
.. c:macro:: DEFINE_KOOH(name, arglist, passlist)
|
||||
|
||||
Same as ``DEFINE_HOOK``, but the sense of priorities / order of callbacks
|
||||
is reversed. This should be used for cleanup hooks.
|
||||
|
||||
.. c:function:: int hook_call(name, ...)
|
||||
|
||||
Calls the specified named hook. Parameters to the hook are passed right
|
||||
after the hook name, e.g.:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
hook_call(foo);
|
||||
hook_call(bar, 0);
|
||||
hook_call(baz, NULL, INADDR_ANY);
|
||||
|
||||
Returns the sum of return values from all callbacks. The ``DEFINE_HOOK``
|
||||
statement for the hook must be placed in the file before any ``hook_call``
|
||||
use of the hook.
|
||||
|
||||
|
||||
Callback registration
|
||||
---------------------
|
||||
|
||||
.. c:function:: void hook_register(name, int (*callback)(...))
|
||||
.. c:function:: void hook_register_prio(name, int priority, int (*callback)(...))
|
||||
.. c:function:: void hook_register_arg(name, int (*callback)(void *arg, ...), void *arg)
|
||||
.. c:function:: void hook_register_arg_prio(name, int priority, int (*callback)(void *arg, ...), void *arg)
|
||||
|
||||
Register a callback with an hook. If the caller needs to pass an extra
|
||||
argument to the callback, the _arg variant can be used and the extra
|
||||
parameter will be passed as first argument to the callback. There is no
|
||||
typechecking for this argument.
|
||||
|
||||
The priority value is used as described above. The variants without a
|
||||
priority parameter use 1000 as priority value.
|
||||
|
||||
.. c:function:: void hook_unregister(name, int (*callback)(...))
|
||||
.. c:function:: void hook_unregister_arg(name, int (*callback)(void *arg, ...), void *arg)
|
||||
|
||||
Removes a previously registered callback from a hook. Note that there
|
||||
is no _prio variant of these calls. The priority value is only used during
|
||||
registration.
|
18
doc/code/index.rst
Normal file
18
doc/code/index.rst
Normal file
@ -0,0 +1,18 @@
|
||||
Welcome to FRR's documentation!
|
||||
===============================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
library
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
10
doc/code/library.rst
Normal file
10
doc/code/library.rst
Normal file
@ -0,0 +1,10 @@
|
||||
libfrr library facilities
|
||||
=========================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
memtypes
|
||||
hooks
|
||||
|
||||
|
117
doc/code/memtypes.rst
Normal file
117
doc/code/memtypes.rst
Normal file
@ -0,0 +1,117 @@
|
||||
.. highlight:: c
|
||||
|
||||
Memtypes
|
||||
========
|
||||
|
||||
FRR includes wrappers arround ``malloc()`` and ``free()`` that count the number
|
||||
of objects currently allocated, for each of a defined ``MTYPE``.
|
||||
|
||||
To this extent, there are `memory groups` and `memory types`. Each memory
|
||||
type must belong to a memory group, this is used just to provide some basic
|
||||
structure.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: c
|
||||
:caption: mydaemon.h
|
||||
|
||||
DECLARE_MGROUP(MYDAEMON)
|
||||
DECLARE_MTYPE(MYNEIGHBOR)
|
||||
|
||||
.. code-block:: c
|
||||
:caption: mydaemon.c
|
||||
|
||||
DEFINE_MGROUP( MYDAEMON, "My daemon's memory")
|
||||
DEFINE_MTYPE( MYDAEMON, MYNEIGHBOR, "Neighbor entry")
|
||||
DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name")
|
||||
|
||||
struct neigh *neighbor_new(const char *name)
|
||||
{
|
||||
struct neigh *n = XMALLOC(MYNEIGHBOR, sizeof(*n));
|
||||
n->name = XSTRDUP(MYNEIGHBORNAME, name);
|
||||
return n;
|
||||
}
|
||||
|
||||
void neighbor_free(struct neigh *n)
|
||||
{
|
||||
XFREE(MYNEIGHBORNAME, n->name);
|
||||
XFREE(MYNEIGHBOR, n);
|
||||
}
|
||||
|
||||
|
||||
Definition
|
||||
----------
|
||||
|
||||
.. c:macro:: DECLARE_MGROUP(name)
|
||||
|
||||
This macro forward-declares a memory group and should be placed in a
|
||||
``.h`` file. It expands to an ``extern struct memgroup`` statement.
|
||||
|
||||
.. c:macro:: DEFINE_MGROUP(mname, description)
|
||||
|
||||
Defines/implements a memory group. Must be placed into exactly one ``.c``
|
||||
file (multiple inclusion will result in a link-time symbol conflict).
|
||||
|
||||
Contains additional logic (constructor and destructor) to register the
|
||||
memory group in a global list.
|
||||
|
||||
.. c:macro:: DECLARE_MTYPE(name)
|
||||
|
||||
Forward-declares a memory type and makes ``MTYPE_name`` available for use.
|
||||
Note that the ``MTYPE_`` prefix must not be included in the name, it is
|
||||
automatically prefixed.
|
||||
|
||||
``MTYPE_name`` is created as a `static const` symbol, i.e. a compile-time
|
||||
constant. It refers to an ``extern struct memtype _mt_name``, where `name`
|
||||
is replaced with the actual name.
|
||||
|
||||
.. c:macro:: DEFINE_MTYPE(group, name, description)
|
||||
|
||||
Define/implement a memory type, must be placed into exactly one ``.c``
|
||||
file (multiple inclusion will result in a link-time symbol conflict).
|
||||
|
||||
Like ``DEFINE_MGROUP``, this contains actual code to register the MTYPE
|
||||
under its group.
|
||||
|
||||
.. c:macro:: DEFINE_MTYPE_STATIC(group, name, description)
|
||||
|
||||
Same as ``DEFINE_MTYPE``, but the ``DEFINE_MTYPE_STATIC`` variant places
|
||||
the C ``static`` keyword on the definition, restricting the MTYPE's
|
||||
availability to the current source file. This should be appropriate in
|
||||
>80% of cases.
|
||||
|
||||
.. todo::
|
||||
|
||||
Daemons currently have ``daemon_memory.[ch]`` files listing all of
|
||||
their MTYPEs. This is not how it should be, most of these types
|
||||
should be moved into the appropriate files where they are used.
|
||||
Only a few MTYPEs should remain non-static after that.
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
.. c:function:: void *XMALLOC(struct memtype *mtype, size_t size)
|
||||
|
||||
.. c:function:: void *XCALLOC(struct memtype *mtype, size_t size)
|
||||
|
||||
.. c:function:: void *XSTRDUP(struct memtype *mtype, size_t size)
|
||||
|
||||
Allocation wrappers for malloc/calloc/realloc/strdup, taking an extra
|
||||
mtype parameter.
|
||||
|
||||
.. c:function:: void *XREALLOC(struct memtype *mtype, void *ptr, size_t size)
|
||||
|
||||
Wrapper around realloc() with MTYPE tracking. Note that ``ptr`` may
|
||||
be NULL, in which case the function does the same as XMALLOC (regardless
|
||||
of whether the system realloc() supports this.)
|
||||
|
||||
.. c:function:: void XFREE(struct memtype *mtype, void *ptr)
|
||||
|
||||
Wrapper around free(), again taking an extra mtype parameter. This is
|
||||
actually a macro, with the following additional properties:
|
||||
|
||||
- the macro contains ``ptr = NULL``
|
||||
- if ptr is NULL, no operation is performed (as is guaranteed by system
|
||||
implementations.) Do not surround XFREE with ``if (ptr != NULL)``
|
||||
checks.
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 *);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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')
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -21,7 +21,7 @@
|
||||
#ifndef _LDE_H_
|
||||
#define _LDE_H_
|
||||
|
||||
#include "openbsd-queue.h"
|
||||
#include "queue.h"
|
||||
#include "openbsd-tree.h"
|
||||
#include "if.h"
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
105
ldpd/ldp_zebra.c
105
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -21,7 +21,7 @@
|
||||
#ifndef _LDPE_H_
|
||||
#define _LDPE_H_
|
||||
|
||||
#include "openbsd-queue.h"
|
||||
#include "queue.h"
|
||||
#include "openbsd-tree.h"
|
||||
#ifdef __OpenBSD__
|
||||
#include <net/pfkeyv2.h>
|
||||
|
@ -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);
|
||||
|
@ -46,8 +46,9 @@ DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack")
|
||||
static int add_nexthops(struct list *, struct graph_node *,
|
||||
struct graph_node **, size_t);
|
||||
|
||||
static struct list *command_match_r(struct graph_node *, vector, unsigned int,
|
||||
struct graph_node **);
|
||||
static enum matcher_rv command_match_r(struct graph_node *, vector,
|
||||
unsigned int, struct graph_node **,
|
||||
struct list **);
|
||||
|
||||
static int score_precedence(enum cmd_token_type);
|
||||
|
||||
@ -80,14 +81,12 @@ static enum match_type match_variable(struct cmd_token *, const char *);
|
||||
|
||||
static enum match_type match_mac(const char *, bool);
|
||||
|
||||
/* matching functions */
|
||||
static enum matcher_rv matcher_rv;
|
||||
|
||||
enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
|
||||
struct list **argv, const struct cmd_element **el)
|
||||
{
|
||||
struct graph_node *stack[MAXDEPTH];
|
||||
matcher_rv = MATCHER_NO_MATCH;
|
||||
enum matcher_rv status;
|
||||
*argv = NULL;
|
||||
|
||||
// prepend a dummy token to match that pesky start node
|
||||
vector vvline = vector_init(vline->alloced + 1);
|
||||
@ -97,9 +96,8 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
|
||||
vvline->active = vline->active + 1;
|
||||
|
||||
struct graph_node *start = vector_slot(cmdgraph->nodes, 0);
|
||||
if ((*argv = command_match_r(start, vvline, 0,
|
||||
stack))) // successful match
|
||||
{
|
||||
status = command_match_r(start, vvline, 0, stack, argv);
|
||||
if (status == MATCHER_OK) { // successful match
|
||||
struct listnode *head = listhead(*argv);
|
||||
struct listnode *tail = listtail(*argv);
|
||||
|
||||
@ -115,6 +113,9 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
|
||||
// input, with each cmd_token->arg holding the corresponding
|
||||
// input
|
||||
assert(*el);
|
||||
} else if (*argv) {
|
||||
del_arglist(*argv);
|
||||
*argv = NULL;
|
||||
}
|
||||
|
||||
if (!*el) {
|
||||
@ -129,7 +130,7 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
|
||||
// free vector
|
||||
vector_free(vvline);
|
||||
|
||||
return matcher_rv;
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,11 +184,15 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
|
||||
*
|
||||
* If no match was found, the return value is NULL.
|
||||
*/
|
||||
static struct list *command_match_r(struct graph_node *start, vector vline,
|
||||
unsigned int n, struct graph_node **stack)
|
||||
static enum matcher_rv command_match_r(struct graph_node *start, vector vline,
|
||||
unsigned int n,
|
||||
struct graph_node **stack,
|
||||
struct list **currbest)
|
||||
{
|
||||
assert(n < vector_active(vline));
|
||||
|
||||
enum matcher_rv status = MATCHER_NO_MATCH;
|
||||
|
||||
// get the minimum match level that can count as a full match
|
||||
struct cmd_token *token = start->data;
|
||||
enum match_type minmatch = min_match_level(token->type);
|
||||
@ -196,11 +201,11 @@ static struct list *command_match_r(struct graph_node *start, vector vline,
|
||||
* this disallows matching the same one more than once if there is a
|
||||
* circle in the graph (used for keyword arguments) */
|
||||
if (n == MAXDEPTH)
|
||||
return NULL;
|
||||
return MATCHER_NO_MATCH;
|
||||
if (!token->allowrepeat)
|
||||
for (size_t s = 0; s < n; s++)
|
||||
if (stack[s] == start)
|
||||
return NULL;
|
||||
return MATCHER_NO_MATCH;
|
||||
|
||||
// get the current operating input token
|
||||
char *input_token = vector_slot(vline, n);
|
||||
@ -231,7 +236,7 @@ static struct list *command_match_r(struct graph_node *start, vector vline,
|
||||
|
||||
// if we don't match this node, die
|
||||
if (match_token(token, input_token) < minmatch)
|
||||
return NULL;
|
||||
return MATCHER_NO_MATCH;
|
||||
|
||||
stack[n] = start;
|
||||
|
||||
@ -244,86 +249,92 @@ static struct list *command_match_r(struct graph_node *start, vector vline,
|
||||
add_nexthops(next, start, NULL, 0);
|
||||
|
||||
// determine the best match
|
||||
int ambiguous = 0;
|
||||
struct list *currbest = NULL;
|
||||
for (ALL_LIST_ELEMENTS_RO(next, ln, gn)) {
|
||||
// if we've matched all input we're looking for END_TKN
|
||||
if (n + 1 == vector_active(vline)) {
|
||||
struct cmd_token *tok = gn->data;
|
||||
if (tok->type == END_TKN) {
|
||||
if (currbest) // there is more than one END_TKN
|
||||
// in the follow set
|
||||
{
|
||||
ambiguous = 1;
|
||||
// if more than one END_TKN in the follow set
|
||||
if (*currbest) {
|
||||
status = MATCHER_AMBIGUOUS;
|
||||
break;
|
||||
} else {
|
||||
status = MATCHER_OK;
|
||||
}
|
||||
currbest = list_new();
|
||||
*currbest = list_new();
|
||||
// node should have one child node with the
|
||||
// element
|
||||
struct graph_node *leaf =
|
||||
vector_slot(gn->to, 0);
|
||||
// last node in the list will hold the
|
||||
// cmd_element;
|
||||
// this is important because list_delete()
|
||||
// expects
|
||||
// that all nodes have the same data type, so
|
||||
// when
|
||||
// deleting this list the last node must be
|
||||
// manually deleted
|
||||
// cmd_element; this is important because
|
||||
// list_delete() expects that all nodes have
|
||||
// the same data type, so when deleting this
|
||||
// list the last node must be manually deleted
|
||||
struct cmd_element *el = leaf->data;
|
||||
listnode_add(currbest, el);
|
||||
currbest->del =
|
||||
listnode_add(*currbest, el);
|
||||
(*currbest)->del =
|
||||
(void (*)(void *)) & cmd_token_del;
|
||||
// do not break immediately; continue walking
|
||||
// through the follow set
|
||||
// to ensure that there is exactly one END_TKN
|
||||
// through the follow set to ensure that there
|
||||
// is exactly one END_TKN
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// else recurse on candidate child node
|
||||
struct list *result = command_match_r(gn, vline, n + 1, stack);
|
||||
struct list *result = NULL;
|
||||
enum matcher_rv rstat =
|
||||
command_match_r(gn, vline, n + 1, stack, &result);
|
||||
|
||||
// save the best match
|
||||
if (result && currbest) {
|
||||
if (result && *currbest) {
|
||||
// pick the best of two matches
|
||||
struct list *newbest =
|
||||
disambiguate(currbest, result, vline, n + 1);
|
||||
// set ambiguity flag
|
||||
ambiguous =
|
||||
!newbest || (ambiguous && newbest == currbest);
|
||||
disambiguate(*currbest, result, vline, n + 1);
|
||||
|
||||
// current best and result are ambiguous
|
||||
if (!newbest)
|
||||
status = MATCHER_AMBIGUOUS;
|
||||
// current best is still the best, but ambiguous
|
||||
else if (newbest == *currbest
|
||||
&& status == MATCHER_AMBIGUOUS)
|
||||
status = MATCHER_AMBIGUOUS;
|
||||
// result is better, but also ambiguous
|
||||
else if (newbest == result
|
||||
&& rstat == MATCHER_AMBIGUOUS)
|
||||
status = MATCHER_AMBIGUOUS;
|
||||
// one or the other is superior and not ambiguous
|
||||
else
|
||||
status = MATCHER_OK;
|
||||
|
||||
// delete the unnecessary result
|
||||
struct list *todelete =
|
||||
((newbest && newbest == result) ? currbest
|
||||
((newbest && newbest == result) ? *currbest
|
||||
: result);
|
||||
del_arglist(todelete);
|
||||
|
||||
currbest = newbest ? newbest : currbest;
|
||||
} else if (result)
|
||||
currbest = result;
|
||||
}
|
||||
|
||||
if (currbest) {
|
||||
if (ambiguous) {
|
||||
del_arglist(currbest);
|
||||
currbest = NULL;
|
||||
matcher_rv = MATCHER_AMBIGUOUS;
|
||||
} else {
|
||||
// copy token, set arg and prepend to currbest
|
||||
struct cmd_token *token = start->data;
|
||||
struct cmd_token *copy = cmd_token_dup(token);
|
||||
copy->arg = XSTRDUP(MTYPE_CMD_ARG, input_token);
|
||||
listnode_add_before(currbest, currbest->head, copy);
|
||||
matcher_rv = MATCHER_OK;
|
||||
*currbest = newbest ? newbest : *currbest;
|
||||
} else if (result) {
|
||||
status = rstat;
|
||||
*currbest = result;
|
||||
} else if (!*currbest) {
|
||||
status = MAX(rstat, status);
|
||||
}
|
||||
} else if (n + 1 == vector_active(vline)
|
||||
&& matcher_rv == MATCHER_NO_MATCH)
|
||||
matcher_rv = MATCHER_INCOMPLETE;
|
||||
}
|
||||
if (*currbest) {
|
||||
// copy token, set arg and prepend to currbest
|
||||
struct cmd_token *token = start->data;
|
||||
struct cmd_token *copy = cmd_token_dup(token);
|
||||
copy->arg = XSTRDUP(MTYPE_CMD_ARG, input_token);
|
||||
listnode_add_before(*currbest, (*currbest)->head, copy);
|
||||
} else if (n + 1 == vector_active(vline) && status == MATCHER_NO_MATCH)
|
||||
status = MATCHER_INCOMPLETE;
|
||||
|
||||
// cleanup
|
||||
list_delete(next);
|
||||
|
||||
return currbest;
|
||||
return status;
|
||||
}
|
||||
|
||||
static void stack_del(void *val)
|
||||
@ -432,12 +443,12 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
|
||||
* next = set of all nodes reachable from all nodes in `matched`
|
||||
*/
|
||||
|
||||
matcher_rv = idx == vector_active(vline) && next->count
|
||||
? MATCHER_OK
|
||||
: MATCHER_NO_MATCH;
|
||||
enum matcher_rv mrv = idx == vector_active(vline) && next->count
|
||||
? MATCHER_OK
|
||||
: MATCHER_NO_MATCH;
|
||||
|
||||
*completions = NULL;
|
||||
if (!MATCHER_ERROR(matcher_rv)) {
|
||||
if (!MATCHER_ERROR(mrv)) {
|
||||
// extract cmd_token into list
|
||||
*completions = list_new();
|
||||
for (ALL_LIST_ELEMENTS_RO(next, node, gstack)) {
|
||||
@ -448,7 +459,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
|
||||
list_delete(current);
|
||||
list_delete(next);
|
||||
|
||||
return matcher_rv;
|
||||
return mrv;
|
||||
}
|
||||
|
||||
/**
|
||||
|
81
lib/compiler.h
Normal file
81
lib/compiler.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2017 David Lamparter, for NetDEF, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _FRR_COMPILER_H
|
||||
#define _FRR_COMPILER_H
|
||||
|
||||
/* function attributes, use like
|
||||
* void prototype(void) __attribute__((_CONSTRUCTOR(100)));
|
||||
*/
|
||||
#if defined(__clang__)
|
||||
# if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5)
|
||||
# define _RET_NONNULL , returns_nonnull
|
||||
# endif
|
||||
# define _CONSTRUCTOR(x) constructor(x)
|
||||
#elif defined(__GNUC__)
|
||||
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
|
||||
# define _RET_NONNULL , returns_nonnull
|
||||
# endif
|
||||
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
|
||||
# define _CONSTRUCTOR(x) constructor(x)
|
||||
# define _DESTRUCTOR(x) destructor(x)
|
||||
# define _ALLOC_SIZE(x) alloc_size(x)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __sun
|
||||
/* Solaris doesn't do constructor priorities due to linker restrictions */
|
||||
# undef _CONSTRUCTOR
|
||||
# undef _DESTRUCTOR
|
||||
#endif
|
||||
|
||||
/* fallback versions */
|
||||
#ifndef _RET_NONNULL
|
||||
# define _RET_NONNULL
|
||||
#endif
|
||||
#ifndef _CONSTRUCTOR
|
||||
# define _CONSTRUCTOR(x) constructor
|
||||
#endif
|
||||
#ifndef _DESTRUCTOR
|
||||
# define _DESTRUCTOR(x) destructor
|
||||
#endif
|
||||
#ifndef _ALLOC_SIZE
|
||||
# define _ALLOC_SIZE(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* for warnings on macros, put in the macro content like this:
|
||||
* #define MACRO BLA CPP_WARN("MACRO has been deprecated")
|
||||
*/
|
||||
#define CPP_STR(X) #X
|
||||
|
||||
#if defined(__ICC)
|
||||
#define CPP_NOTICE(text) _Pragma(CPP_STR(message __FILE__ ": " text))
|
||||
#define CPP_WARN(text) CPP_NOTICE(text)
|
||||
|
||||
#elif (defined(__GNUC__) \
|
||||
&& (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \
|
||||
|| (defined(__clang__) \
|
||||
&& (__clang_major__ >= 4 \
|
||||
|| (__clang_major__ == 3 && __clang_minor__ >= 5)))
|
||||
#define CPP_WARN(text) _Pragma(CPP_STR(GCC warning text))
|
||||
#define CPP_NOTICE(text) _Pragma(CPP_STR(message text))
|
||||
|
||||
#else
|
||||
#define CPP_WARN(text)
|
||||
#endif
|
||||
|
||||
#endif /* _FRR_COMPILER_H */
|
679
lib/freebsd-queue.h
Normal file
679
lib/freebsd-queue.h
Normal file
@ -0,0 +1,679 @@
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SYS_QUEUE_H_
|
||||
#define _SYS_QUEUE_H_
|
||||
|
||||
/*
|
||||
* This file defines four types of data structures: singly-linked lists,
|
||||
* singly-linked tail queues, lists and tail queues.
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The elements
|
||||
* are singly linked for minimum space and pointer manipulation overhead at
|
||||
* the expense of O(n) removal for arbitrary elements. New elements can be
|
||||
* added to the list after an existing element or at the head of the list.
|
||||
* Elements being removed from the head of the list should use the explicit
|
||||
* macro for this purpose for optimum efficiency. A singly-linked list may
|
||||
* only be traversed in the forward direction. Singly-linked lists are ideal
|
||||
* for applications with large datasets and few or no removals or for
|
||||
* implementing a LIFO queue.
|
||||
*
|
||||
* A singly-linked tail queue is headed by a pair of pointers, one to the
|
||||
* head of the list and the other to the tail of the list. The elements are
|
||||
* singly linked for minimum space and pointer manipulation overhead at the
|
||||
* expense of O(n) removal for arbitrary elements. New elements can be added
|
||||
* to the list after an existing element, at the head of the list, or at the
|
||||
* end of the list. Elements being removed from the head of the tail queue
|
||||
* should use the explicit macro for this purpose for optimum efficiency.
|
||||
* A singly-linked tail queue may only be traversed in the forward direction.
|
||||
* Singly-linked tail queues are ideal for applications with large datasets
|
||||
* and few or no removals or for implementing a FIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may only be traversed in the forward direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*
|
||||
*
|
||||
* SLIST LIST STAILQ TAILQ
|
||||
* _HEAD + + + +
|
||||
* _HEAD_INITIALIZER + + + +
|
||||
* _ENTRY + + + +
|
||||
* _INIT + + + +
|
||||
* _EMPTY + + + +
|
||||
* _FIRST + + + +
|
||||
* _NEXT + + + +
|
||||
* _PREV - - - +
|
||||
* _LAST - - + +
|
||||
* _FOREACH + + + +
|
||||
* _FOREACH_SAFE + + + +
|
||||
* _FOREACH_REVERSE - - - +
|
||||
* _FOREACH_REVERSE_SAFE - - - +
|
||||
* _INSERT_HEAD + + + +
|
||||
* _INSERT_BEFORE - + - +
|
||||
* _INSERT_AFTER + + + +
|
||||
* _INSERT_TAIL - - + +
|
||||
* _CONCAT - - + +
|
||||
* _REMOVE_AFTER + - + -
|
||||
* _REMOVE_HEAD + - + -
|
||||
* _REMOVE + + + +
|
||||
* _SWAP + + + +
|
||||
*
|
||||
*/
|
||||
#ifdef QUEUE_MACRO_DEBUG
|
||||
/* Store the last 2 places the queue element or head was altered */
|
||||
struct qm_trace {
|
||||
char *lastfile;
|
||||
int lastline;
|
||||
char *prevfile;
|
||||
int prevline;
|
||||
};
|
||||
|
||||
#define TRACEBUF struct qm_trace trace;
|
||||
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
|
||||
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
|
||||
|
||||
#define QMD_TRACE_HEAD(head) \
|
||||
do { \
|
||||
(head)->trace.prevline = (head)->trace.lastline; \
|
||||
(head)->trace.prevfile = (head)->trace.lastfile; \
|
||||
(head)->trace.lastline = __LINE__; \
|
||||
(head)->trace.lastfile = __FILE__; \
|
||||
} while (0)
|
||||
|
||||
#define QMD_TRACE_ELEM(elem) \
|
||||
do { \
|
||||
(elem)->trace.prevline = (elem)->trace.lastline; \
|
||||
(elem)->trace.prevfile = (elem)->trace.lastfile; \
|
||||
(elem)->trace.lastline = __LINE__; \
|
||||
(elem)->trace.lastfile = __FILE__; \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#define QMD_TRACE_ELEM(elem)
|
||||
#define QMD_TRACE_HEAD(head)
|
||||
#define QMD_SAVELINK(name, link)
|
||||
#define TRACEBUF
|
||||
#define TRASHIT(x)
|
||||
#endif /* QUEUE_MACRO_DEBUG */
|
||||
|
||||
/*
|
||||
* Singly-linked List declarations.
|
||||
*/
|
||||
#define SLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_HEAD_INITIALIZER(head) \
|
||||
{ \
|
||||
NULL \
|
||||
}
|
||||
|
||||
#define SLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
|
||||
|
||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||
|
||||
#define SLIST_FOREACH(var, head, field) \
|
||||
for ((var) = SLIST_FIRST((head)); (var); \
|
||||
(var) = SLIST_NEXT((var), field))
|
||||
|
||||
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = SLIST_FIRST((head)); \
|
||||
(var) && ((tvar) = SLIST_NEXT((var), field), 1); (var) = (tvar))
|
||||
|
||||
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
|
||||
for ((varp) = &SLIST_FIRST((head)); ((var) = *(varp)) != NULL; \
|
||||
(varp) = &SLIST_NEXT((var), field))
|
||||
|
||||
#define SLIST_INIT(head) \
|
||||
do { \
|
||||
SLIST_FIRST((head)) = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) \
|
||||
do { \
|
||||
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
|
||||
SLIST_NEXT((slistelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_HEAD(head, elm, field) \
|
||||
do { \
|
||||
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
|
||||
SLIST_FIRST((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
#define SLIST_REMOVE(head, elm, type, field) \
|
||||
do { \
|
||||
QMD_SAVELINK(oldnext, (elm)->field.sle_next); \
|
||||
if (SLIST_FIRST((head)) == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
struct type *curelm = SLIST_FIRST((head)); \
|
||||
while (SLIST_NEXT(curelm, field) != (elm)) \
|
||||
curelm = SLIST_NEXT(curelm, field); \
|
||||
SLIST_REMOVE_AFTER(curelm, field); \
|
||||
} \
|
||||
TRASHIT(*oldnext); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_AFTER(elm, field) \
|
||||
do { \
|
||||
SLIST_NEXT(elm, field) = \
|
||||
SLIST_NEXT(SLIST_NEXT(elm, field), field); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_HEAD(head, field) \
|
||||
do { \
|
||||
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_SWAP(head1, head2, type) \
|
||||
do { \
|
||||
struct type *swap_first = SLIST_FIRST(head1); \
|
||||
SLIST_FIRST(head1) = SLIST_FIRST(head2); \
|
||||
SLIST_FIRST(head2) = swap_first; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue declarations.
|
||||
*/
|
||||
#define STAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *stqh_first; /* first element */ \
|
||||
struct type **stqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define STAILQ_HEAD_INITIALIZER(head) \
|
||||
{ \
|
||||
NULL, &(head).stqh_first \
|
||||
}
|
||||
|
||||
#define STAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *stqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue functions.
|
||||
*/
|
||||
#define STAILQ_CONCAT(head1, head2) \
|
||||
do { \
|
||||
if (!STAILQ_EMPTY((head2))) { \
|
||||
*(head1)->stqh_last = (head2)->stqh_first; \
|
||||
(head1)->stqh_last = (head2)->stqh_last; \
|
||||
STAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
|
||||
|
||||
#define STAILQ_FIRST(head) ((head)->stqh_first)
|
||||
|
||||
#define STAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = STAILQ_FIRST((head)); (var); \
|
||||
(var) = STAILQ_NEXT((var), field))
|
||||
|
||||
|
||||
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = STAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); (var) = (tvar))
|
||||
|
||||
#define STAILQ_INIT(head) \
|
||||
do { \
|
||||
STAILQ_FIRST((head)) = NULL; \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) \
|
||||
do { \
|
||||
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) \
|
||||
== NULL) \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
STAILQ_NEXT((tqelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_HEAD(head, elm, field) \
|
||||
do { \
|
||||
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) \
|
||||
== NULL) \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
STAILQ_FIRST((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_TAIL(head, elm, field) \
|
||||
do { \
|
||||
STAILQ_NEXT((elm), field) = NULL; \
|
||||
*(head)->stqh_last = (elm); \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_LAST(head, type, field) \
|
||||
(STAILQ_EMPTY((head)) \
|
||||
? NULL \
|
||||
: ((struct type *)(void *)((char *)((head)->stqh_last) \
|
||||
- offsetof(struct type, \
|
||||
field))))
|
||||
|
||||
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
|
||||
|
||||
#define STAILQ_REMOVE(head, elm, type, field) \
|
||||
do { \
|
||||
QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
|
||||
if (STAILQ_FIRST((head)) == (elm)) { \
|
||||
STAILQ_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
struct type *curelm = STAILQ_FIRST((head)); \
|
||||
while (STAILQ_NEXT(curelm, field) != (elm)) \
|
||||
curelm = STAILQ_NEXT(curelm, field); \
|
||||
STAILQ_REMOVE_AFTER(head, curelm, field); \
|
||||
} \
|
||||
TRASHIT(*oldnext); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE_AFTER(head, elm, field) \
|
||||
do { \
|
||||
if ((STAILQ_NEXT(elm, field) = \
|
||||
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) \
|
||||
== NULL) \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE_HEAD(head, field) \
|
||||
do { \
|
||||
if ((STAILQ_FIRST((head)) = \
|
||||
STAILQ_NEXT(STAILQ_FIRST((head)), field)) \
|
||||
== NULL) \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_SWAP(head1, head2, type) \
|
||||
do { \
|
||||
struct type *swap_first = STAILQ_FIRST(head1); \
|
||||
struct type **swap_last = (head1)->stqh_last; \
|
||||
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
|
||||
(head1)->stqh_last = (head2)->stqh_last; \
|
||||
STAILQ_FIRST(head2) = swap_first; \
|
||||
(head2)->stqh_last = swap_last; \
|
||||
if (STAILQ_EMPTY(head1)) \
|
||||
(head1)->stqh_last = &STAILQ_FIRST(head1); \
|
||||
if (STAILQ_EMPTY(head2)) \
|
||||
(head2)->stqh_last = &STAILQ_FIRST(head2); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* List declarations.
|
||||
*/
|
||||
#define LIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ \
|
||||
NULL \
|
||||
}
|
||||
|
||||
#define LIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
|
||||
#if (defined(_KERNEL) && defined(INVARIANTS))
|
||||
#define QMD_LIST_CHECK_HEAD(head, field) \
|
||||
do { \
|
||||
if (LIST_FIRST((head)) != NULL \
|
||||
&& LIST_FIRST((head))->field.le_prev \
|
||||
!= &LIST_FIRST((head))) \
|
||||
panic("Bad list head %p first->prev != head", (head)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_LIST_CHECK_NEXT(elm, field) \
|
||||
do { \
|
||||
if (LIST_NEXT((elm), field) != NULL \
|
||||
&& LIST_NEXT((elm), field)->field.le_prev \
|
||||
!= &((elm)->field.le_next)) \
|
||||
panic("Bad link elm %p next->prev != elm", (elm)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_LIST_CHECK_PREV(elm, field) \
|
||||
do { \
|
||||
if (*(elm)->field.le_prev != (elm)) \
|
||||
panic("Bad link elm %p prev->next != elm", (elm)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define QMD_LIST_CHECK_HEAD(head, field)
|
||||
#define QMD_LIST_CHECK_NEXT(elm, field)
|
||||
#define QMD_LIST_CHECK_PREV(elm, field)
|
||||
#endif /* (_KERNEL && INVARIANTS) */
|
||||
|
||||
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
|
||||
|
||||
#define LIST_FIRST(head) ((head)->lh_first)
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for ((var) = LIST_FIRST((head)); (var); (var) = LIST_NEXT((var), field))
|
||||
|
||||
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = LIST_FIRST((head)); \
|
||||
(var) && ((tvar) = LIST_NEXT((var), field), 1); (var) = (tvar))
|
||||
|
||||
#define LIST_INIT(head) \
|
||||
do { \
|
||||
LIST_FIRST((head)) = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_AFTER(listelm, elm, field) \
|
||||
do { \
|
||||
QMD_LIST_CHECK_NEXT(listelm, field); \
|
||||
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) \
|
||||
!= NULL) \
|
||||
LIST_NEXT((listelm), field)->field.le_prev = \
|
||||
&LIST_NEXT((elm), field); \
|
||||
LIST_NEXT((listelm), field) = (elm); \
|
||||
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_BEFORE(listelm, elm, field) \
|
||||
do { \
|
||||
QMD_LIST_CHECK_PREV(listelm, field); \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
LIST_NEXT((elm), field) = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_HEAD(head, elm, field) \
|
||||
do { \
|
||||
QMD_LIST_CHECK_HEAD((head), field); \
|
||||
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
|
||||
LIST_FIRST((head))->field.le_prev = \
|
||||
&LIST_NEXT((elm), field); \
|
||||
LIST_FIRST((head)) = (elm); \
|
||||
(elm)->field.le_prev = &LIST_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
#define LIST_REMOVE(elm, field) \
|
||||
do { \
|
||||
QMD_SAVELINK(oldnext, (elm)->field.le_next); \
|
||||
QMD_SAVELINK(oldprev, (elm)->field.le_prev); \
|
||||
QMD_LIST_CHECK_NEXT(elm, field); \
|
||||
QMD_LIST_CHECK_PREV(elm, field); \
|
||||
if (LIST_NEXT((elm), field) != NULL) \
|
||||
LIST_NEXT((elm), field)->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
|
||||
TRASHIT(*oldnext); \
|
||||
TRASHIT(*oldprev); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_SWAP(head1, head2, type, field) \
|
||||
do { \
|
||||
struct type *swap_tmp = LIST_FIRST((head1)); \
|
||||
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
|
||||
LIST_FIRST((head2)) = swap_tmp; \
|
||||
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
|
||||
swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
|
||||
if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
|
||||
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Tail queue declarations.
|
||||
*/
|
||||
#define TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *tqh_first; /* first element */ \
|
||||
struct type **tqh_last; /* addr of last next element */ \
|
||||
TRACEBUF \
|
||||
}
|
||||
|
||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ \
|
||||
NULL, &(head).tqh_first \
|
||||
}
|
||||
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
TRACEBUF \
|
||||
}
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#if (defined(_KERNEL) && defined(INVARIANTS))
|
||||
#define QMD_TAILQ_CHECK_HEAD(head, field) \
|
||||
do { \
|
||||
if (!TAILQ_EMPTY(head) \
|
||||
&& TAILQ_FIRST((head))->field.tqe_prev \
|
||||
!= &TAILQ_FIRST((head))) \
|
||||
panic("Bad tailq head %p first->prev != head", \
|
||||
(head)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_TAILQ_CHECK_TAIL(head, field) \
|
||||
do { \
|
||||
if (*(head)->tqh_last != NULL) \
|
||||
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_TAILQ_CHECK_NEXT(elm, field) \
|
||||
do { \
|
||||
if (TAILQ_NEXT((elm), field) != NULL \
|
||||
&& TAILQ_NEXT((elm), field)->field.tqe_prev \
|
||||
!= &((elm)->field.tqe_next)) \
|
||||
panic("Bad link elm %p next->prev != elm", (elm)); \
|
||||
} while (0)
|
||||
|
||||
#define QMD_TAILQ_CHECK_PREV(elm, field) \
|
||||
do { \
|
||||
if (*(elm)->field.tqe_prev != (elm)) \
|
||||
panic("Bad link elm %p prev->next != elm", (elm)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define QMD_TAILQ_CHECK_HEAD(head, field)
|
||||
#define QMD_TAILQ_CHECK_TAIL(head, headname)
|
||||
#define QMD_TAILQ_CHECK_NEXT(elm, field)
|
||||
#define QMD_TAILQ_CHECK_PREV(elm, field)
|
||||
#endif /* (_KERNEL && INVARIANTS) */
|
||||
|
||||
#define TAILQ_CONCAT(head1, head2, field) \
|
||||
do { \
|
||||
if (!TAILQ_EMPTY(head2)) { \
|
||||
*(head1)->tqh_last = (head2)->tqh_first; \
|
||||
(head2)->tqh_first->field.tqe_prev = \
|
||||
(head1)->tqh_last; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
TAILQ_INIT((head2)); \
|
||||
QMD_TRACE_HEAD(head1); \
|
||||
QMD_TRACE_HEAD(head2); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
||||
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = TAILQ_FIRST((head)); (var); \
|
||||
(var) = TAILQ_NEXT((var), field))
|
||||
|
||||
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); (var) = (tvar))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for ((var) = TAILQ_LAST((head), headname); (var); \
|
||||
(var) = TAILQ_PREV((var), headname, field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
|
||||
for ((var) = TAILQ_LAST((head), headname); \
|
||||
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
|
||||
(var) = (tvar))
|
||||
|
||||
#define TAILQ_INIT(head) \
|
||||
do { \
|
||||
TAILQ_FIRST((head)) = NULL; \
|
||||
(head)->tqh_last = &TAILQ_FIRST((head)); \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) \
|
||||
do { \
|
||||
QMD_TAILQ_CHECK_NEXT(listelm, field); \
|
||||
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) \
|
||||
!= NULL) \
|
||||
TAILQ_NEXT((elm), field)->field.tqe_prev = \
|
||||
&TAILQ_NEXT((elm), field); \
|
||||
else { \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
} \
|
||||
TAILQ_NEXT((listelm), field) = (elm); \
|
||||
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
QMD_TRACE_ELEM(&listelm->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) \
|
||||
do { \
|
||||
QMD_TAILQ_CHECK_PREV(listelm, field); \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
TAILQ_NEXT((elm), field) = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
QMD_TRACE_ELEM(&listelm->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) \
|
||||
do { \
|
||||
QMD_TAILQ_CHECK_HEAD(head, field); \
|
||||
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
|
||||
TAILQ_FIRST((head))->field.tqe_prev = \
|
||||
&TAILQ_NEXT((elm), field); \
|
||||
else \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
TAILQ_FIRST((head)) = (elm); \
|
||||
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) \
|
||||
do { \
|
||||
QMD_TAILQ_CHECK_TAIL(head, field); \
|
||||
TAILQ_NEXT((elm), field) = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
|
||||
#define TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) \
|
||||
do { \
|
||||
QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
|
||||
QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
|
||||
QMD_TAILQ_CHECK_NEXT(elm, field); \
|
||||
QMD_TAILQ_CHECK_PREV(elm, field); \
|
||||
if ((TAILQ_NEXT((elm), field)) != NULL) \
|
||||
TAILQ_NEXT((elm), field)->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else { \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
QMD_TRACE_HEAD(head); \
|
||||
} \
|
||||
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
|
||||
TRASHIT(*oldnext); \
|
||||
TRASHIT(*oldprev); \
|
||||
QMD_TRACE_ELEM(&(elm)->field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_SWAP(head1, head2, type, field) \
|
||||
do { \
|
||||
struct type *swap_first = (head1)->tqh_first; \
|
||||
struct type **swap_last = (head1)->tqh_last; \
|
||||
(head1)->tqh_first = (head2)->tqh_first; \
|
||||
(head1)->tqh_last = (head2)->tqh_last; \
|
||||
(head2)->tqh_first = swap_first; \
|
||||
(head2)->tqh_last = swap_last; \
|
||||
if ((swap_first = (head1)->tqh_first) != NULL) \
|
||||
swap_first->field.tqe_prev = &(head1)->tqh_first; \
|
||||
else \
|
||||
(head1)->tqh_last = &(head1)->tqh_first; \
|
||||
if ((swap_first = (head2)->tqh_first) != NULL) \
|
||||
swap_first->field.tqe_prev = &(head2)->tqh_first; \
|
||||
else \
|
||||
(head2)->tqh_last = &(head2)->tqh_first; \
|
||||
} while (0)
|
||||
|
||||
#endif /* !_SYS_QUEUE_H_ */
|
191
lib/frr_zmq.c
Normal file
191
lib/frr_zmq.c
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* libzebra ZeroMQ bindings
|
||||
* Copyright (C) 2015 David Lamparter
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
#include <zmq.h>
|
||||
|
||||
#include "thread.h"
|
||||
#include "memory.h"
|
||||
#include "frr_zmq.h"
|
||||
#include "log.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback")
|
||||
|
||||
/* libzmq's context */
|
||||
void *frrzmq_context = NULL;
|
||||
static unsigned frrzmq_initcount = 0;
|
||||
|
||||
void frrzmq_init(void)
|
||||
{
|
||||
if (frrzmq_initcount++ == 0) {
|
||||
frrzmq_context = zmq_ctx_new();
|
||||
zmq_ctx_set(frrzmq_context, ZMQ_IPV6, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void frrzmq_finish(void)
|
||||
{
|
||||
if (--frrzmq_initcount == 0) {
|
||||
zmq_ctx_term(frrzmq_context);
|
||||
frrzmq_context = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* read callback integration */
|
||||
struct frrzmq_cb {
|
||||
struct thread *thread;
|
||||
void *zmqsock;
|
||||
void *arg;
|
||||
int fd;
|
||||
|
||||
bool cancelled;
|
||||
|
||||
void (*cb_msg)(void *arg, void *zmqsock);
|
||||
void (*cb_part)(void *arg, void *zmqsock,
|
||||
zmq_msg_t *msg, unsigned partnum);
|
||||
};
|
||||
|
||||
|
||||
static int frrzmq_read_msg(struct thread *t)
|
||||
{
|
||||
struct frrzmq_cb *cb = THREAD_ARG(t);
|
||||
zmq_msg_t msg;
|
||||
unsigned partno;
|
||||
int ret, more;
|
||||
size_t moresz;
|
||||
|
||||
while (1) {
|
||||
zmq_pollitem_t polli = {
|
||||
.socket = cb->zmqsock,
|
||||
.events = ZMQ_POLLIN
|
||||
};
|
||||
ret = zmq_poll(&polli, 1, 0);
|
||||
|
||||
if (ret < 0)
|
||||
goto out_err;
|
||||
if (!(polli.revents & ZMQ_POLLIN))
|
||||
break;
|
||||
|
||||
if (cb->cb_msg) {
|
||||
cb->cb_msg(cb->arg, cb->zmqsock);
|
||||
|
||||
if (cb->cancelled) {
|
||||
XFREE(MTYPE_ZEROMQ_CB, cb);
|
||||
return 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
partno = 0;
|
||||
if (zmq_msg_init(&msg))
|
||||
goto out_err;
|
||||
do {
|
||||
ret = zmq_msg_recv(&msg, cb->zmqsock, ZMQ_NOBLOCK);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN)
|
||||
break;
|
||||
|
||||
zmq_msg_close(&msg);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
cb->cb_part(cb->arg, cb->zmqsock, &msg, partno);
|
||||
if (cb->cancelled) {
|
||||
zmq_msg_close(&msg);
|
||||
XFREE(MTYPE_ZEROMQ_CB, cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* cb_part may have read additional parts of the
|
||||
* message; don't use zmq_msg_more here */
|
||||
moresz = sizeof(more);
|
||||
more = 0;
|
||||
ret = zmq_getsockopt(cb->zmqsock, ZMQ_RCVMORE,
|
||||
&more, &moresz);
|
||||
if (ret < 0) {
|
||||
zmq_msg_close(&msg);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
partno++;
|
||||
} while (more);
|
||||
zmq_msg_close(&msg);
|
||||
}
|
||||
|
||||
funcname_thread_add_read_write(THREAD_READ, t->master, frrzmq_read_msg,
|
||||
cb, cb->fd, &cb->thread, t->funcname, t->schedfrom,
|
||||
t->schedfrom_line);
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
zlog_err("ZeroMQ error: %s(%d)", strerror (errno), errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct frrzmq_cb *funcname_frrzmq_thread_add_read(
|
||||
struct thread_master *master,
|
||||
void (*msgfunc)(void *arg, void *zmqsock),
|
||||
void (*partfunc)(void *arg, void *zmqsock,
|
||||
zmq_msg_t *msg, unsigned partnum),
|
||||
void *arg, void *zmqsock, debugargdef)
|
||||
{
|
||||
int fd, events;
|
||||
size_t len;
|
||||
struct frrzmq_cb *cb;
|
||||
|
||||
if (!(msgfunc || partfunc) || (msgfunc && partfunc))
|
||||
return NULL;
|
||||
len = sizeof(fd);
|
||||
if (zmq_getsockopt(zmqsock, ZMQ_FD, &fd, &len))
|
||||
return NULL;
|
||||
len = sizeof(events);
|
||||
if (zmq_getsockopt(zmqsock, ZMQ_EVENTS, &events, &len))
|
||||
return NULL;
|
||||
|
||||
cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
|
||||
if (!cb)
|
||||
return NULL;
|
||||
|
||||
cb->arg = arg;
|
||||
cb->zmqsock = zmqsock;
|
||||
cb->cb_msg = msgfunc;
|
||||
cb->cb_part = partfunc;
|
||||
cb->fd = fd;
|
||||
|
||||
if (events & ZMQ_POLLIN)
|
||||
funcname_thread_add_event(master,
|
||||
frrzmq_read_msg, cb, fd, &cb->thread,
|
||||
funcname, schedfrom, fromln);
|
||||
else
|
||||
funcname_thread_add_read_write(THREAD_READ, master,
|
||||
frrzmq_read_msg, cb, fd, &cb->thread,
|
||||
funcname, schedfrom, fromln);
|
||||
return cb;
|
||||
}
|
||||
|
||||
void frrzmq_thread_cancel(struct frrzmq_cb *cb)
|
||||
{
|
||||
if (!cb->thread) {
|
||||
/* canceling from within callback */
|
||||
cb->cancelled = 1;
|
||||
return;
|
||||
}
|
||||
thread_cancel(cb->thread);
|
||||
XFREE(MTYPE_ZEROMQ_CB, cb);
|
||||
}
|
88
lib/frr_zmq.h
Normal file
88
lib/frr_zmq.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* libzebra ZeroMQ bindings
|
||||
* Copyright (C) 2015 David Lamparter
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _FRRZMQ_H
|
||||
#define _FRRZMQ_H
|
||||
|
||||
#include "thread.h"
|
||||
#include <zmq.h>
|
||||
|
||||
/* linking/packaging note: this is a separate library that needs to be
|
||||
* linked into any daemon/library/module that wishes to use its
|
||||
* functionality. The purpose of this is to encapsulate the libzmq
|
||||
* dependency and not make libfrr/FRR itself depend on libzmq.
|
||||
*
|
||||
* libfrrzmq should be put in LDFLAGS/LIBADD *before* either libfrr or
|
||||
* libzmq, and both of these should always be listed, e.g.
|
||||
* foo_LDFLAGS = libfrrzmq.la libfrr.la $(ZEROMQ_LIBS)
|
||||
*/
|
||||
|
||||
/* libzmq's context
|
||||
*
|
||||
* this is mostly here as a convenience, it has IPv6 enabled but nothing
|
||||
* else is tied to it; you can use a separate context without problems
|
||||
*/
|
||||
extern void *frrzmq_context;
|
||||
|
||||
extern void frrzmq_init (void);
|
||||
extern void frrzmq_finish (void);
|
||||
|
||||
#define debugargdef const char *funcname, const char *schedfrom, int fromln
|
||||
|
||||
/* core event registration, one of these 2 macros should be used */
|
||||
#define frrzmq_thread_add_read_msg(m,f,a,z) funcname_frrzmq_thread_add_read( \
|
||||
m,f,NULL,a,z,#f,__FILE__,__LINE__)
|
||||
#define frrzmq_thread_add_read_part(m,f,a,z) funcname_frrzmq_thread_add_read( \
|
||||
m,NULL,f,a,z,#f,__FILE__,__LINE__)
|
||||
|
||||
struct frrzmq_cb;
|
||||
|
||||
/* Set up a POLLIN notification to be called from the libfrr main loop.
|
||||
* This has the following properties:
|
||||
*
|
||||
* - since ZeroMQ works with edge triggered notifications, it will loop and
|
||||
* dispatch as many events as ZeroMQ has pending at the time libfrr calls
|
||||
* into this code
|
||||
* - due to this looping (which means it non-single-issue), the callback is
|
||||
* also persistent. Do _NOT_ re-register the event inside of your
|
||||
* callback function.
|
||||
* - either msgfunc or partfunc will be called (only one can be specified)
|
||||
* - msgfunc is called once for each incoming message
|
||||
* - if partfunc is specified, the message is read and partfunc is called
|
||||
* for each ZeroMQ multi-part subpart. Note that you can't send replies
|
||||
* before all parts have been read because that violates the ZeroMQ FSM.
|
||||
* - you can safely cancel the callback from within itself
|
||||
* - installing a callback will check for pending events (ZMQ_EVENTS) and
|
||||
* may schedule the event to run as soon as libfrr is back in its main
|
||||
* loop.
|
||||
*
|
||||
* TODO #1: add ZMQ_POLLERR / error callback
|
||||
* TODO #2: add frrzmq_check_events() function to check for edge triggered
|
||||
* things that may have happened after a zmq_send() call or so
|
||||
*/
|
||||
extern struct frrzmq_cb *funcname_frrzmq_thread_add_read(
|
||||
struct thread_master *master,
|
||||
void (*msgfunc)(void *arg, void *zmqsock),
|
||||
void (*partfunc)(void *arg, void *zmqsock,
|
||||
zmq_msg_t *msg, unsigned partnum),
|
||||
void *arg, void *zmqsock, debugargdef);
|
||||
|
||||
extern void frrzmq_thread_cancel(struct frrzmq_cb *cb);
|
||||
|
||||
#endif /* _FRRZMQ_H */
|
@ -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);
|
||||
|
13
lib/hash.c
13
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;
|
||||
|
16
lib/hook.c
16
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)
|
||||
|
51
lib/hook.h
51
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 */
|
||||
|
35
lib/if.c
35
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)
|
||||
{
|
||||
|
17
lib/if.h
17
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 **);
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "openbsd-queue.h"
|
||||
#include "queue.h"
|
||||
#include "imsg.h"
|
||||
|
||||
int ibuf_realloc(struct ibuf *, size_t);
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "openbsd-queue.h"
|
||||
#include "queue.h"
|
||||
#include "imsg.h"
|
||||
|
||||
int imsg_fd_overhead = 0;
|
||||
|
56
lib/libfrr.c
56
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);
|
||||
}
|
||||
}
|
||||
|
10
lib/libfrr.h
10
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 */
|
||||
|
14
lib/log.c
14
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),
|
||||
|
10
lib/memory.c
10
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;
|
||||
}
|
||||
|
40
lib/memory.h
40
lib/memory.h
@ -18,7 +18,9 @@
|
||||
#define _QUAGGA_MEMORY_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <frratomic.h>
|
||||
#include "compiler.h"
|
||||
|
||||
#define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
|
||||
|
||||
@ -36,41 +38,6 @@ struct memgroup {
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#if defined(__clang__)
|
||||
#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5)
|
||||
# define _RET_NONNULL , returns_nonnull
|
||||
#endif
|
||||
# define _CONSTRUCTOR(x) constructor(x)
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
|
||||
# define _RET_NONNULL , returns_nonnull
|
||||
#endif
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
|
||||
# define _CONSTRUCTOR(x) constructor(x)
|
||||
# define _DESTRUCTOR(x) destructor(x)
|
||||
# define _ALLOC_SIZE(x) alloc_size(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __sun
|
||||
/* Solaris doesn't do constructor priorities due to linker restrictions */
|
||||
#undef _CONSTRUCTOR
|
||||
#undef _DESTRUCTOR
|
||||
#endif
|
||||
|
||||
#ifndef _RET_NONNULL
|
||||
# define _RET_NONNULL
|
||||
#endif
|
||||
#ifndef _CONSTRUCTOR
|
||||
# define _CONSTRUCTOR(x) constructor
|
||||
#endif
|
||||
#ifndef _DESTRUCTOR
|
||||
# define _DESTRUCTOR(x) destructor
|
||||
#endif
|
||||
#ifndef _ALLOC_SIZE
|
||||
# define _ALLOC_SIZE(x)
|
||||
#endif
|
||||
|
||||
/* macro usage:
|
||||
*
|
||||
* mydaemon.h
|
||||
@ -194,7 +161,8 @@ static inline size_t mtype_stats_alloc(struct memtype *mt)
|
||||
* last value from qmem_walk_fn. */
|
||||
typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt);
|
||||
extern int qmem_walk(qmem_walk_fn *func, void *arg);
|
||||
extern void log_memstats_stderr(const char *);
|
||||
extern int log_memstats(FILE *fp, const char *);
|
||||
#define log_memstats_stderr(prefix) log_memstats(stderr, prefix)
|
||||
|
||||
extern void memory_oom(size_t size, const char *name);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 *);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
35
lib/prefix.h
35
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)
|
||||
|
@ -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)) {
|
||||
|
701
lib/queue.h
701
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 */
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
20
lib/table.c
20
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;
|
||||
|
20
lib/table.h
20
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
|
||||
*
|
||||
|
@ -31,48 +31,60 @@ struct ttable_style ttable_styles[] = {
|
||||
.corner = '+',
|
||||
.rownums_on = false,
|
||||
.indent = 1,
|
||||
.border.top = '-',
|
||||
.border.bottom = '-',
|
||||
.border.left = '|',
|
||||
.border.right = '|',
|
||||
.border.top_on = true,
|
||||
.border.bottom_on = true,
|
||||
.border.left_on = true,
|
||||
.border.right_on = true,
|
||||
.cell.lpad = 1,
|
||||
.cell.rpad = 1,
|
||||
.cell.align = LEFT,
|
||||
.cell.border.bottom = '-',
|
||||
.cell.border.bottom_on = true,
|
||||
.cell.border.top = '-',
|
||||
.cell.border.top_on = false,
|
||||
.cell.border.right = '|',
|
||||
.cell.border.right_on = true,
|
||||
.cell.border.left = '|',
|
||||
.cell.border.left_on = false,
|
||||
.border = {
|
||||
.top = '-',
|
||||
.bottom = '-',
|
||||
.left = '|',
|
||||
.right = '|',
|
||||
.top_on = true,
|
||||
.bottom_on = true,
|
||||
.left_on = true,
|
||||
.right_on = true,
|
||||
},
|
||||
.cell = {
|
||||
.lpad = 1,
|
||||
.rpad = 1,
|
||||
.align = LEFT,
|
||||
.border = {
|
||||
.bottom = '-',
|
||||
.bottom_on = true,
|
||||
.top = '-',
|
||||
.top_on = false,
|
||||
.right = '|',
|
||||
.right_on = true,
|
||||
.left = '|',
|
||||
.left_on = false,
|
||||
},
|
||||
},
|
||||
}, { // blank, suitable for plaintext alignment
|
||||
.corner = ' ',
|
||||
.rownums_on = false,
|
||||
.indent = 1,
|
||||
.border.top = ' ',
|
||||
.border.bottom = ' ',
|
||||
.border.left = ' ',
|
||||
.border.right = ' ',
|
||||
.border.top_on = false,
|
||||
.border.bottom_on = false,
|
||||
.border.left_on = false,
|
||||
.border.right_on = false,
|
||||
.cell.lpad = 0,
|
||||
.cell.rpad = 3,
|
||||
.cell.align = LEFT,
|
||||
.cell.border.bottom = ' ',
|
||||
.cell.border.bottom_on = false,
|
||||
.cell.border.top = ' ',
|
||||
.cell.border.top_on = false,
|
||||
.cell.border.right = ' ',
|
||||
.cell.border.right_on = false,
|
||||
.cell.border.left = ' ',
|
||||
.cell.border.left_on = false,
|
||||
.border = {
|
||||
.top = ' ',
|
||||
.bottom = ' ',
|
||||
.left = ' ',
|
||||
.right = ' ',
|
||||
.top_on = false,
|
||||
.bottom_on = false,
|
||||
.left_on = false,
|
||||
.right_on = false,
|
||||
},
|
||||
.cell = {
|
||||
.lpad = 0,
|
||||
.rpad = 3,
|
||||
.align = LEFT,
|
||||
.border = {
|
||||
.bottom = ' ',
|
||||
.bottom_on = false,
|
||||
.top = ' ',
|
||||
.top_on = false,
|
||||
.right = ' ',
|
||||
.right_on = false,
|
||||
.left = ' ',
|
||||
.left_on = false,
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
/* clang-format on */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user