static int
lcommunity_regexp_include (regex_t * reg, struct lcommunity *lcom, int i)
{
- const char *str;
+ char *str;
/* When there is no communities attribute it is treated as empty string. */
if (lcom == NULL || lcom->size == 0)
- str = "";
+ str = XSTRDUP (MTYPE_LCOMMUNITY_STR, "");
else
str = lcommunity_str_get (lcom, i);
/* Regular expression match. */
if (regexec (reg, str, 0, NULL, 0) == 0)
- return 1;
+ {
+ XFREE (MTYPE_LCOMMUNITY_STR, str);
+ return 1;
+ }
+ XFREE (MTYPE_LCOMMUNITY_STR, str);
/* No match. */
return 0;
}
"Neighbor to display information about\n"
"Display routes learned from neighbor\n")
{
- int idx_peer = 5;
- union sockunion su;
+ int idx_peer = 0;
+ union sockunion *su;
struct peer *peer;
- if (sockunion_str2su (argv[idx_peer]->arg))
+ argv_find(argv, argc, "A.B.C.D", &idx_peer);
+ su = sockunion_str2su (argv[idx_peer]->arg);
+
+ if (!su)
{
vty_out (vty, "Malformed address: %s%s", argv[idx_peer]->arg, VTY_NEWLINE);
return CMD_WARNING;
}
- peer = peer_lookup (NULL, &su);
+ peer = peer_lookup (NULL, su);
if (! peer || ! peer->afc[AFI_IP][SAFI_ENCAP])
{
vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
return CMD_WARNING;
}
- return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_neighbor, &su, 0);
+ return bgp_show_encap (vty, AFI_IP, NULL, bgp_show_type_neighbor, su, 0);
}
DEFUN (show_bgp_ipv6_encap_neighbor_routes,
if (route_length - 4 - 10 - 8 -
3 /* label to be read */ >= 32) {
p_evpn_p->flags = IP_PREFIX_V6;
- memcpy(&(p_evpn_p->ip.v4_addr), pnt, 16);
+ memcpy(&(p_evpn_p->ip.v6_addr), pnt, 16);
pnt += 16;
memcpy(&evpn.gw_ip.ipv6, pnt, 16);
pnt += 16;
"Gateway IP ( A.B.C.D )\n"
"Gateway IPv6 ( X:X::X:X )\n"
"Router Mac Ext Comm\n"
- "Router Mac address Value ( aa:bb:cc:dd:ee:ff format)\n")
+ "Router Mac address Value ( aa:bb:cc:dd:ee:ff format)\n"
+ "Route-map to modify the attributes\n"
+ "Name of the route map\n")
{
int idx_ipv4_prefixlen = 1;
int idx_ext_community = 3;
int ret = community_list_unset (bgp_clist, cl_name_or_number, str, direct, style, delete_all);
+ XFREE (MTYPE_TMP, str);
+
if (ret < 0)
{
community_list_perror (vty, ret);
int ret = community_list_unset (bgp_clist, cl_name_or_number, str, direct, style, delete_all);
+ XFREE (MTYPE_TMP, str);
+
if (ret < 0)
{
community_list_perror (vty, ret);
list_delete (group->listen_range[afi]);
}
- XFREE(MTYPE_BGP_PEER_HOST, group->name);
+ XFREE(MTYPE_PEER_GROUP_HOST, group->name);
group->name = NULL;
group->conf->group = NULL;
if (gfilter->plist[direct].name)
{
if (filter->plist[direct].name)
- XSTRDUP(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
filter->plist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->plist[direct].name);
filter->plist[direct].plist = gfilter->plist[direct].plist;
peer_on_policy_change(peer, afi, safi,
api.nexthop = nhp_ary;
api.ifindex_num = 0;
api.instance = 0;
+ api.safi = SAFI_UNICAST;
if (BGP_DEBUG (zebra, ZEBRA))
{
api.ifindex_num = 1;
api.ifindex = &ifindex;
api.instance = 0;
+ api.safi = SAFI_UNICAST;
if (BGP_DEBUG (zebra, ZEBRA))
{
===========================
Check /etc/pam.d/frr, it probably denies access to your user. The passwords
-configured in /etc/frr/Frr.conf are only for telnet access.
+configured in /etc/frr/frr.conf are only for telnet access.
fi
# Exceptions for vtysh.
- f=$d/Frr.conf
+ f=$d/frr.conf
if [ -f $d/Zebra.conf ]; then
mv $d/Zebra.conf $f
fi
.B vtysh
config file.
.TP
-.BI @CFG_SYSCONF@/Frr.conf
+.BI @CFG_SYSCONF@/frr.conf
The default location of the integrated @PACKAGE_FULLNAME@ routing engine config file
if integrated config file is in use (not default).
.TP
@section Integrated configuration mode
Integrated configuration mode uses a single configuration file,
-@file{Frr.conf}, for all daemons. This replaces the individual files like
+@file{frr.conf}, for all daemons. This replaces the individual files like
@file{zebra.conf} or @file{bgpd.conf}.
-@file{Frr.conf} is located in @file{@value{INSTALL_PREFIX_ETC}}. All
+@file{frr.conf} is located in @file{@value{INSTALL_PREFIX_ETC}}. All
daemons check for the existence of this file at startup, and if it exists
will not load their individual configuration files. Instead,
-@command{vtysh -b} must be invoked to process @file{Frr.conf} and apply
+@command{vtysh -b} must be invoked to process @file{frr.conf} and apply
its settings to the individual daemons.
@quotation Warning
@subsection Configuration saving, file ownership and permissions
-The @file{Frr.conf} file is not written by any of the daemons; instead
+The @file{frr.conf} file is not written by any of the daemons; instead
@command{vtysh} contains the neccessary logic to collect configuration from
all of the daemons, combine it and write it out.
system, configuration writes will be tried through @command{watchfrr},
using the @command{write integrated} command internally. Since
@command{watchfrr} is running as superuser, @command{vtysh} is able to
-ensure correct ownership and permissions on @file{Frr.conf}.
+ensure correct ownership and permissions on @file{frr.conf}.
If @command{watchfrr} is not running or the configuration write fails,
@command{vtysh} will attempt to directly write to the file. This is likely
should be run as either the superuser or the Frr user.
We recommend you do not mix the use of the two types of files. Further, it
-is better not to use the integrated Frr.conf file, as any syntax error in
+is better not to use the integrated frr.conf file, as any syntax error in
it can lead to /all/ of your daemons being unable to start up. Per daemon
files are more robust as impact of errors in configuration are limited to
the daemon in whose file the error is made.
@deffn {Command} {service integrated-vtysh-config} {}
@deffnx {Command} {no service integrated-vtysh-config} {}
-Control whether integrated @file{Frr.conf} file is written when
+Control whether integrated @file{frr.conf} file is written when
'write file' is issued.
These commands need to be placed in @file{vtysh.conf} to have any effect.
@item
@command{service integrated-vtysh-config}
-@command{vtysh} will always write @file{Frr.conf}.
+@command{vtysh} will always write @file{frr.conf}.
@item
@command{no service integrated-vtysh-config}
-@command{vtysh} will never write @file{Frr.conf}; instead it will ask
+@command{vtysh} will never write @file{frr.conf}; instead it will ask
daemons to write their individual configuration files.
@item
Neither option present (default)
-@command{vtysh} will check whether @file{Frr.conf} exists. If it does,
+@command{vtysh} will check whether @file{frr.conf} exists. If it does,
configuration writes will update that file. Otherwise, writes are performed
through the individual daemons.
@end itemize
@deffn {Command} {write integrated} {}
Unconditionally (regardless of @command{service integrated-vtysh-config}
-setting) write out integrated @file{Frr.conf} file through
+setting) write out integrated @file{frr.conf} file through
@command{watchfrr}. If @command{watchfrr} is not running, this command
is unavailable.
Configuration changes made while some daemon is not running will be invisible
to that daemon. The daemon will start up with its saved configuration
-(either in its individual configuration file, or in @file{Frr.conf}).
+(either in its individual configuration file, or in @file{frr.conf}).
This is particularly troublesome for route-maps and prefix lists, which would
otherwise be synchronized between daemons.
}
isis_spf_schedule (lsp->area, lsp->level);
- isis_spf_schedule6 (lsp->area, lsp->level);
if (lsp->pdu)
stream_free (lsp->pdu);
ntohs (lsp->lsp_header->pdu_len) - 12, 12);
isis_spf_schedule (lsp->area, lsp->level);
- isis_spf_schedule6 (lsp->area, lsp->level);
return;
}
if (lsp->lsp_header->seq_num != 0)
{
isis_spf_schedule (lsp->area, lsp->level);
- isis_spf_schedule6 (lsp->area, lsp->level);
}
}
{
zlog_warn ("ISIS-Rte (%s) %s called for unknown family %d",
area->area_tag, __func__, family);
+ route_table_finish(merge);
return;
}
#include "hash.h"
#include "if.h"
#include "table.h"
+#include "spf_backoff.h"
#include "isis_constants.h"
#include "isis_common.h"
#include "isis_route.h"
#include "isis_csm.h"
-int isis_run_spf_l1 (struct thread *thread);
-int isis_run_spf_l2 (struct thread *thread);
-
/* 7.2.7 */
static void
remove_excess_adjs (struct list *adjs)
tree->last_run_timestamp = 0;
tree->last_run_duration = 0;
tree->runcount = 0;
- tree->pending = 0;
return tree;
}
void
isis_spftree_del (struct isis_spftree *spftree)
{
- THREAD_TIMER_OFF (spftree->t_spf);
spftree->tents->del = (void (*)(void *)) isis_vertex_del;
list_delete (spftree->tents);
out:
isis_route_validate (area);
- spftree->pending = 0;
spftree->runcount++;
spftree->last_run_timestamp = time (NULL);
monotime(&time_now);
end_time = (end_time * 1000000) + time_now.tv_usec;
spftree->last_run_duration = end_time - start_time;
-
return retval;
}
-int
+static int
isis_run_spf_l1 (struct thread *thread)
{
struct isis_area *area;
area = THREAD_ARG (thread);
assert (area);
- area->spftree[0]->t_spf = NULL;
- area->spftree[0]->pending = 0;
+ area->spf_timer[0] = NULL;
if (!(area->is_type & IS_LEVEL_1))
{
if (area->ip_circuits)
retval = isis_run_spf (area, 1, AF_INET, isis->sysid);
+ if (area->ipv6_circuits)
+ retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
return retval;
}
-int
+static int
isis_run_spf_l2 (struct thread *thread)
{
struct isis_area *area;
area = THREAD_ARG (thread);
assert (area);
- area->spftree[1]->t_spf = NULL;
- area->spftree[1]->pending = 0;
+ area->spf_timer[1] = NULL;
if (!(area->is_type & IS_LEVEL_2))
{
if (area->ip_circuits)
retval = isis_run_spf (area, 2, AF_INET, isis->sysid);
+ if (area->ipv6_circuits)
+ retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
return retval;
}
zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago",
area->area_tag, level, diff);
- if (spftree->pending)
- return ISIS_OK;
-
- THREAD_TIMER_OFF (spftree->t_spf);
-
- /* wait configured min_spf_interval before doing the SPF */
- if (diff >= area->min_spf_interval[level-1])
- return isis_run_spf (area, level, AF_INET, isis->sysid);
-
- if (level == 1)
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area,
- area->min_spf_interval[0] - diff);
- else
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area,
- area->min_spf_interval[1] - diff);
-
- if (isis->debugs & DEBUG_SPF_EVENTS)
- zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
- area->area_tag, level, area->min_spf_interval[level-1] - diff);
-
- spftree->pending = 1;
-
- return ISIS_OK;
-}
-
-static int
-isis_run_spf6_l1 (struct thread *thread)
-{
- struct isis_area *area;
- int retval = ISIS_OK;
-
- area = THREAD_ARG (thread);
- assert (area);
-
- area->spftree6[0]->t_spf = NULL;
- area->spftree6[0]->pending = 0;
-
- if (!(area->is_type & IS_LEVEL_1))
+ if (area->spf_delay_ietf[level - 1])
{
- if (isis->debugs & DEBUG_SPF_EVENTS)
- zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
- return ISIS_WARNING;
- }
-
- if (isis->debugs & DEBUG_SPF_EVENTS)
- zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag);
-
- if (area->ipv6_circuits)
- retval = isis_run_spf (area, 1, AF_INET6, isis->sysid);
+ /* Need to call schedule function also if spf delay is running to
+ * restart holdoff timer - compare draft-ietf-rtgwg-backoff-algo-04 */
+ long delay = spf_backoff_schedule(area->spf_delay_ietf[level -1]);
+ if (area->spf_timer[level - 1])
+ return ISIS_OK;
- return retval;
-}
-
-static int
-isis_run_spf6_l2 (struct thread *thread)
-{
- struct isis_area *area;
- int retval = ISIS_OK;
-
- area = THREAD_ARG (thread);
- assert (area);
-
- area->spftree6[1]->t_spf = NULL;
- area->spftree6[1]->pending = 0;
-
- if (!(area->is_type & IS_LEVEL_2))
- {
- if (isis->debugs & DEBUG_SPF_EVENTS)
- zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag);
- return ISIS_WARNING;
+ if (level == 1)
+ {
+ THREAD_TIMER_MSEC_ON(master, area->spf_timer[0],
+ isis_run_spf_l1, area, delay);
+ }
+ else
+ {
+ THREAD_TIMER_MSEC_ON(master, area->spf_timer[1],
+ isis_run_spf_l2, area, delay);
+ }
+ return ISIS_OK;
}
- if (isis->debugs & DEBUG_SPF_EVENTS)
- zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag);
-
- if (area->ipv6_circuits)
- retval = isis_run_spf (area, 2, AF_INET6, isis->sysid);
-
- return retval;
-}
-
-int
-isis_spf_schedule6 (struct isis_area *area, int level)
-{
- int retval = ISIS_OK;
- struct isis_spftree *spftree = area->spftree6[level - 1];
- time_t now = time (NULL);
- time_t diff = now - spftree->last_run_timestamp;
-
- assert (diff >= 0);
- assert (area->is_type & level);
-
- if (isis->debugs & DEBUG_SPF_EVENTS)
- zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %lld sec ago",
- area->area_tag, level, (long long)diff);
-
- if (spftree->pending)
+ if (area->spf_timer[level -1])
return ISIS_OK;
- THREAD_TIMER_OFF (spftree->t_spf);
-
/* wait configured min_spf_interval before doing the SPF */
if (diff >= area->min_spf_interval[level-1])
- return isis_run_spf (area, level, AF_INET6, isis->sysid);
+ {
+ int retval = ISIS_OK;
+
+ if (area->ip_circuits)
+ retval = isis_run_spf (area, level, AF_INET, isis->sysid);
+ if (area->ipv6_circuits)
+ retval = isis_run_spf (area, level, AF_INET6, isis->sysid);
+
+ return retval;
+ }
if (level == 1)
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area,
+ THREAD_TIMER_ON (master, area->spf_timer[0], isis_run_spf_l1, area,
area->min_spf_interval[0] - diff);
else
- THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area,
+ THREAD_TIMER_ON (master, area->spf_timer[1], isis_run_spf_l2, area,
area->min_spf_interval[1] - diff);
if (isis->debugs & DEBUG_SPF_EVENTS)
- zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %lld sec from now",
- area->area_tag, level,
- (long long)(area->min_spf_interval[level-1] - diff));
-
- spftree->pending = 1;
+ zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now",
+ area->area_tag, level, area->min_spf_interval[level-1] - diff);
- return retval;
+ return ISIS_OK;
}
static void
struct isis_spftree
{
- struct thread *t_spf; /* spf threads */
struct list *paths; /* the SPT */
struct list *tents; /* TENT */
struct isis_area *area; /* back pointer to area */
- int pending; /* already scheduled */
unsigned int runcount; /* number of runs since uptime */
time_t last_run_timestamp; /* last run timestamp for scheduling */
time_t last_run_duration; /* last run duration in msec */
struct isis_adjacency *adj);
int isis_spf_schedule (struct isis_area *area, int level);
void isis_spf_cmds_init (void);
-int isis_spf_schedule6 (struct isis_area *area, int level);
#endif /* _ZEBRA_ISIS_SPF_H */
*/
#include <zebra.h>
-#include <command.h>
+
+#include "command.h"
+#include "spf_backoff.h"
#include "isis_circuit.h"
#include "isis_csm.h"
return CMD_SUCCESS;
}
+DEFUN (no_spf_delay_ietf,
+ no_spf_delay_ietf_cmd,
+ "no spf-delay-ietf",
+ NO_STR
+ "IETF SPF delay algorithm\n")
+{
+ VTY_DECLVAR_CONTEXT (isis_area, area);
+
+ spf_backoff_free(area->spf_delay_ietf[0]);
+ spf_backoff_free(area->spf_delay_ietf[1]);
+ area->spf_delay_ietf[0] = NULL;
+ area->spf_delay_ietf[1] = NULL;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (spf_delay_ietf,
+ spf_delay_ietf_cmd,
+ "spf-delay-ietf init-delay (0-60000) short-delay (0-60000) long-delay (0-60000) holddown (0-60000) time-to-learn (0-60000)",
+ "IETF SPF delay algorithm\n"
+ "Delay used while in QUIET state\n"
+ "Delay used while in QUIET state in milliseconds\n"
+ "Delay used while in SHORT_WAIT state\n"
+ "Delay used while in SHORT_WAIT state in milliseconds\n"
+ "Delay used while in LONG_WAIT\n"
+ "Delay used while in LONG_WAIT state in milliseconds\n"
+ "Time with no received IGP events before considering IGP stable\n"
+ "Time with no received IGP events before considering IGP stable (in milliseconds)\n"
+ "Maximum duration needed to learn all the events related to a single failure\n"
+ "Maximum duration needed to learn all the events related to a single failure (in milliseconds)\n")
+{
+ VTY_DECLVAR_CONTEXT (isis_area, area);
+
+ long init_delay = atol(argv[2]->arg);
+ long short_delay = atol(argv[4]->arg);
+ long long_delay = atol(argv[6]->arg);
+ long holddown = atol(argv[8]->arg);
+ long timetolearn = atol(argv[10]->arg);
+
+ size_t bufsiz = strlen(area->area_tag) + sizeof("IS-IS Lx");
+ char *buf = XCALLOC(MTYPE_TMP, bufsiz);
+
+ snprintf(buf, bufsiz, "IS-IS %s L1", area->area_tag);
+ spf_backoff_free(area->spf_delay_ietf[0]);
+ area->spf_delay_ietf[0] = spf_backoff_new(master, buf, init_delay,
+ short_delay, long_delay,
+ holddown, timetolearn);
+
+ snprintf(buf, bufsiz, "IS-IS %s L2", area->area_tag);
+ spf_backoff_free(area->spf_delay_ietf[1]);
+ area->spf_delay_ietf[1] = spf_backoff_new(master, buf, init_delay,
+ short_delay, long_delay,
+ holddown, timetolearn);
+
+ XFREE(MTYPE_TMP, buf);
+ return CMD_SUCCESS;
+}
static int
area_max_lsp_lifetime_set(struct vty *vty, int level,
install_element (ISIS_NODE, &domain_passwd_md5_cmd);
install_element (ISIS_NODE, &domain_passwd_clear_cmd);
install_element (ISIS_NODE, &no_area_passwd_cmd);
+
+ install_element (ISIS_NODE, &spf_delay_ietf_cmd);
+ install_element (ISIS_NODE, &no_spf_delay_ietf_cmd);
+
}
#include "prefix.h"
#include "table.h"
#include "qobj.h"
+#include "spf_backoff.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
spftree_area_del (area);
+ THREAD_TIMER_OFF(area->spf_timer[0]);
+ THREAD_TIMER_OFF(area->spf_timer[1]);
+
+ spf_backoff_free(area->spf_delay_ietf[0]);
+ spf_backoff_free(area->spf_delay_ietf[1]);
+
/* invalidate and validate would delete all routes from zebra */
isis_route_invalidate (area);
isis_route_validate (area);
vty_out (vty, "debug isis lsp-sched%s", VTY_NEWLINE);
write++;
}
+ write += spf_backoff_write_config(vty);
return write;
}
vty_out (vty, " ago");
}
+DEFUN (show_isis_spf_ietf,
+ show_isis_spf_ietf_cmd,
+ "show isis spf-delay-ietf",
+ SHOW_STR
+ "IS-IS information\n"
+ "IS-IS SPF delay IETF information\n")
+{
+ if (!isis)
+ {
+ vty_out (vty, "ISIS is not running%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
+
+ struct listnode *node;
+ struct isis_area *area;
+
+ for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
+ {
+ vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null",
+ VTY_NEWLINE);
+
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
+ {
+ if ((area->is_type & level) == 0)
+ continue;
+
+ vty_out (vty, " Level-%d:%s", level, VTY_NEWLINE);
+ vty_out (vty, " SPF delay status: ");
+ 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%s",
+ remain.tv_sec * 1000 + remain.tv_usec / 1000,
+ VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out(vty, "Not scheduled%s", VTY_NEWLINE);
+ }
+
+ if (area->spf_delay_ietf[level - 1]) {
+ vty_out(vty, " Using draft-ietf-rtgwg-backoff-algo-04%s", VTY_NEWLINE);
+ spf_backoff_show(area->spf_delay_ietf[level - 1], vty, " ");
+ } else {
+ vty_out(vty, " Using legacy backoff algo%s", VTY_NEWLINE);
+ }
+ }
+ }
+ return CMD_SUCCESS;
+}
+
DEFUN (show_isis_summary,
show_isis_summary_cmd,
"show isis summary",
vty_out (vty, " Level-%d:%s", level, VTY_NEWLINE);
spftree = area->spftree[level - 1];
- if (spftree->pending)
- vty_out (vty, " IPv4 SPF: (pending)%s", VTY_NEWLINE);
+ if (area->spf_timer[level - 1])
+ vty_out (vty, " SPF: (pending)%s", VTY_NEWLINE);
else
- vty_out (vty, " IPv4 SPF:%s", VTY_NEWLINE);
+ vty_out (vty, " SPF:%s", VTY_NEWLINE);
- vty_out (vty, " minimum interval : %d%s",
- area->min_spf_interval[level - 1], VTY_NEWLINE);
+ vty_out (vty, " minimum interval : %d",
+ area->min_spf_interval[level - 1]);
+ if (area->spf_delay_ietf[level - 1])
+ vty_out (vty, " (not used, IETF SPF delay activated)");
+ vty_out (vty, VTY_NEWLINE);
+ vty_out (vty, " IPv4 route computation:%s", VTY_NEWLINE);
vty_out (vty, " last run elapsed : ");
vty_out_timestr(vty, spftree->last_run_timestamp);
vty_out (vty, "%s", VTY_NEWLINE);
spftree->runcount, VTY_NEWLINE);
spftree = area->spftree6[level - 1];
- if (spftree->pending)
- vty_out (vty, " IPv6 SPF: (pending)%s", VTY_NEWLINE);
- else
- vty_out (vty, " IPv6 SPF:%s", VTY_NEWLINE);
-
- vty_out (vty, " minimum interval : %d%s",
- area->min_spf_interval[level - 1], VTY_NEWLINE);
+ vty_out (vty, " IPv6 route computation:%s", VTY_NEWLINE);
vty_out (vty, " last run elapsed : ");
vty_out_timestr(vty, spftree->last_run_timestamp);
isis_spftree_del (area->spftree6[level - 1]);
area->spftree6[level - 1] = NULL;
}
+ THREAD_TIMER_OFF(area->spf_timer[level - 1]);
if (area->route_table[level - 1])
{
route_table_finish (area->route_table[level - 1]);
write++;
}
}
+
+ /* IETF SPF interval */
+ if (area->spf_delay_ietf[0])
+ {
+ vty_out (vty, " spf-delay-ietf init-delay %ld short-delay %ld long-delay %ld holddown %ld time-to-learn %ld%s",
+ spf_backoff_init_delay(area->spf_delay_ietf[0]),
+ spf_backoff_short_delay(area->spf_delay_ietf[0]),
+ spf_backoff_long_delay(area->spf_delay_ietf[0]),
+ spf_backoff_holddown(area->spf_delay_ietf[0]),
+ spf_backoff_timetolearn(area->spf_delay_ietf[0]),
+ VTY_NEWLINE);
+ write++;
+ }
+
/* Authentication passwords. */
if (area->area_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
{
install_element (VIEW_NODE, &show_isis_summary_cmd);
+ install_element (VIEW_NODE, &show_isis_spf_ietf_cmd);
+
install_element (VIEW_NODE, &show_isis_interface_cmd);
install_element (VIEW_NODE, &show_isis_interface_detail_cmd);
install_element (VIEW_NODE, &show_isis_interface_arg_cmd);
install_element (ISIS_NODE, &log_adj_changes_cmd);
install_element (ISIS_NODE, &no_log_adj_changes_cmd);
+
+ spf_backoff_cmd_init();
}
[ZEBRA_ROUTE_MAX + 1][ISIS_LEVELS];
struct route_table *ext_reach[REDIST_PROTOCOL_COUNT][ISIS_LEVELS];
+ struct spf_backoff *spf_delay_ietf[ISIS_LEVELS]; /*Structure with IETF SPF algo parameters*/
+ struct thread *spf_timer[ISIS_LEVELS];
+
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(isis_area)
event_counter.c \
grammar_sandbox.c \
srcdest_table.c \
+ spf_backoff.c \
strlcpy.c \
strlcat.c
skiplist.h qobj.h wheel.h \
event_counter.h \
monotime.h \
+ spf_backoff.h \
srcdest_table.h
noinst_HEADERS = \
#ifndef TIMESPEC_TO_TIMEVAL
/* should be in sys/time.h on BSD & Linux libcs */
-#define TIMESPEC_TO_TIMEVAL(tv, ts) do { \
- (tv)->tv_sec = (ts)->tv_sec; \
- (tv)->tv_usec = (ts)->tv_nsec / 1000; \
- } while (0)
+#define TIMESPEC_TO_TIMEVAL(tv, ts) do { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+ } while (0)
#endif
#ifndef TIMEVAL_TO_TIMESPEC
/* should be in sys/time.h on BSD & Linux libcs */
-#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
- (ts)->tv_sec = (tv)->tv_sec; \
- (ts)->tv_nsec = (tv)->tv_usec * 1000; \
- } while (0)
+#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+ } while (0)
#endif
static inline time_t monotime(struct timeval *tvo)
{
- struct timespec ts;
+ struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- if (tvo) {
- TIMESPEC_TO_TIMEVAL(tvo, &ts);
- }
- return ts.tv_sec;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (tvo) {
+ TIMESPEC_TO_TIMEVAL(tvo, &ts);
+ }
+ return ts.tv_sec;
}
/* the following two return microseconds, not time_t!
* code more readable
*/
static inline int64_t monotime_since(const struct timeval *ref,
- struct timeval *out)
+ struct timeval *out)
{
- struct timeval tv;
- monotime(&tv);
- timersub(&tv, ref, &tv);
- if (out)
- *out = tv;
- return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
+ struct timeval tv;
+ monotime(&tv);
+ timersub(&tv, ref, &tv);
+ if (out)
+ *out = tv;
+ return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
}
static inline int64_t monotime_until(const struct timeval *ref,
- struct timeval *out)
+ struct timeval *out)
{
- struct timeval tv;
- monotime(&tv);
- timersub(ref, &tv, &tv);
- if (out)
- *out = tv;
- return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
+ struct timeval tv;
+ monotime(&tv);
+ timersub(ref, &tv, &tv);
+ if (out)
+ *out = tv;
+ return (int64_t)tv.tv_sec * 1000000LL + tv.tv_usec;
}
#endif /* _FRR_MONOTIME_H */
--- /dev/null
+/*
+ * This is an implementation of the IETF SPF delay algorithm
+ * as explained in draft-ietf-rtgwg-backoff-algo-04
+ *
+ * Created: 25-01-2017 by S. Litkowski
+ *
+ * Copyright (C) 2017 Orange Labs http://www.orange.com/
+ * Copyright (C) 2017 by Christian Franke, Open Source Routing / NetDEF Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "spf_backoff.h"
+
+#include "command.h"
+#include "memory.h"
+#include "thread.h"
+#include "vty.h"
+
+DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF, "SPF backoff")
+DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF_NAME, "SPF backoff name")
+
+static bool debug_spf_backoff = false;
+#define backoff_debug(...) \
+ do \
+ { \
+ if (debug_spf_backoff) \
+ zlog_debug(__VA_ARGS__); \
+ } \
+ while (0)
+
+enum spf_backoff_state {
+ SPF_BACKOFF_QUIET,
+ SPF_BACKOFF_SHORT_WAIT,
+ SPF_BACKOFF_LONG_WAIT
+};
+
+struct spf_backoff {
+ struct thread_master *m;
+
+ /* Timers as per draft */
+ long init_delay;
+ long short_delay;
+ long long_delay;
+ long holddown;
+ long timetolearn;
+
+ /* State machine */
+ enum spf_backoff_state state;
+ struct thread *t_holddown;
+ struct thread *t_timetolearn;
+
+ /* For debugging */
+ char *name;
+ struct timeval first_event_time;
+ struct timeval last_event_time;
+};
+
+static const char *
+spf_backoff_state2str(enum spf_backoff_state state)
+{
+ switch (state)
+ {
+ case SPF_BACKOFF_QUIET:
+ return "QUIET";
+ case SPF_BACKOFF_SHORT_WAIT:
+ return "SHORT_WAIT";
+ case SPF_BACKOFF_LONG_WAIT:
+ return "LONG_WAIT";
+ }
+ return "???";
+}
+
+struct spf_backoff *
+spf_backoff_new(struct thread_master *m,
+ const char *name,
+ long init_delay,
+ long short_delay,
+ long long_delay,
+ long holddown,
+ long timetolearn)
+{
+ struct spf_backoff *rv;
+
+ rv = XCALLOC(MTYPE_SPF_BACKOFF, sizeof(*rv));
+ rv->m = m;
+
+ rv->init_delay = init_delay;
+ rv->short_delay = short_delay;
+ rv->long_delay = long_delay;
+ rv->holddown = holddown;
+ rv->timetolearn = timetolearn;
+
+ rv->state = SPF_BACKOFF_QUIET;
+
+ rv->name = XSTRDUP(MTYPE_SPF_BACKOFF_NAME, name);
+ return rv;
+}
+
+void
+spf_backoff_free(struct spf_backoff *backoff)
+{
+ if (!backoff)
+ return;
+
+ THREAD_TIMER_OFF(backoff->t_holddown);
+ THREAD_TIMER_OFF(backoff->t_timetolearn);
+ XFREE(MTYPE_SPF_BACKOFF_NAME, backoff->name);
+
+ XFREE(MTYPE_SPF_BACKOFF, backoff);
+}
+
+static int
+spf_backoff_timetolearn_elapsed(struct thread *thread)
+{
+ struct spf_backoff *backoff = THREAD_ARG(thread);
+
+ backoff->t_timetolearn = NULL;
+ backoff->state = SPF_BACKOFF_LONG_WAIT;
+ backoff_debug("SPF Back-off(%s) TIMETOLEARN elapsed, move to state %s",
+ backoff->name, spf_backoff_state2str(backoff->state));
+ return 0;
+}
+
+static int
+spf_backoff_holddown_elapsed(struct thread *thread)
+{
+ struct spf_backoff *backoff = THREAD_ARG(thread);
+
+ backoff->t_holddown = NULL;
+ THREAD_TIMER_OFF(backoff->t_timetolearn);
+ timerclear(&backoff->first_event_time);
+ backoff->state = SPF_BACKOFF_QUIET;
+ backoff_debug("SPF Back-off(%s) HOLDDOWN elapsed, move to state %s",
+ backoff->name, spf_backoff_state2str(backoff->state));
+ return 0;
+}
+
+long spf_backoff_schedule(struct spf_backoff *backoff)
+{
+ long rv;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ backoff_debug("SPF Back-off(%s) schedule called in state %s",
+ backoff->name, spf_backoff_state2str(backoff->state));
+
+ backoff->last_event_time = now;
+
+ switch (backoff->state)
+ {
+ case SPF_BACKOFF_QUIET:
+ backoff->state = SPF_BACKOFF_SHORT_WAIT;
+ THREAD_TIMER_MSEC_ON(backoff->m, backoff->t_timetolearn,
+ spf_backoff_timetolearn_elapsed, backoff,
+ backoff->timetolearn);
+ THREAD_TIMER_MSEC_ON(backoff->m, backoff->t_holddown,
+ spf_backoff_holddown_elapsed, backoff,
+ backoff->holddown);
+ backoff->first_event_time = now;
+ rv = backoff->init_delay;
+ break;
+ case SPF_BACKOFF_SHORT_WAIT:
+ case SPF_BACKOFF_LONG_WAIT:
+ THREAD_TIMER_OFF(backoff->t_holddown);
+ THREAD_TIMER_MSEC_ON(backoff->m, backoff->t_holddown,
+ spf_backoff_holddown_elapsed, backoff,
+ backoff->holddown);
+ if (backoff->state == SPF_BACKOFF_SHORT_WAIT)
+ rv = backoff->short_delay;
+ else
+ rv = backoff->long_delay;
+ break;
+ default:
+ zlog_warn("SPF Back-off(%s) in unknown state", backoff->name);
+ rv = backoff->init_delay;
+ }
+
+ backoff_debug("SPF Back-off(%s) changed state to %s and returned %ld delay",
+ backoff->name, spf_backoff_state2str(backoff->state), rv);
+ return rv;
+}
+
+static const char *
+timeval_format(struct timeval *tv)
+{
+ struct tm tm_store;
+ struct tm *tm;
+ static char timebuf[256];
+
+ if (!tv->tv_sec && !tv->tv_usec)
+ return "(never)";
+
+ tm = localtime_r(&tv->tv_sec, &tm_store);
+ if (!tm || strftime(timebuf, sizeof(timebuf),
+ "%Z %a %Y-%m-%d %H:%M:%S", tm) == 0)
+ {
+ return "???";
+ }
+
+ size_t offset = strlen(timebuf);
+ snprintf(timebuf + offset, sizeof(timebuf) - offset, ".%ld", tv->tv_usec);
+
+ return timebuf;
+}
+
+void
+spf_backoff_show(struct spf_backoff *backoff, struct vty *vty,
+ const char *prefix)
+{
+ vty_out(vty, "%sCurrent state: %s%s", prefix,
+ spf_backoff_state2str(backoff->state), VTY_NEWLINE);
+ vty_out(vty, "%sInit timer: %ld msec%s", prefix,
+ backoff->init_delay, VTY_NEWLINE);
+ vty_out(vty, "%sShort timer: %ld msec%s", prefix,
+ backoff->short_delay, VTY_NEWLINE);
+ vty_out(vty, "%sLong timer: %ld msec%s", prefix,
+ backoff->long_delay, VTY_NEWLINE);
+ vty_out(vty, "%sHolddown timer: %ld msec%s", prefix,
+ backoff->holddown, VTY_NEWLINE);
+ if (backoff->t_holddown)
+ {
+ struct timeval remain = thread_timer_remain(backoff->t_holddown);
+ vty_out(vty, "%s Still runs for %ld msec%s",
+ prefix, remain.tv_sec * 1000 + remain.tv_usec/1000, VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out(vty, "%s Inactive%s", prefix, VTY_NEWLINE);
+ }
+
+ vty_out(vty, "%sTimeToLearn timer: %ld msec%s", prefix,
+ backoff->timetolearn, VTY_NEWLINE);
+ if (backoff->t_timetolearn)
+ {
+ struct timeval remain = thread_timer_remain(backoff->t_timetolearn);
+ vty_out(vty, "%s Still runs for %ld msec%s",
+ prefix, remain.tv_sec * 1000 + remain.tv_usec/1000, VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out(vty, "%s Inactive%s", prefix, VTY_NEWLINE);
+ }
+
+ vty_out(vty, "%sFirst event: %s%s", prefix,
+ timeval_format(&backoff->first_event_time), VTY_NEWLINE);
+ vty_out(vty, "%sLast event: %s%s", prefix,
+ timeval_format(&backoff->last_event_time), VTY_NEWLINE);
+}
+
+DEFUN(spf_backoff_debug,
+ spf_backoff_debug_cmd,
+ "debug spf-delay-ietf",
+ DEBUG_STR
+ "SPF Back-off Debugging\n")
+{
+ debug_spf_backoff = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_spf_backoff_debug,
+ no_spf_backoff_debug_cmd,
+ "no debug spf-delay-ietf",
+ NO_STR
+ DEBUG_STR
+ "SPF Back-off Debugging\n")
+{
+ debug_spf_backoff = false;
+ return CMD_SUCCESS;
+}
+
+int
+spf_backoff_write_config(struct vty *vty)
+{
+ int written = 0;
+
+ if (debug_spf_backoff)
+ {
+ vty_out(vty, "debug spf-delay-ietf%s", VTY_NEWLINE);
+ written++;
+ }
+
+ return written;
+}
+
+void
+spf_backoff_cmd_init(void)
+{
+ install_element(ENABLE_NODE, &spf_backoff_debug_cmd);
+ install_element(CONFIG_NODE, &spf_backoff_debug_cmd);
+ install_element(ENABLE_NODE, &no_spf_backoff_debug_cmd);
+ install_element(CONFIG_NODE, &no_spf_backoff_debug_cmd);
+}
+
+long
+spf_backoff_init_delay(struct spf_backoff *backoff)
+{
+ return backoff->init_delay;
+}
+
+long
+spf_backoff_short_delay(struct spf_backoff *backoff)
+{
+ return backoff->short_delay;
+}
+
+long
+spf_backoff_long_delay(struct spf_backoff *backoff)
+{
+ return backoff->long_delay;
+}
+
+long
+spf_backoff_holddown(struct spf_backoff *backoff)
+{
+ return backoff->holddown;
+}
+
+long
+spf_backoff_timetolearn(struct spf_backoff *backoff)
+{
+ return backoff->timetolearn;
+}
--- /dev/null
+/*
+ * This is an implementation of the IETF SPF delay algorithm
+ * as explained in draft-ietf-rtgwg-backoff-algo-04
+ *
+ * Created: 25-01-2017 by S. Litkowski
+ *
+ * Copyright (C) 2017 Orange Labs http://www.orange.com/
+ * Copyright (C) 2017 by Christian Franke, Open Source Routing / NetDEF Inc.
+ *
+ * This file is part of FreeRangeRouting (FRR)
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef _ZEBRA_SPF_BACKOFF_H
+#define _ZEBRA_SPF_BACKOFF_H
+
+struct spf_backoff;
+struct thread_master;
+struct vty;
+
+struct spf_backoff *spf_backoff_new(struct thread_master *m,
+ const char *name,
+ long init_delay,
+ long short_delay,
+ long long_delay,
+ long holddown,
+ long timetolearn);
+
+void spf_backoff_free(struct spf_backoff *backoff);
+
+/* Called whenever an IGP event is received, returns how many
+ * milliseconds routing table computation should be delayed */
+long spf_backoff_schedule(struct spf_backoff *backoff);
+
+/* Shows status of SPF backoff instance */
+void spf_backoff_show(struct spf_backoff *backoff,
+ struct vty *vty,
+ const char *prefix);
+
+/* Writes out global SPF backoff debug config */
+int spf_backoff_write_config(struct vty *vty);
+
+/* Registers global SPF backoff debug commands */
+void spf_backoff_cmd_init(void);
+
+/* Accessor functions for SPF backoff parameters */
+long spf_backoff_init_delay(struct spf_backoff *backoff);
+long spf_backoff_short_delay(struct spf_backoff *backoff);
+long spf_backoff_long_delay(struct spf_backoff *backoff);
+long spf_backoff_holddown(struct spf_backoff *backoff);
+long spf_backoff_timetolearn(struct spf_backoff *backoff);
+
+#endif
};
/* Integrated configuration file. */
-#define INTEGRATE_DEFAULT_CONFIG "Frr.conf"
+#define INTEGRATE_DEFAULT_CONFIG "frr.conf"
/* Small macro to determine newline is newline only or linefeed needed. */
#define VTY_NEWLINE ((vty->type == VTY_TERM) ? "\r\n" : "\n")
struct stream *s;
struct zapi_ipv6 api;
unsigned long ifindex;
- struct prefix_ipv6 p, src_p;
+ struct prefix p, src_p;
struct in6_addr *nexthop;
if (ospf6 == NULL)
api.message = stream_getc (s);
/* IPv6 prefix. */
- memset (&p, 0, sizeof (struct prefix_ipv6));
+ memset (&p, 0, sizeof (struct prefix));
p.family = AF_INET6;
p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s));
- stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+ stream_get (&p.u.prefix6, s, PSIZE (p.prefixlen));
- memset (&src_p, 0, sizeof (struct prefix_ipv6));
+ memset (&src_p, 0, sizeof (struct prefix));
src_p.family = AF_INET6;
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_SRCPFX))
{
src_p.prefixlen = stream_getc (s);
- stream_get (&src_p.prefix, s, PSIZE (src_p.prefixlen));
+ stream_get (&src_p.u.prefix6, s, PSIZE (src_p.prefixlen));
}
if (src_p.prefixlen)
}
if (command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
- ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p,
+ ospf6_asbr_redistribute_add (api.type, ifindex, &p,
api.nexthop_num, nexthop, api.tag);
else
- ospf6_asbr_redistribute_remove (api.type, ifindex, (struct prefix *) &p);
+ ospf6_asbr_redistribute_remove (api.type, ifindex, &p);
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
free (nexthop);
void igmp_source_delete(struct igmp_source *source)
{
struct igmp_group *group;
+ struct in_addr src;
group = source->source_group;
*/
listnode_delete(group->group_source_list, source);
+ src.s_addr = source->source_addr.s_addr;
igmp_source_free(source);
+
/* Group source list is empty and current source is * then
*,G group going away so do not trigger start */
if (group->group_filtermode_isexcl &&
(listcount (group->group_source_list) != 0) &&
- source->source_addr.s_addr != INADDR_ANY)
+ src.s_addr != INADDR_ANY)
{
group_exclude_fwd_anysrc_ifempty (group);
}
vtysh_b ()
{
# Rember, that all variables have been incremented by 1 in convert_daemon_prios()
- if [ "$vtysh_enable" = 2 -a -f $C_PATH/Frr.conf ]; then
+ if [ "$vtysh_enable" = 2 -a -f $C_PATH/frr.conf ]; then
/usr/bin/vtysh -b -n
fi
}
check_daemon()
{
# If the integrated config file is used the others are not checked.
- if [ -r "$C_PATH/Frr.conf" ]; then
+ if [ -r "$C_PATH/frr.conf" ]; then
return 0
fi
reload)
# Just apply the commands that have changed, no restart necessary
[ ! -x "$RELOAD_SCRIPT" ] && echo "frr-reload script not available" && exit 0
- NEW_CONFIG_FILE="${2:-$C_PATH/Frr.conf}"
+ NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}"
[ ! -r $NEW_CONFIG_FILE ] && echo "Unable to read new configuration file $NEW_CONFIG_FILE" && exit 1
- echo "Applying only incremental changes to running configuration from Frr.conf"
- "$RELOAD_SCRIPT" --reload /etc/frr/Frr.conf
+ echo "Applying only incremental changes to running configuration from frr.conf"
+ "$RELOAD_SCRIPT" --reload /etc/frr/frr.conf
exit $?
;;
def line_for_vtysh_file(ctx_keys, line, delete):
"""
- Return the command as it would appear in Frr.conf
+ Return the command as it would appear in frr.conf
"""
cmd = []
parser.add_argument('--debug', action='store_true', help='Enable debugs', default=False)
parser.add_argument('--stdout', action='store_true', help='Log to STDOUT', default=False)
parser.add_argument('filename', help='Location of new frr config file')
- parser.add_argument('--overwrite', action='store_true', help='Overwrite Frr.conf with running config output', default=False)
+ parser.add_argument('--overwrite', action='store_true', help='Overwrite frr.conf with running config output', default=False)
args = parser.parse_args()
# Logging
os.unlink(filename)
# Make these changes persistent
- if args.overwrite or args.filename != '/etc/frr/Frr.conf':
+ if args.overwrite or args.filename != '/etc/frr/frr.conf':
subprocess.call(['/usr/bin/vtysh', '-c', 'write'])
LimitNOFILE=1024
ExecStart=/usr/lib/frr/frr start
ExecStop=/usr/lib/frr/frr stop
-ExecReload=/usr/lib/frr/frr-reload.py --reload /etc/frr/Frr.conf
+ExecReload=/usr/lib/frr/frr-reload.py --reload /etc/frr/frr.conf
[Install]
WantedBy=network-online.target
fprintf (stdout, "Note: this version of vtysh never writes vtysh.conf\n");
- /* If integrated Frr.conf explicitely set. */
+ /* If integrated frr.conf explicitely set. */
if (want_config_integrated())
{
ret = CMD_WARNING;
/* vtysh local configuration file. */
#define VTYSH_DEFAULT_CONFIG "vtysh.conf"
-#define FRR_DEFAULT_CONFIG "Frr.conf"
+#define FRR_DEFAULT_CONFIG "frr.conf"
enum vtysh_write_integrated {
WRITE_INTEGRATED_UNSPECIFIED,
"-m, --markfile Mark input file with context end\n" \
" --vty_socket Override vty socket path\n" \
" --config_dir Override config directory path\n" \
- "-w, --writeconfig Write integrated config (Frr.conf) and exit\n" \
+ "-w, --writeconfig Write integrated config (frr.conf) and exit\n" \
"-h, --help Display this help and exit\n\n" \
"Note that multiple commands may be executed from the command\n" \
"line by passing multiple -c args, or by embedding linefeed\n" \
strlcat(vtysh_config_always, vtysh_configfile_name,
sizeof(vtysh_config_always));
/*
- * Overwrite location for Frr.conf
+ * Overwrite location for frr.conf
*/
vtysh_configfile_name = strrchr(FRR_DEFAULT_CONFIG, '/');
if (vtysh_configfile_name)
config_write_integrated_cmd,
"write integrated",
"Write running configuration to memory, network, or terminal\n"
- "Write integrated all-daemon Frr.conf file\n")
+ "Write integrated all-daemon frr.conf file\n")
{
pid_t child;
sigset_t oldmask, sigmask;
during bootstrap. */
static int
netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id)
+ ns_id_t ns_id, int startup)
{
int len;
struct ifinfomsg *ifi;
ret = netlink_request (AF_PACKET, RTM_GETLINK, &zns->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns, 0);
+ ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns, 0, 1);
if (ret < 0)
return ret;
ret = netlink_request (AF_INET, RTM_GETADDR, &zns->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0);
+ ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0, 1);
if (ret < 0)
return ret;
ret = netlink_request (AF_INET6, RTM_GETADDR, &zns->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0);
+ ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns, 0, 1);
if (ret < 0)
return ret;
addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
strlen (ifc->label) + 1);
- return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
+ return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
}
int
int
netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id)
+ ns_id_t ns_id, int startup)
{
int len;
struct ifaddrmsg *ifa;
int
netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id)
+ ns_id_t ns_id, int startup)
{
int len;
struct ifinfomsg *ifi;
#ifdef HAVE_NETLINK
extern int netlink_interface_addr (struct sockaddr_nl *snl,
- struct nlmsghdr *h, ns_id_t ns_id);
+ struct nlmsghdr *h, ns_id_t ns_id, int startup);
extern int netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id);
+ ns_id_t ns_id, int startup);
extern int interface_lookup_netlink (struct zebra_ns *zns);
#endif /* HAVE_NETLINK */
int
netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id)
+ ns_id_t ns_id, int startup)
{
zlog_warn ("netlink_talk: ignoring message type 0x%04x NS %u", h->nlmsg_type,
ns_id);
static int
netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id)
+ ns_id_t ns_id, int startup)
{
/* JF: Ignore messages that aren't from the kernel */
if ( snl->nl_pid != 0 )
switch (h->nlmsg_type)
{
case RTM_NEWROUTE:
- return netlink_route_change (snl, h, ns_id);
+ return netlink_route_change (snl, h, ns_id, startup);
break;
case RTM_DELROUTE:
- return netlink_route_change (snl, h, ns_id);
+ return netlink_route_change (snl, h, ns_id, startup);
break;
case RTM_NEWLINK:
- return netlink_link_change (snl, h, ns_id);
+ return netlink_link_change (snl, h, ns_id, startup);
break;
case RTM_DELLINK:
- return netlink_link_change (snl, h, ns_id);
+ return netlink_link_change (snl, h, ns_id, startup);
break;
case RTM_NEWADDR:
- return netlink_interface_addr (snl, h, ns_id);
+ return netlink_interface_addr (snl, h, ns_id, startup);
break;
case RTM_DELADDR:
- return netlink_interface_addr (snl, h, ns_id);
+ return netlink_interface_addr (snl, h, ns_id, startup);
break;
default:
zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type,
kernel_read (struct thread *thread)
{
struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG (thread);
- netlink_parse_info (netlink_information_fetch, &zns->netlink, zns, 5);
+ netlink_parse_info (netlink_information_fetch, &zns->netlink, zns, 5, 0);
zns->t_netlink = thread_add_read (zebrad.master, kernel_read, zns,
zns->netlink.sock);
return lookup (rttype_str, rttype);
}
-/* Receive message from netlink interface and pass those information
- to the given function. */
+/*
+ * netlink_parse_info
+ *
+ * Receive message from netlink interface and pass those information
+ * to the given function.
+ *
+ * filter -> Function to call to read the results
+ * nl -> netlink socket information
+ * zns -> The zebra namespace data
+ * count -> How many we should read in, 0 means as much as possible
+ * startup -> Are we reading in under startup conditions? passed to
+ * the filter.
+ */
int
netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
- ns_id_t),
- struct nlsock *nl, struct zebra_ns *zns, int count)
+ ns_id_t, int),
+ struct nlsock *nl, struct zebra_ns *zns, int count, int startup)
{
int status;
int ret = 0;
continue;
}
- error = (*filter) (&snl, h, zns->ns_id);
+ error = (*filter) (&snl, h, zns->ns_id, startup);
if (error < 0)
{
zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
return ret;
}
-/* sendmsg() to netlink socket then recvmsg(). */
+/*
+ * netlink_talk
+ *
+ * sendmsg() to netlink socket then recvmsg().
+ * Calls netlink_parse_info to parse returned data
+ *
+ * filter -> The filter to read final results from kernel
+ * nlmsghdr -> The data to send to the kernel
+ * nl -> The netlink socket information
+ * zns -> The zebra namespace information
+ * startup -> Are we reading in under startup conditions
+ * This is passed through eventually to filter.
+ */
int
netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
- ns_id_t),
- struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns)
+ ns_id_t, int startup),
+ struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns, int startup)
{
int status;
struct sockaddr_nl snl;
* Get reply from netlink socket.
* The reply should either be an acknowlegement or an error.
*/
- return netlink_parse_info (filter, nl, zns, 0);
+ return netlink_parse_info (filter, nl, zns, 0, startup);
}
/* Get type specified information from netlink. */
extern const char * nl_rttype_to_str (u_char rttype);
extern int netlink_parse_info (int (*filter) (struct sockaddr_nl *,
- struct nlmsghdr *, ns_id_t), struct nlsock *nl,
- struct zebra_ns *zns, int count);
+ struct nlmsghdr *, ns_id_t, int),
+ struct nlsock *nl, struct zebra_ns *zns,
+ int count, int startup);
extern int netlink_talk_filter (struct sockaddr_nl *, struct nlmsghdr *,
- ns_id_t);
+ ns_id_t, int startup);
extern int netlink_talk (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
- ns_id_t),
+ ns_id_t, int startup),
struct nlmsghdr *n, struct nlsock *nl,
- struct zebra_ns *zns);
+ struct zebra_ns *zns, int startup);
extern int netlink_request (int family, int type, struct nlsock *nl);
#endif /* HAVE_NETLINK */
/* Looking up routing table by netlink interface. */
static int
-netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id)
+netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
+ ns_id_t ns_id, int startup)
{
int len;
struct rtmsg *rtm;
rtm = NLMSG_DATA (h);
- if (h->nlmsg_type != RTM_NEWROUTE)
+ if (startup && h->nlmsg_type != RTM_NEWROUTE)
return 0;
- if (rtm->rtm_type != RTN_UNICAST)
+ if (startup && rtm->rtm_type != RTN_UNICAST)
return 0;
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
if (rtm->rtm_protocol == RTPROT_KERNEL)
return 0;
+ if (!startup &&
+ rtm->rtm_protocol == RTPROT_ZEBRA &&
+ h->nlmsg_type == RTM_NEWROUTE)
+ return 0;
+
/* We don't care about change notifications for the MPLS table. */
/* TODO: Revisit this. */
if (rtm->rtm_family == AF_MPLS)
if (tb[RTA_GATEWAY])
gate = RTA_DATA (tb[RTA_GATEWAY]);
- if (tb[RTA_PRIORITY])
- metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
-
- if (tb[RTA_METRICS])
+ if (h->nlmsg_type == RTM_NEWROUTE)
{
- struct rtattr *mxrta[RTAX_MAX+1];
+ if (tb[RTA_PRIORITY])
+ metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
- memset (mxrta, 0, sizeof mxrta);
- netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
- RTA_PAYLOAD(tb[RTA_METRICS]));
+ if (tb[RTA_METRICS])
+ {
+ struct rtattr *mxrta[RTAX_MAX+1];
+
+ memset (mxrta, 0, sizeof mxrta);
+ netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
+ RTA_PAYLOAD(tb[RTA_METRICS]));
- if (mxrta[RTAX_MTU])
- mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
+ if (mxrta[RTAX_MTU])
+ mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
+ }
}
if (rtm->rtm_family == AF_INET)
p.family = AF_INET;
memcpy (&p.u.prefix4, dest, 4);
p.prefixlen = rtm->rtm_dst_len;
+ }
+ else if (rtm->rtm_family == AF_INET6)
+ {
+ p.family = AF_INET6;
+ memcpy (&p.u.prefix6, dest, 16);
+ p.prefixlen = rtm->rtm_dst_len;
+
+ src_p.family = AF_INET6;
+ memcpy (&src_p.prefix, src, 16);
+ src_p.prefixlen = rtm->rtm_src_len;
+ }
- if (rtm->rtm_src_len != 0)
- return 0;
+ if (rtm->rtm_src_len != 0)
+ {
+ char buf[PREFIX_STRLEN];
+ zlog_warn ("unsupported IPv[4|6] sourcedest route (dest %s vrf %u)",
+ prefix2str (&p, buf, sizeof(buf)), vrf_id);
+ return 0;
+ }
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ {
+ char buf[PREFIX_STRLEN];
+ char buf2[PREFIX_STRLEN];
+ zlog_debug ("%s %s%s%s vrf %u",
+ nl_msg_type_to_str (h->nlmsg_type),
+ prefix2str (&p, buf, sizeof(buf)),
+ src_p.prefixlen ? " from " : "",
+ src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2)) : "",
+ vrf_id);
+ }
+
+ afi_t afi = AFI_IP;
+ if (rtm->rtm_family == AF_INET6)
+ afi = AFI_IP6;
+ if (h->nlmsg_type == RTM_NEWROUTE)
+ {
if (!tb[RTA_MULTIPATH])
- rib_add (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
- 0, flags, &p, NULL, gate, prefsrc, index,
- table, metric, mtu, 0);
+ rib_add (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
+ 0, flags, &p, NULL, gate, prefsrc, index,
+ table, metric, mtu, 0);
else
{
/* This is a multipath route */
if (gate)
{
- if (index)
- rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index);
- else
- rib_nexthop_ipv4_add (rib, gate, prefsrc);
+ if (rtm->rtm_family == AF_INET)
+ {
+ if (index)
+ rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index);
+ else
+ rib_nexthop_ipv4_add (rib, gate, prefsrc);
+ }
+ else if (rtm->rtm_family == AF_INET6)
+ {
+ if (index)
+ rib_nexthop_ipv6_ifindex_add (rib, gate, index);
+ else
+ rib_nexthop_ipv6_add (rib,gate);
+ }
}
else
rib_nexthop_ifindex_add (rib, index);
rtnh = RTNH_NEXT(rtnh);
}
- zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
- rib->nexthop_num);
+ zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
+ rib->nexthop_num);
if (rib->nexthop_num == 0)
XFREE (MTYPE_RIB, rib);
else
rib_add_multipath (AFI_IP, SAFI_UNICAST, &p, NULL, rib);
}
}
- if (rtm->rtm_family == AF_INET6)
- {
- p.family = AF_INET6;
- memcpy (&p.u.prefix6, dest, 16);
- p.prefixlen = rtm->rtm_dst_len;
-
- src_p.family = AF_INET6;
- memcpy (&src_p.prefix, src, 16);
- src_p.prefixlen = rtm->rtm_src_len;
-
- rib_add (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
- 0, flags, &p, &src_p, gate, prefsrc, index,
- table, metric, mtu, 0);
- }
-
- return 0;
-}
-
-/* Routing information change from the kernel. */
-static int
-netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id)
-{
- int len;
- struct rtmsg *rtm;
- struct rtattr *tb[RTA_MAX + 1];
- u_char zebra_flags = 0;
- struct prefix p;
- vrf_id_t vrf_id = VRF_DEFAULT;
- char anyaddr[16] = { 0 };
-
- int index = 0;
- int table;
- int metric = 0;
- u_int32_t mtu = 0;
-
- void *dest = NULL;
- void *gate = NULL;
- void *prefsrc = NULL; /* IPv4 preferred source host address */
- void *src = NULL; /* IPv6 srcdest source prefix */
-
- rtm = NLMSG_DATA (h);
-
- len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
-
- memset (tb, 0, sizeof tb);
- netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
-
- if (rtm->rtm_flags & RTM_F_CLONED)
- return 0;
- if (rtm->rtm_protocol == RTPROT_REDIRECT)
- return 0;
- if (rtm->rtm_protocol == RTPROT_KERNEL)
- return 0;
-
- if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE)
- return 0;
- if (rtm->rtm_protocol == RTPROT_ZEBRA)
- SET_FLAG(zebra_flags, ZEBRA_FLAG_SELFROUTE);
-
- /* Table corresponding to route. */
- if (tb[RTA_TABLE])
- table = *(int *) RTA_DATA (tb[RTA_TABLE]);
else
- table = rtm->rtm_table;
-
- /* Map to VRF */
- vrf_id = vrf_lookup_by_table(table);
- if (vrf_id == VRF_DEFAULT)
{
- if (!is_zebra_valid_kernel_table(table) &&
- !is_zebra_main_routing_table(table))
- return 0;
- }
-
- if (tb[RTA_OIF])
- index = *(int *) RTA_DATA (tb[RTA_OIF]);
-
- if (tb[RTA_DST])
- dest = RTA_DATA (tb[RTA_DST]);
- else
- dest = anyaddr;
-
- if (tb[RTA_SRC])
- src = RTA_DATA (tb[RTA_SRC]);
- else
- src = anyaddr;
-
- if (tb[RTA_GATEWAY])
- gate = RTA_DATA (tb[RTA_GATEWAY]);
-
- if (tb[RTA_PREFSRC])
- prefsrc = RTA_DATA (tb[RTA_PREFSRC]);
-
- if (h->nlmsg_type == RTM_NEWROUTE)
- {
- if (tb[RTA_PRIORITY])
- metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
-
- if (tb[RTA_METRICS])
+ if (!tb[RTA_MULTIPATH])
+ rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags,
+ &p, NULL, gate, index, table);
+ else
{
- struct rtattr *mxrta[RTAX_MAX+1];
-
- memset (mxrta, 0, sizeof mxrta);
- netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
- RTA_PAYLOAD(tb[RTA_METRICS]));
-
- if (mxrta[RTAX_MTU])
- mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
- }
- }
-
- if (rtm->rtm_family == AF_INET)
- {
- p.family = AF_INET;
- memcpy (&p.u.prefix4, dest, 4);
- p.prefixlen = rtm->rtm_dst_len;
-
- if (rtm->rtm_src_len != 0)
- {
- zlog_warn ("unsupported IPv4 sourcedest route (dest %s/%d)",
- inet_ntoa (p.u.prefix4), p.prefixlen);
- return 0;
- }
+ struct rtnexthop *rtnh =
+ (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
- if (IS_ZEBRA_DEBUG_KERNEL)
- {
- char buf[PREFIX_STRLEN];
- zlog_debug ("%s %s vrf %u",
- nl_msg_type_to_str (h->nlmsg_type),
- prefix2str (&p, buf, sizeof(buf)), vrf_id);
- }
+ len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
- if (h->nlmsg_type == RTM_NEWROUTE)
- {
- if (!tb[RTA_MULTIPATH])
- rib_add (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
- 0, 0, &p, NULL, gate, prefsrc, index,
- table, metric, mtu, 0);
- else
+ for (;;)
{
- /* This is a multipath route */
-
- struct rib *rib;
- struct rtnexthop *rtnh =
- (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
-
- len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
-
- rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
- rib->type = ZEBRA_ROUTE_KERNEL;
- rib->distance = 0;
- rib->flags = 0;
- rib->metric = metric;
- rib->mtu = mtu;
- rib->vrf_id = vrf_id;
- rib->table = table;
- rib->nexthop_num = 0;
- rib->uptime = time (NULL);
-
- for (;;)
- {
- if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
- break;
-
- index = rtnh->rtnh_ifindex;
- gate = 0;
- if (rtnh->rtnh_len > sizeof (*rtnh))
- {
- memset (tb, 0, sizeof (tb));
- netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
- rtnh->rtnh_len - sizeof (*rtnh));
- if (tb[RTA_GATEWAY])
- gate = RTA_DATA (tb[RTA_GATEWAY]);
- }
-
- if (gate)
- {
- if (index)
- rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index);
- else
- rib_nexthop_ipv4_add (rib, gate, prefsrc);
- }
- else
- rib_nexthop_ifindex_add (rib, index);
+ if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
+ break;
- len -= NLMSG_ALIGN(rtnh->rtnh_len);
- rtnh = RTNH_NEXT(rtnh);
+ gate = NULL;
+ if (rtnh->rtnh_len > sizeof (*rtnh))
+ {
+ memset (tb, 0, sizeof (tb));
+ netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
+ rtnh->rtnh_len - sizeof (*rtnh));
+ if (tb[RTA_GATEWAY])
+ gate = RTA_DATA (tb[RTA_GATEWAY]);
}
- zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
- rib->nexthop_num);
+ if (gate)
+ rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags,
+ &p, NULL, gate, index, table);
- if (rib->nexthop_num == 0)
- XFREE (MTYPE_RIB, rib);
- else
- rib_add_multipath (AFI_IP, SAFI_UNICAST, &p, NULL, rib);
+ len -= NLMSG_ALIGN(rtnh->rtnh_len);
+ rtnh = RTNH_NEXT(rtnh);
}
}
- else
- rib_delete (AFI_IP, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, zebra_flags,
- &p, NULL, gate, index, table);
- }
-
- if (rtm->rtm_family == AF_INET6)
- {
- struct prefix p;
- struct prefix_ipv6 src_p;
-
- p.family = AF_INET6;
- memcpy (&p.u.prefix6, dest, 16);
- p.prefixlen = rtm->rtm_dst_len;
-
- src_p.family = AF_INET6;
- memcpy (&src_p.prefix, src, 16);
- src_p.prefixlen = rtm->rtm_src_len;
-
- if (IS_ZEBRA_DEBUG_KERNEL)
- {
- char buf[PREFIX_STRLEN];
- char buf2[PREFIX_STRLEN];
- zlog_debug ("%s %s%s%s vrf %u",
- nl_msg_type_to_str (h->nlmsg_type),
- prefix2str (&p, buf, sizeof(buf)),
- src_p.prefixlen ? " from " : "",
- src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2)) : "",
- vrf_id);
- }
-
- if (h->nlmsg_type == RTM_NEWROUTE)
- rib_add (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
- 0, 0, &p, &src_p, gate, prefsrc, index,
- table, metric, mtu, 0);
- else
- rib_delete (AFI_IP6, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
- 0, zebra_flags, &p, &src_p, gate, index, table);
}
return 0;
static int
netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id)
+ ns_id_t ns_id, int startup)
{
int len;
struct rtmsg *rtm;
int
netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id)
+ ns_id_t ns_id, int startup)
{
int len;
vrf_id_t vrf_id = ns_id;
switch (rtm->rtm_type)
{
case RTN_UNICAST:
- netlink_route_change_read_unicast (snl, h, ns_id);
+ netlink_route_change_read_unicast (snl, h, ns_id, startup);
break;
case RTN_MULTICAST:
- netlink_route_change_read_multicast (snl, h, ns_id);
+ netlink_route_change_read_multicast (snl, h, ns_id, startup);
break;
default:
return 0;
ret = netlink_request (AF_INET, RTM_GETROUTE, &zns->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_routing_table, &zns->netlink_cmd, zns, 0);
+ ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1);
if (ret < 0)
return ret;
ret = netlink_request (AF_INET6, RTM_GETROUTE, &zns->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_routing_table, &zns->netlink_cmd, zns, 0);
+ ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1);
if (ret < 0)
return ret;
addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
- return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
+ return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
}
/* Routing table change via netlink interface. */
snl.nl_family = AF_NETLINK;
/* Talk to netlink socket. */
- return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
+ return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
}
int
addattr_l (&req.n, sizeof (req), RTA_SRC, &mroute->sg.src.s_addr, 4);
addattr_l (&req.n, sizeof (req), RTA_DST, &mroute->sg.grp.s_addr, 4);
- suc = netlink_talk (netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns);
+ suc = netlink_talk (netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns, 0);
mroute = NULL;
return suc;
}
/* Talk to netlink socket. */
- return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns);
+ return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
}
/*
netlink_mpls_multipath (int cmd, zebra_lsp_t *lsp);
extern int netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
- ns_id_t ns_id);
+ ns_id_t ns_id, int startup);
extern int netlink_route_read (struct zebra_ns *zns);
#endif /* HAVE_NETLINK */