(I *think* I got all your suggestions in here, including rebase. I
will be out for a few hours starting at 2PM EST (Dr. appt), so if you
want any changes, try to mail back early. Also, it wasn't clear to me
if the rng needs to be changed right away to allow for dhcp and an ip
address to be set at the same time (was that added in with your ipv6
commit?); likewise - I guess we need to add something to allow for
'source="device"', but I'm not familiar enough with RNG to know
what
to put where.)
ncf_if_xml_state() returns the current live state of the interface,
which is just the same document returned by ncf_if_xml_desc(), with
the addition/modification of IP address and netmask (prefix) to the
values retrieved directly from the interface. This is useful to learn
the IP address assigned to an interface configured to used DHCP.
Any ip address retrieved in this manner will have a property "source"
set to "device", as a clue for the consumer.
Currently only the 1st IPv4 address on an interface is added. The next
step will be to use the netlink socket (rather than
ioctl(SOICGIFxxxx)) to get all IPv4 and IPv6 addresses for the
interface.
---
src/drv_initscripts.c | 68 +++++++++++++++++++++++++----
src/dutil.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++
src/dutil.h | 14 ++++++
src/internal.h | 1 +
src/ncftool.c | 8 +++-
src/netcf.c | 10 ++++
src/netcf.h | 14 +++++-
src/netcf_public.syms | 5 ++
8 files changed, 222 insertions(+), 13 deletions(-)
diff --git a/src/drv_initscripts.c b/src/drv_initscripts.c
index 02b7e6e..e8c4698 100644
--- a/src/drv_initscripts.c
+++ b/src/drv_initscripts.c
@@ -702,18 +702,16 @@ static int aug_put_xml(struct netcf *ncf, xmlDocPtr xml) {
return result;
}
-char *drv_xml_desc(struct netcf_if *nif) {
- char *result = NULL;
- struct augeas *aug;
+/* given a netcf_if, get the config for an interface in the simple
+ * Augeas format
+ */
+static xmlDocPtr aug_get_xml_for_nif(struct netcf_if *nif) {
struct netcf *ncf;
char **devs = NULL, **intf = NULL;
xmlDocPtr aug_xml = NULL;
int ndevs = 0, nint = 0;
ncf = nif->ncf;
- aug = get_augeas(ncf);
- ERR_BAIL(ncf);
-
ndevs = aug_fmt_match(ncf, &devs,
"%s[ DEVICE = '%s' or BRIDGE = '%s' or MASTER =
'%s'"
" or MASTER = ../*[BRIDGE = '%s']/DEVICE ]/DEVICE",
@@ -725,12 +723,64 @@ char *drv_xml_desc(struct netcf_if *nif) {
aug_xml = aug_get_xml(ncf, nint, intf);
+ error:
+ free_matches(ndevs, &devs);
+ free_matches(nint, &intf);
+ return aug_xml;
+}
+
+/* return the current static configuration (as saved on disk) */
+char *drv_xml_desc(struct netcf_if *nif) {
+ char *result = NULL;
+ struct netcf *ncf;
+ xmlDocPtr aug_xml = NULL;
+
+ ncf = nif->ncf;
+ aug_xml = aug_get_xml_for_nif(nif);
+ ERR_BAIL(ncf);
+
result = apply_stylesheet_to_string(ncf, ncf->driver->put, aug_xml);
+
+ error:
+ xmlFreeDoc(aug_xml);
+ return result;
+}
+
+/* return the current live configuration state - a combination of
+ * drv_xml_desc + results of querying the interface directly */
+
+char *drv_xml_state(struct netcf_if *nif) {
+ char *result = NULL;
+ int r, result_len;
+ struct netcf *ncf;
+ xmlDocPtr aug_xml = NULL, ncf_xml = NULL;
+ unsigned int ipv4;
+ int prefix;
+
+ ncf = nif->ncf;
+ aug_xml = aug_get_xml_for_nif(nif);
ERR_BAIL(ncf);
- done:
- free_matches(ndevs, &devs);
- free_matches(nint, &intf);
+ ncf_xml = apply_stylesheet(ncf, ncf->driver->put, aug_xml);
+ ERR_BAIL(ncf);
+
+ /* get the current IP address. If it's non-zero, also get the
+ * current prefix, and add both to the document */
+ ipv4 = if_ipv4_address(ncf, nif->name);
+ ERR_BAIL(ncf);
+ if (ipv4 != 0) {
+ prefix = if_ipv4_prefix(ncf, nif->name);
+ ERR_BAIL(ncf);
+ add_state_to_xml_doc(ncf_xml, ncf, ipv4, prefix);
+ ERR_BAIL(ncf);
+ }
+
+ r = xsltSaveResultToString((xmlChar **)&result, &result_len,
+ ncf_xml, ncf->driver->put);
+ ERR_NOMEM(r < 0, ncf);
+
+done:
+ xmlFreeDoc(ncf_xml);
xmlFreeDoc(aug_xml);
return result;
error:
diff --git a/src/dutil.c b/src/dutil.c
index d51994f..e2d05b8 100644
--- a/src/dutil.c
+++ b/src/dutil.c
@@ -35,6 +35,9 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
#include "safe-alloc.h"
#include "ref.h"
@@ -435,11 +438,53 @@ int if_is_active(struct netcf *ncf, const char *intf) {
strncpy(ifr.ifr_name, intf, sizeof(ifr.ifr_name));
ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
if (ioctl(ncf->driver->ioctl_fd, SIOCGIFFLAGS, &ifr)) {
+ report_error(ncf, NETCF_EIOCTL, "Failed to get interface flags for %s",
intf);
return 0;
}
return ((ifr.ifr_flags & IFF_UP) == IFF_UP);
}
+unsigned int if_ipv4_address(struct netcf *ncf, const char *intf) {
+ struct ifreq ifr;
+
+ MEMZERO(&ifr, 1);
+ strncpy(ifr.ifr_name, intf, sizeof(ifr.ifr_name));
+ ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
+ if (ioctl(ncf->driver->ioctl_fd, SIOCGIFADDR, &ifr)) {
+ report_error(ncf, NETCF_EIOCTL, "Failed to get ipv4 address for %s",
intf);
+ return 0;
+ }
+
+ return (((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr);
+}
+
+unsigned int if_ipv4_netmask(struct netcf *ncf, const char *intf) {
+ struct ifreq ifr;
+
+ MEMZERO(&ifr, 1);
+ strncpy(ifr.ifr_name, intf, sizeof(ifr.ifr_name));
+ ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
+ if (ioctl(ncf->driver->ioctl_fd, SIOCGIFNETMASK, &ifr)) {
+ report_error(ncf, NETCF_EIOCTL, "Failed to get ipv4 netmask for %s",
intf);
+ return 0;
+ }
+
+ return (((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr);
+}
+
+
+int if_ipv4_prefix(struct netcf *ncf, const char *intf) {
+ unsigned int nmv4 = if_ipv4_netmask(ncf, intf);
+ int prefix = 0;
+
+ nmv4 = ntohl(nmv4);
+ while ((nmv4 & 0xFFFFFFFF) != 0) {
+ nmv4 <<= 1;
+ prefix++;
+ }
+ return prefix;
+}
+
/* Create a new netcf if instance for interface NAME */
struct netcf_if *make_netcf_if(struct netcf *ncf, char *name) {
int r;
@@ -499,6 +544,76 @@ int dutil_put_aug(struct netcf *ncf, const char *aug_xml, char
**ncf_xml) {
return result;
}
+/* Given an xml document that follows interface.rng, add the IP
+ * address and prefix under protocol/ip
+ */
+void add_state_to_xml_doc(xmlDocPtr doc, struct netcf *ncf ATTRIBUTE_UNUSED,
+ unsigned int ipv4, int prefix) {
+
+ xmlNodePtr root = NULL, proto = NULL, ip = NULL, cur;
+ xmlAttrPtr prop = NULL;
+ char ip_str[48], prefix_str[16];
+
+
+ root = xmlDocGetRootElement(doc);
+ ERR_THROW((root == NULL), ncf, EINTERNAL, "failed to get document root
element");
+
+ ERR_THROW(!xmlStrEqual(root->name, BAD_CAST "interface"),
+ ncf, EINTERNAL, "root document is not an interface");
+
+ for (cur = root->children; cur != NULL; cur = cur->next) {
+ if ((cur->type == XML_ELEMENT_NODE) &&
+ (xmlStrEqual(cur->name, BAD_CAST "protocol"))) {
+ xmlChar *family = xmlGetProp(cur, BAD_CAST "family");
+ if (family != NULL) {
+ if (xmlStrEqual(family, BAD_CAST "ipv4"))
+ proto = cur;
+ xmlFree(family);
+ if (proto != NULL) {
+ break;
+ }
+ }
+ }
+ }
+ if (proto == NULL) {
+ proto = xmlNewDocNode(doc, NULL, BAD_CAST "protocol", NULL);
+ ERR_NOMEM((proto == NULL), ncf);
+
+ cur = xmlAddChild(root, proto);
+ ERR_NOMEM((cur == NULL), ncf);
+ prop = xmlSetProp(proto, BAD_CAST "family", BAD_CAST
"ipv4");
+ ERR_NOMEM((prop == NULL), ncf);
+
+ }
+
+ for (cur = proto->children; cur != NULL; cur = cur->next) {
+ if ((cur->type == XML_ELEMENT_NODE) &&
+ (xmlStrEqual(cur->name, BAD_CAST "ip"))) {
+ break;
+ }
+ }
+
+ if (ip == NULL) {
+ ip = xmlNewDocNode(doc, NULL, BAD_CAST "ip", NULL);
+ ERR_NOMEM((ip == NULL), ncf);
+
+ cur = xmlAddChild(proto, ip);
+ ERR_NOMEM((cur == NULL), ncf);
+ }
+
+ inet_ntop(AF_INET, (struct in_addr *)&ipv4, ip_str, sizeof(ip_str));
+ prop = xmlSetProp(ip, BAD_CAST "address", BAD_CAST ip_str);
+ ERR_NOMEM((prop == NULL), ncf);
+ snprintf(prefix_str, sizeof(prefix_str), "%d", prefix);
+ prop = xmlSetProp(ip, BAD_CAST "prefix", BAD_CAST prefix_str);
+ ERR_NOMEM((prop == NULL), ncf);
+ prop = xmlSetProp(ip, BAD_CAST "source", BAD_CAST "device");
+ ERR_NOMEM((prop == NULL), ncf);
+
+error:
+ return;
+}
+
/*
* Bringing interfaces up/down
*/
diff --git a/src/dutil.h b/src/dutil.h
index 094324f..0a9715f 100644
--- a/src/dutil.h
+++ b/src/dutil.h
@@ -112,6 +112,17 @@ int init_ioctl_fd(struct netcf *ncf);
/* Check if the interface INTF is up using an ioctl call */
int if_is_active(struct netcf *ncf, const char *intf);
+/* Get the current IPv4 address of INTF as an unsigned int using an ioctl call */
+unsigned int if_ipv4_address(struct netcf *ncf, const char *intf);
+
+/* get the current IPv4 netmask of INTF as an unsigned int using an ioctl call */
+unsigned int if_ipv4_netmask(struct netcf *ncf, const char *intf);
+
+/* get the current IPv4 prefix (#bits of netmask) of INTF as an
+ * int using an ioctl call */
+
+int if_ipv4_prefix(struct netcf *ncf, const char *intf);
+
/* Create a new netcf if instance for interface NAME */
struct netcf_if *make_netcf_if(struct netcf *ncf, char *name);
@@ -121,6 +132,9 @@ int dutil_get_aug(struct netcf *ncf, const char *ncf_xml, char
**aug_xml);
/* Transform the Augeas XML AUG_XML into interface XML NCF_XML */
int dutil_put_aug(struct netcf *ncf, const char *aug_xml, char **ncf_xml);
+/* add the given state (currently IP + netmask) to the interface's xml document */
+void add_state_to_xml_doc(xmlDocPtr doc, struct netcf *ncf, unsigned int ipv4, int
prefix);
+
/* Run the program PROG with the single argument ARG */
void run1(struct netcf *ncf, const char *prog, const char *arg);
diff --git a/src/internal.h b/src/internal.h
index 7205e72..ca9a0ef 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -179,6 +179,7 @@ struct netcf_if *drv_lookup_by_name(struct netcf *ncf, const char
*name);
int drv_lookup_by_mac_string(struct netcf *, const char *mac,
int maxifaces, struct netcf_if **ifaces);
char *drv_xml_desc(struct netcf_if *);
+char *drv_xml_state(struct netcf_if *);
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 a1362c2..3639dd7 100644
--- a/src/ncftool.c
+++ b/src/ncftool.c
@@ -228,7 +228,11 @@ static int cmd_dump_xml(const struct command *cmd) {
goto done;
}
- xml = ncf_if_xml_desc(nif);
+ if (opt_present(cmd, "live")) {
+ xml = ncf_if_xml_state(nif);
+ } else {
+ xml = ncf_if_xml_desc(nif);
+ }
if (xml == NULL)
goto done;
@@ -246,6 +250,8 @@ static const struct command_opt_def cmd_dump_xml_opts[] = {
.help = "interpret the name as a MAC address" },
{ .tag = CMD_OPT_ARG, .name = "name",
.help = "the name of the interface" },
+ { .tag = CMD_OPT_BOOL, .name = "live",
+ .help = "show show live state of the interface, rather than just config file
settings" },
CMD_OPT_DEF_LAST
};
diff --git a/src/netcf.c b/src/netcf.c
index 7ca4fd9..97d3b17 100644
--- a/src/netcf.c
+++ b/src/netcf.c
@@ -200,6 +200,16 @@ char *ncf_if_xml_desc(struct netcf_if *nif) {
return drv_xml_desc(nif);
}
+/* Produce an XML description of the current live state of the
+ * interface, in the same format that NCF_DEFINE expects, but
+ * potentially with extra info not contained in the static config (ie
+ * the current IP address of an interface that uses DHCP)
+ */
+char *ncf_if_xml_state(struct netcf_if *nif) {
+ API_ENTRY(nif->ncf);
+ return drv_xml_state(nif);
+}
+
/* 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 482b6d0..4219cc1 100644
--- a/src/netcf.h
+++ b/src/netcf.h
@@ -51,7 +51,8 @@ typedef enum {
NETCF_EINUSE, /* attempt to close a netcf instance that is still
* used by other data structures */
NETCF_EXSLTFAILED, /* XSLT transformation failed */
- NETCF_EFILE /* Some file access failed */
+ NETCF_EFILE, /* Some file access failed */
+ NETCF_EIOCTL /* An ioctl call failed */
} netcf_errcode_t;
@@ -149,11 +150,18 @@ int ncf_if_down(struct netcf_if *);
/* Delete the definition */
int ncf_if_undefine(struct netcf_if *);
-/* Produce an XML description for the interface, in the same format that
- * NCF_DEFINE expects
+/* Produce an XML description for the static (stored) interface
+ * config, in the same format that NCF_DEFINE expects
*/
char *ncf_if_xml_desc(struct netcf_if *);
+/* Produce an XML description of the current live state of the
+ * interface, in the same format that NCF_DEFINE expects, but
+ * potentially with extra info not contained in the static config (ie
+ * the current IP address of an interface that uses DHCP)
+ */
+char *ncf_if_xml_state(struct netcf_if *);
+
/* 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 230b6bf..d2d1832 100644
--- a/src/netcf_public.syms
+++ b/src/netcf_public.syms
@@ -18,3 +18,8 @@ NETCF_1.0.0 {
local:
*;
};
+
+NETCF_1.1.0 {
+ global:
+ ncf_if_xml_state;
+} NETCF_1.0.0;
--
1.6.2.5