zebra: Add command to configure default for link-state, and make it sticky
* Provide a way for the user to specify their own preference for the default
behaviour of link-detect, independent of the compiled in default.
Add a global "default link-detect (on|off)" command to zebra, to set
the default policy for link-detect accordingly. The command is "sticky" -
when set it will stay set and always be written out, regardless of how it
compares to the baked-in, compile-time default.
The per-interface "link-detect" command is similarly made sticky.
* zebra/interface.h: (zebra_if_linkdetect;) enum for link-detect configured
state.
(struct zebra_if_defaults) Global link-detect default
(struct zebra_if) Add field for per-iface link-detect default.
* lib/if.c: (if_create_vrf) Remove the default flag setting on if-create
here, it's a zebra flag so do it in zebra's if_zebra_new_hook
* zebra/interface.c: Add static storage for global defaults.
(if_zebra_new_hook) Set the link-detect flag on new ifaces according to the
baked in default or else the configured global default.
(config_write_zebra_if_defaults,default_linkdetect_cmd) global link-detect
command and config write out machinery.
(linkdetect_cmd) Set the configuration state rather than the flag.
The new hook will then set the interface flag when the if comes up.
(if_config_write) Write config according to configured state, not the
low-level flag.
(zebra_if_init) add new commands.
diff --git a/zebra/interface.c b/zebra/interface.c
index f259eeb..7559795 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -49,6 +49,50 @@
const char *rtadv_pref_strs[] = { "medium", "high", "INVALID", "low", 0 };
#endif /* HAVE_RTADV */
+/* We don't have a tidy top-level instance object for zebra, or interfaces */
+static struct zebra_if_defaults zif_defaults = {
+ .linkdetect = IF_LINKDETECT_UNSPEC,
+};
+
+/* helper only for if_zebra_linkdetect */
+static void
+if_zebra_linkdetect_set_val (struct interface *ifp, zebra_if_linkdetect val)
+{
+ switch (val)
+ {
+ case IF_LINKDETECT_ON:
+ SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+ break;
+ case IF_LINKDETECT_OFF:
+ UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+ break;
+ default: break;
+ }
+}
+
+static void
+if_zebra_linkdetect_set (struct interface *ifp)
+{
+ struct zebra_if *zif = ifp->info;
+ assert (zif != NULL);
+ int if_was_operative = if_is_operative(ifp);
+
+ /* If user has explicitly configured for the interface, let that set */
+ if (zif->linkdetect != IF_LINKDETECT_UNSPEC)
+ if_zebra_linkdetect_set_val (ifp, zif->linkdetect);
+ else
+ {
+ /* general compiled in default is to set */
+ SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+ /* but user can specify a default too */
+ if_zebra_linkdetect_set_val (ifp, zif_defaults.linkdetect);
+ }
+ /* When linkdetection is enabled, interface might come down */
+ if (!if_is_operative(ifp) && if_was_operative) if_down(ifp);
+ /* Alternatively, it may come up after disabling link detection */
+ if (if_is_operative(ifp) && !if_was_operative) if_up(ifp);
+}
+
/* Called when new interface is added. */
static int
if_zebra_new_hook (struct interface *ifp)
@@ -60,6 +104,18 @@
zebra_if->multicast = IF_ZEBRA_MULTICAST_UNSPEC;
zebra_if->shutdown = IF_ZEBRA_SHUTDOWN_OFF;
+ switch (zif_defaults.linkdetect)
+ {
+ case IF_LINKDETECT_OFF:
+ UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+ break;
+ case IF_LINKDETECT_UNSPEC:
+ case IF_LINKDETECT_ON:
+ default:
+ SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+ break;
+ }
+
#if defined (HAVE_RTADV)
{
/* Set default router advertise values. */
@@ -1304,21 +1360,65 @@
return CMD_SUCCESS;
}
+/* Hacky: create a dummy node just to hang a config-writer callback off it */
+static struct cmd_node zebra_if_defaults_node = {
+ ZEBRA_IF_DEFAULTS_NODE,
+ "",
+ 1,
+};
+
+static int
+config_write_zebra_if_defaults (struct vty *vty)
+{
+ if (zif_defaults.linkdetect != IF_LINKDETECT_UNSPEC)
+ vty_out (vty, "default link-detect %s%s",
+ zif_defaults.linkdetect == IF_LINKDETECT_ON ? "on" : "off",
+ VTY_NEWLINE);
+ return 0;
+}
+
+DEFUN(default_linkdetect,
+ default_linkdetect_cmd,
+ "default link-detect (on|off)",
+ "Configure defaults of settings\n"
+ "Interface link detection\n"
+ "Interface link-detect defaults to enabled\n"
+ "Interface link-detect defaults to disabled\n")
+{
+ zebra_if_linkdetect prev = zif_defaults.linkdetect;
+ struct listnode *node;
+ struct interface *ifp;
+ vrf_iter_t iter;
+
+ if (strcmp (argv[1], "on") == 0)
+ zif_defaults.linkdetect = IF_LINKDETECT_ON;
+ else
+ zif_defaults.linkdetect = IF_LINKDETECT_OFF;
+
+ if (zif_defaults.linkdetect != prev)
+ for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+ for (ALL_LIST_ELEMENTS_RO (vrf_iter2iflist (iter), node, ifp))
+ if_zebra_linkdetect_set (ifp);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (linkdetect,
linkdetect_cmd,
- "link-detect",
- "Enable link detection on interface\n")
+ "link-detect [default]",
+ "Enable link detection on interface\n"
+ "Leave link-detect to the default\n")
{
struct interface *ifp;
- int if_was_operative;
+ struct zebra_if *zif;
ifp = (struct interface *) vty->index;
- if_was_operative = if_is_operative(ifp);
- SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
-
- /* When linkdetection is enabled, if might come down */
- if (!if_is_operative(ifp) && if_was_operative) if_down(ifp);
-
+ zif = ifp->info;
+ assert (zif != NULL);
+
+ zif->linkdetect = IF_LINKDETECT_ON;
+ if_zebra_linkdetect_set (ifp);
+
/* FIXME: Will defer status change forwarding if interface
does not come down! */
@@ -1333,15 +1433,15 @@
"Disable link detection on interface\n")
{
struct interface *ifp;
- int if_was_operative;
-
- ifp = (struct interface *) vty->index;
- if_was_operative = if_is_operative(ifp);
- UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
+ struct zebra_if *zif;
- /* Interface may come up after disabling link detection */
- if (if_is_operative(ifp) && !if_was_operative) if_up(ifp);
-
+ ifp = (struct interface *) vty->index;
+ zif = ifp->info;
+ assert (zif != NULL);
+
+ zif->linkdetect = IF_LINKDETECT_OFF;
+ if_zebra_linkdetect_set (ifp);
+
/* FIXME: see linkdetect_cmd */
return CMD_SUCCESS;
@@ -2573,11 +2673,18 @@
while processing config script */
if (ifp->bandwidth != 0)
vty_out(vty, " bandwidth %u%s", ifp->bandwidth, VTY_NEWLINE);
- if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION))
- vty_out(vty, " link-detect%s", VTY_NEWLINE);
- else
- vty_out(vty, " no link-detect%s", VTY_NEWLINE);
-
+
+ switch (if_data->linkdetect)
+ {
+ case IF_LINKDETECT_ON:
+ vty_out(vty, " link-detect%s", VTY_NEWLINE);
+ break;
+ case IF_LINKDETECT_OFF:
+ vty_out(vty, " no link-detect%s", VTY_NEWLINE);
+ break;
+ default: break;
+ }
+
for (ALL_LIST_ELEMENTS_RO (ifp->connected, addrnode, ifc))
{
if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
@@ -2629,6 +2736,8 @@
/* Install configuration write function. */
install_node (&interface_node, if_config_write);
+
+ install_node (&zebra_if_defaults_node, config_write_zebra_if_defaults);
install_node (&link_params_node, NULL);
@@ -2642,6 +2751,7 @@
install_element (CONFIG_NODE, &zebra_interface_vrf_cmd);
install_element (CONFIG_NODE, &no_interface_cmd);
install_element (CONFIG_NODE, &no_interface_vrf_cmd);
+ install_element (CONFIG_NODE, &default_linkdetect_cmd);
install_default (INTERFACE_NODE);
install_element (INTERFACE_NODE, &interface_desc_cmd);
install_element (INTERFACE_NODE, &no_interface_desc_cmd);