This patch provides three new public API functions that allow
reverting the network configuration back to a previous "known good"
state. The three new functions are:
ncf_change_begin() - save a snapshot of current network config
ncf_change_rollback() - revert to the config previously saved
ncf_change_commit() - delete the saved snapshot, making the new
config permanent
If the system is rebooted after ncf_change_begin() is called, but
prior to calling ncf_change_commit(), the network config will be
automatically reverted to the saved state during the boot process.
The functionality is provided by the the script netcf-transaction,
which was added in the previous patch.
This initial version only updates the config files during a
rollback. It doesn't attempt to ifdown interfaces that are being
removed, ifup interfaces that are being added, or ifdown/ifup
interfaces that have been changed. That will be in an upcoming patch.
---
configure.ac | 2 +-
src/drv_initscripts.c | 43 +++++++++++++++++++++++++++++++++
src/internal.h | 4 +++
src/ncftool.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++
src/netcf.c | 21 ++++++++++++++++
src/netcf.h | 22 +++++++++++++++++
src/netcf_public.syms | 7 +++++
7 files changed, 161 insertions(+), 1 deletions(-)
diff --git a/configure.ac b/configure.ac
index f62097b..abc7a13 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,7 +6,7 @@ AM_CONFIG_HEADER([config.h])
AM_INIT_AUTOMAKE([-Wno-portability 1.11 color-tests parallel-tests])
AM_SILENT_RULES([yes]) # make --enable-silent-rules the default.
-AC_SUBST([LIBNETCF_VERSION_INFO], [4:3:3])
+AC_SUBST([LIBNETCF_VERSION_INFO], [5:0:4])
AC_GNU_SOURCE
diff --git a/src/drv_initscripts.c b/src/drv_initscripts.c
index b2f16d5..39a8070 100644
--- a/src/drv_initscripts.c
+++ b/src/drv_initscripts.c
@@ -1070,6 +1070,49 @@ int drv_if_down(struct netcf_if *nif) {
return result;
}
+/* Functions to take a snapshot of network config (change_begin), and
+ * later either revert to that config (change_rollback), or make the
+ * new config permanent (change_commit).
+ */
+int
+drv_change_begin(struct netcf *ncf ATTRIBUTE_UNUSED,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ int result = -1;
+
+ run1(ncf, NETCF_TRANSACTION, "change-begin");
+ ERR_BAIL(ncf);
+ result = 0;
+error:
+ return result;
+}
+
+int
+drv_change_rollback(struct netcf *ncf ATTRIBUTE_UNUSED,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ int result = -1;
+
+ run1(ncf, NETCF_TRANSACTION, "change-rollback");
+ ERR_BAIL(ncf);
+ result = 0;
+error:
+ return result;
+}
+
+int
+drv_change_commit(struct netcf *ncf ATTRIBUTE_UNUSED,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ int result = -1;
+
+ run1(ncf, NETCF_TRANSACTION, "change-commit");
+ ERR_BAIL(ncf);
+ result = 0;
+error:
+ return result;
+}
+
/*
* Test interface
*/
diff --git a/src/internal.h b/src/internal.h
index b7fa5f2..78494e9 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -182,6 +182,10 @@ int drv_lookup_by_mac_string(struct netcf *, const char *mac,
char *drv_xml_desc(struct netcf_if *);
char *drv_xml_state(struct netcf_if *);
int drv_if_status(struct netcf_if *nif, unsigned int *flags);
+int drv_change_begin(struct netcf *ncf, unsigned int flags);
+int drv_change_rollback(struct netcf *ncf, unsigned int flags);
+int drv_change_commit(struct netcf *ncf, unsigned int flags);
+
const char *drv_mac_string(struct netcf_if *nif);
struct netcf_if *drv_define(struct netcf *ncf, const char *xml);
int drv_undefine(struct netcf_if *nif);
diff --git a/src/ncftool.c b/src/ncftool.c
index f86b62c..b202e17 100644
--- a/src/ncftool.c
+++ b/src/ncftool.c
@@ -412,6 +412,66 @@ static const struct command_def cmd_undefine_def = {
.help = "remove the configuration of an interface"
};
+static int cmd_change_begin(ATTRIBUTE_UNUSED const struct command *cmd)
+{
+ if (ncf_change_begin(ncf, 0) < 0)
+ return CMD_RES_ERR;
+ printf("config change transaction started\n");
+ return CMD_RES_OK;
+}
+
+static const struct command_opt_def cmd_change_begin_opts[] = {
+ CMD_OPT_DEF_LAST
+};
+
+static const struct command_def cmd_change_begin_def = {
+ .name = "change-begin",
+ .opts = cmd_change_begin_opts,
+ .handler = cmd_change_begin,
+ .synopsis = "mark the beginning of a set of revertable network config
changes",
+ .help = "marks the beginning of a set of revertable network config
changes",
+};
+
+static int cmd_change_commit(ATTRIBUTE_UNUSED const struct command *cmd)
+{
+ if (ncf_change_commit(ncf, 0) < 0)
+ return CMD_RES_ERR;
+ printf("config change transaction committed\n");
+ return CMD_RES_OK;
+}
+
+static const struct command_opt_def cmd_change_commit_opts[] = {
+ CMD_OPT_DEF_LAST
+};
+
+static const struct command_def cmd_change_commit_def = {
+ .name = "change-commit",
+ .opts = cmd_change_commit_opts,
+ .handler = cmd_change_commit,
+ .synopsis = "commit the pending network config changes",
+ .help = "commits (makes permanent) of a set of network config changes",
+};
+
+static int cmd_change_rollback(ATTRIBUTE_UNUSED const struct command *cmd)
+{
+ if (ncf_change_rollback(ncf, 0) < 0)
+ return CMD_RES_ERR;
+ printf("config change transaction rolled back\n");
+ return CMD_RES_OK;
+}
+
+static const struct command_opt_def cmd_change_rollback_opts[] = {
+ CMD_OPT_DEF_LAST
+};
+
+static const struct command_def cmd_change_rollback_def = {
+ .name = "change-rollback",
+ .opts = cmd_change_rollback_opts,
+ .handler = cmd_change_rollback,
+ .synopsis = "rollback (revert) a set of network config changes",
+ .help = "rollback (revert) a set of network config changes",
+};
+
static int cmd_help(const struct command *cmd) {
const char *name = param_value(cmd, "command");
if (name == NULL) {
@@ -616,6 +676,9 @@ static const struct command_def const *commands[] = {
&cmd_undefine_def,
&cmd_if_up_def,
&cmd_if_down_def,
+ &cmd_change_begin_def,
+ &cmd_change_commit_def,
+ &cmd_change_rollback_def,
&cmd_help_def,
&cmd_quit_def,
&cmd_def_last
diff --git a/src/netcf.c b/src/netcf.c
index 9440ed0..34994bb 100644
--- a/src/netcf.c
+++ b/src/netcf.c
@@ -196,6 +196,27 @@ int ncf_if_status(struct netcf_if *nif, unsigned int *flags) {
return drv_if_status(nif, flags);
}
+int
+ncf_change_begin(struct netcf *ncf, unsigned int flags)
+{
+ API_ENTRY(ncf);
+ return drv_change_begin(ncf, flags);
+}
+
+int
+ncf_change_rollback(struct netcf *ncf, unsigned int flags)
+{
+ API_ENTRY(ncf);
+ return drv_change_rollback(ncf, flags);
+}
+
+int
+ncf_change_commit(struct netcf *ncf, unsigned int flags)
+{
+ API_ENTRY(ncf);
+ return drv_change_commit(ncf, flags);
+}
+
/* Release any resources used by this NETCF_IF; the pointer is invalid
* after this call
*/
diff --git a/src/netcf.h b/src/netcf.h
index bf5e4e2..e507b97 100644
--- a/src/netcf.h
+++ b/src/netcf.h
@@ -169,6 +169,28 @@ char *ncf_if_xml_state(struct netcf_if *);
*/
int ncf_if_status(struct netcf_if *nif, unsigned int *flags);
+/* Mark the beginning of a sequence of revertable changes to the
+ * network interface config by saving a snapshot of all relevant
+ * config information.
+ * Returns 0 on success, -1 on failure
+ */
+int ncf_change_begin(struct netcf *ncf, unsigned int flags);
+
+/* Revert to the previously snapshotted (with ncf_change_begin)
+ * network config, effectively undoing the changes.
+ * Returns 0 on success, -1 on failure
+ */
+int ncf_change_rollback(struct netcf *ncf, unsigned int flags);
+
+/* Commit the changes made to network config since ncf_change_begin
+ * was called (usually by simply deleting the snapshot that was saved,
+ * as well as bringing down any interfaces that will not be present in
+ * the restored config, and bouncing interfaces that still exist, but
+ * have changed their config.)
+ * Returns 0 on success, -1 on failure
+ */
+int ncf_change_commit(struct netcf *ncf, unsigned int flags);
+
/* Release any resources used by this NETCF_IF; the pointer is invalid
* after this call
*/
diff --git a/src/netcf_public.syms b/src/netcf_public.syms
index 9180614..e0e034a 100644
--- a/src/netcf_public.syms
+++ b/src/netcf_public.syms
@@ -28,3 +28,10 @@ NETCF_1.3.0 {
global:
ncf_if_status;
} NETCF_1.2.0;
+
+NETCF_1.4.0 {
+ global:
+ ncf_change_begin;
+ ncf_change_commit;
+ ncf_change_rollback;
+} NETCF_1.3.0;
--
1.7.3.4