Undefining a bridge does not recreate the original interface
by Cole Robinson
Hi all,
Playing with netcf a bit, I'm hitting an issue with undefining a bridge:
the original interface disappears from the ncftool --list output, and
its ifcfg script is completely gone.
$ sudo cat /etc/sysconfig/network-scripts/ifcfg-wlan0
# Networking Interface
DEVICE=wlan0
HWADDR=00:1C:BF:04:29:A4
ONBOOT=no
TYPE=wireless
$ cat netcfbridge.xml
<interface type="bridge" name="testbr0">
<start mode="none"/>
<mtu size="1500"/>
<protocol family="ipv4">
<dhcp/>
</protocol>
<bridge stp="off" delay="0.01">
<interface type="ethernet" name="wlan0">
<mac address="00:1C:BF:04:29:A4"/>
</interface>
</bridge>
</interface>
$ sudo src/ncftool
ncftool> list --all
eth0
lo
wlan0
ncftool> define netcfbridge.xml
Defined interface testbr0
ncftool> list --all
eth0
lo
testbr0
ncftool> dumpxml testbr0
<?xml version="1.0"?>
<interface type="bridge" name="testbr0">
<start mode="none"/>
<mtu size="1500"/>
<protocol family="ipv4">
<dhcp/>
</protocol>
<bridge stp="off" delay="0.01">
<interface type="ethernet" name="wlan0">
<mac address="00:1C:BF:04:29:A4"/>
</interface>
</bridge>
</interface>
ncftool> undefine testbr0
testbr0 undefined
ncftool> list --all
eth0
lo
Maybe netcf could attempt to rebuild ifcfg files for child interfaces
when undefining? Since it is already accessing /sys, it should be
straight forward to build a simple config with at least mac and
interface name.
On an unrelated note, the bridge XML example on the main trac page is
outdated and doesn't match the current XML schema.
Thanks,
Cole
14 years, 4 months
[PATCH] Add required vlan properties to live xml.
by Laine Stump
Grab the vlan id and master interface name during the libnl "link"
cache traversal callback, and add it to the xml for vlans.
This is necessary for the xml to pass libvirt's parsing.
---
src/dutil.c | 127 +++++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 98 insertions(+), 29 deletions(-)
diff --git a/src/dutil.c b/src/dutil.c
index d4eea90..93bb597 100644
--- a/src/dutil.c
+++ b/src/dutil.c
@@ -50,6 +50,9 @@
#include <netlink/cache.h>
#include <netlink/route/addr.h>
#include <netlink/route/link.h>
+/* For some reason, the headers for libnl vlan functions aren't installed */
+extern int rtnl_link_vlan_get_id(struct rtnl_link *link);
+
#include <libxml/parser.h>
#include <libxml/relaxng.h>
@@ -611,6 +614,7 @@ struct nl_callback_data {
xmlNodePtr protov4;
xmlNodePtr protov6;
xmlNodePtr mac;
+ xmlNodePtr vlan;
struct netcf_if *nif;
};
@@ -709,58 +713,123 @@ error:
return;
}
-static void add_mac_cb(struct nl_object *obj, void *arg) {
+static void add_link_info_cb(struct nl_object *obj, void *arg) {
struct nl_callback_data *cb_data = arg;
struct rtnl_link *iflink = (struct rtnl_link *)obj;
struct netcf *ncf = cb_data->nif->ncf;
struct nl_addr *addr;
- char mac_str[64];
+ char *link_type;
xmlNodePtr cur;
xmlAttrPtr prop = NULL;
- if (cb_data->mac != NULL)
- return;
+ /* look for mac address */
+ if ((cb_data->mac == NULL)
+ && ((addr = rtnl_link_get_addr(iflink)) != NULL)
+ && !nl_addr_iszero(addr)) {
- addr = rtnl_link_get_addr(iflink);
- if ((addr == NULL) || nl_addr_iszero(addr))
- return;
+ char mac_str[64];
- nl_addr2str(addr, mac_str, sizeof(mac_str));
+ nl_addr2str(addr, mac_str, sizeof(mac_str));
+
+ for (cur = cb_data->root->children; cur != NULL; cur = cur->next) {
+ if ((cur->type == XML_ELEMENT_NODE) &&
+ xmlStrEqual(cur->name, BAD_CAST "mac")) {
+ cb_data->mac = cur;
+ break;
+ }
+ }
- for (cur = cb_data->root->children; cur != NULL; cur = cur->next) {
- if ((cur->type == XML_ELEMENT_NODE) &&
- xmlStrEqual(cur->name, BAD_CAST "mac")) {
- cb_data->mac = cur;
- break;
+ if (cb_data->mac == NULL) {
+ /* No mac node exists in the document, create a new one.
+ */
+ cb_data->mac = xmlNewDocNode(cb_data->doc, NULL,
+ BAD_CAST "mac", NULL);
+ ERR_NOMEM(cb_data->mac == NULL, ncf);
+
+ cur = xmlAddChild(cb_data->root, cb_data->mac);
+ if (cur == NULL) {
+ xmlFreeNode(cb_data->mac);
+ cb_data->mac = NULL;
+ report_error(ncf, NETCF_ENOMEM, NULL);
+ goto error;
+ }
}
+
+ prop = xmlSetProp(cb_data->mac, BAD_CAST "address", BAD_CAST mac_str);
+ ERR_NOMEM(prop == NULL, ncf);
}
- if (cb_data->mac == NULL) {
- /* No mac node exists in the document, create a new one.
- */
- cb_data->mac = xmlNewDocNode(cb_data->doc, NULL, BAD_CAST "mac", NULL);
- ERR_NOMEM(cb_data->mac == NULL, ncf);
+ /* If this is a vlan link, get the master interface and vlan id.
+ */
+ if ((cb_data->vlan == NULL)
+ && ((link_type = rtnl_link_get_info_type(iflink)) != NULL)
+ && STREQ(link_type, "vlan")) {
+
+ struct rtnl_link *master_link;
+ char *master_name = NULL;
+ int vlan_id = rtnl_link_vlan_get_id(iflink);
+ int l_link = rtnl_link_get_link(iflink);
+
+ if ((l_link != RTNL_LINK_NOT_FOUND)
+ && ((master_link = rtnl_link_get(nl_object_get_cache(obj),
+ l_link)) != NULL)
+ && ((master_name = rtnl_link_get_name(master_link)) != NULL)) {
+
+ char vlan_id_str[16];
+ xmlNodePtr master;
+
+ for (cur = cb_data->root->children; cur != NULL; cur = cur->next) {
+ if ((cur->type == XML_ELEMENT_NODE) &&
+ xmlStrEqual(cur->name, BAD_CAST "vlan")) {
+ cb_data->vlan = cur;
+ break;
+ }
+ }
- cur = xmlAddChild(cb_data->root, cb_data->mac);
- if (cur == NULL) {
- xmlFreeNode(cb_data->mac);
- cb_data->mac = NULL;
- report_error(ncf, NETCF_ENOMEM, NULL);
- goto error;
+ if (cb_data->vlan == NULL) {
+ /* No vlan node exists in the document, create a new one.
+ */
+ cb_data->vlan = xmlNewDocNode(cb_data->doc, NULL,
+ BAD_CAST "vlan", NULL);
+ ERR_NOMEM(cb_data->vlan == NULL, ncf);
+
+ cur = xmlAddChild(cb_data->root, cb_data->vlan);
+ if (cur == NULL) {
+ xmlFreeNode(cb_data->vlan);
+ cb_data->vlan = NULL;
+ report_error(ncf, NETCF_ENOMEM, NULL);
+ goto error;
+ }
+ }
+
+ snprintf(vlan_id_str, sizeof(vlan_id_str), "%d", vlan_id);
+ prop = xmlSetProp(cb_data->vlan, BAD_CAST "tag",
+ BAD_CAST vlan_id_str);
+ ERR_NOMEM(prop == NULL, ncf);
+
+ master = xmlNewDocNode(cb_data->doc, NULL,
+ BAD_CAST "interface", NULL);
+ ERR_NOMEM(master == NULL, ncf);
+ cur = xmlAddChild(cb_data->vlan, master);
+ if (cur == NULL) {
+ xmlFreeNode(master);
+ report_error(ncf, NETCF_ENOMEM, NULL);
+ goto error;
+ }
+ prop = xmlSetProp(master, BAD_CAST "name", BAD_CAST master_name);
+ ERR_NOMEM(prop == NULL, ncf);
}
}
- prop = xmlSetProp(cb_data->mac, BAD_CAST "address", BAD_CAST mac_str);
- ERR_NOMEM(prop == NULL, ncf);
-
error:
return;
}
void add_state_to_xml_doc(struct netcf_if *nif, xmlDocPtr doc) {
- struct nl_callback_data cb_data = { doc, NULL, NULL, NULL, NULL, nif };
+ struct nl_callback_data cb_data
+ = { doc, NULL, NULL, NULL, NULL, NULL, nif };
struct rtnl_addr *filter_addr = NULL;
struct rtnl_link *filter_link = NULL;
int ifindex, code;
@@ -795,7 +864,7 @@ void add_state_to_xml_doc(struct netcf_if *nif, xmlDocPtr doc) {
rtnl_link_set_ifindex(filter_link, ifindex);
nl_cache_foreach_filter(nif->ncf->driver->link_cache,
- OBJ_CAST(filter_link), add_mac_cb,
+ OBJ_CAST(filter_link), add_link_info_cb,
&cb_data);
/* Build an rtnl_addr with the interface name set. This is used by
--
1.6.5.15.gc274d
14 years, 5 months
[PATCH] * src/drv_initscripts.c (drv_close): protect against segfault
by David Lutterkort
It should be legal to pass in a NULL ncf or ncf->driver. Also added a test
that checks we return an error code when ncf_init is called with a bogus
root.
---
src/drv_initscripts.c | 2 ++
tests/test-initscripts.c | 14 ++++++++++++++
2 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/src/drv_initscripts.c b/src/drv_initscripts.c
index 8e082b6..6163035 100644
--- a/src/drv_initscripts.c
+++ b/src/drv_initscripts.c
@@ -508,6 +508,8 @@ int drv_init(struct netcf *ncf) {
}
void drv_close(struct netcf *ncf) {
+ if (ncf == NULL || ncf->driver == NULL)
+ return;
xsltFreeStylesheet(ncf->driver->get);
xsltFreeStylesheet(ncf->driver->put);
xmlRelaxNGFree(ncf->driver->rng);
diff --git a/tests/test-initscripts.c b/tests/test-initscripts.c
index 0f2a887..329bf19 100644
--- a/tests/test-initscripts.c
+++ b/tests/test-initscripts.c
@@ -192,6 +192,19 @@ static void testTransforms(CuTest *tc) {
assert_transforms(tc, "ipv6-static-multi");
}
+static void testCorruptedSetup(CuTest *tc) {
+ int r;
+
+ ncf_close(ncf);
+ ncf = NULL;
+
+ r = ncf_init(&ncf, "/dev/null");
+ CuAssertIntEquals(tc, -1, r);
+ CuAssertPtrNotNull(tc, ncf);
+ r = ncf_error(ncf, NULL, NULL);
+ CuAssertIntEquals(tc, NETCF_EFILE, r);
+}
+
int main(void) {
char *output = NULL;
CuSuite* suite = CuSuiteNew();
@@ -221,6 +234,7 @@ int main(void) {
SUITE_ADD_TEST(suite, testLookupByMAC);
SUITE_ADD_TEST(suite, testDefineUndefine);
SUITE_ADD_TEST(suite, testTransforms);
+ SUITE_ADD_TEST(suite, testCorruptedSetup);
CuSuiteRun(suite);
CuSuiteSummary(suite, &output);
--
1.6.2.5
14 years, 5 months
ANNOUNCE: netcf 0.1.3
by David Lutterkort
I am pleased to announce the release of netcf 0.1.2.
Changes in this release are mostly focused around interrogating live
interfaces. Detailed news:
- The interface.rng schema now allows specifying IPv4 and IPv6 addresses
in any order
- ncf_if_status: new API call
- ncf_if_xml_state: only report information about the live interface, and
none of the information from configuration files; report interface
type; report all addresses assigned to an interface; report MAC address
of an interface
- ncf_list_interfaces, ncf_num_interfaces, ncf_if_xml_state: fix bugs
when dealing with interfaces that are down
- ncf_if_mac_string: do not report error when MAC is not known, simply
return NULL
- use libnl to determine information about live interfaces
Tarball: https://fedorahosted.org/released/netcf/netcf-0.1.3.tar.gz
GPG signature[1]: https://fedorahosted.org/released/netcf/netcf-0.1.3.tar.gz.sig
RPM's for Fedora and EPEL are making their way through the build systems
and will be available shortly from the usual repos.
David
[1] To verify the signature, first download both the .sig file and the
corresponding tarball. Then, run a command like this:
gpg --verify netcf-0.1.3.tar.gz.sig
If that command fails because you don't have the required public key,
then run this command to import it:
gpg --keyserver keys.gnupg.net --recv-keys FC6E8A22
and rerun the `gpg --verify' command.
14 years, 5 months
[PATCH] Implement ncf_if_status()
by Laine Stump
Here's a first draft of a suggested new API, subject to change based
on comments.
ncf_if_status returns various status bits about the given interface. As a
start, only a single bit is defined:
NETCF_IFACE_STATUS_UP
This bit is set if the interface is currently up (active) and not set if it
is currently down (inactive).
The value of all other bits should be considered random by an
application program, as later versions of netcf may use them. In other
words, you should always mask out all the other bits.
---
src/drv_initscripts.c | 16 ++++++++++++++++
src/internal.h | 1 +
src/netcf.c | 8 ++++++++
src/netcf.h | 9 +++++++++
src/netcf_public.syms | 5 +++++
5 files changed, 39 insertions(+), 0 deletions(-)
diff --git a/src/drv_initscripts.c b/src/drv_initscripts.c
index 6d03baa..17fad00 100644
--- a/src/drv_initscripts.c
+++ b/src/drv_initscripts.c
@@ -807,6 +807,22 @@ char *drv_xml_state(struct netcf_if *nif) {
goto done;
}
+/* Report various status info about the interface as bits in
+ * "flags". Returns 0 on success, -1 on failure
+ */
+int drv_if_status(struct netcf_if *nif, ncf_if_status_flags *flags) {
+ int is_active;
+
+ ERR_THROW(flags == NULL, nif->ncf, EOTHER, "NULL pointer for flags in ncf_if_status");
+ *flags = 0;
+ is_active = if_is_active(nif->ncf, nif->name);
+ if (is_active)
+ *flags |= NETCF_IFACE_STATUS_UP;
+ return 0;
+error:
+ return -1;
+}
+
/* Get the content of /interface/@name. Result must be freed with xmlFree()
*
* The name on VLAN interfaces is optional; if there is no
diff --git a/src/internal.h b/src/internal.h
index ca9a0ef..abdc01d 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -180,6 +180,7 @@ 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 *);
+int drv_if_status(struct netcf_if *nif, ncf_if_status_flags *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/netcf.c b/src/netcf.c
index 1cd7aed..3cf045c 100644
--- a/src/netcf.c
+++ b/src/netcf.c
@@ -212,6 +212,14 @@ char *ncf_if_xml_state(struct netcf_if *nif) {
return drv_xml_state(nif);
}
+/* Report various status info about the interface as bits in
+ * "flags". Returns 0 on success, -1 on failure
+ */
+int ncf_if_status(struct netcf_if *nif, ncf_if_status_flags *flags) {
+ API_ENTRY(nif->ncf);
+ return drv_if_status(nif, 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 a8619f5..0e1d4bd 100644
--- a/src/netcf.h
+++ b/src/netcf.h
@@ -163,6 +163,15 @@ char *ncf_if_xml_desc(struct netcf_if *);
*/
char *ncf_if_xml_state(struct netcf_if *);
+typedef enum {
+ NETCF_IFACE_STATUS_UP = 1,
+} ncf_if_status_flags;
+
+/* Report various status info about the interface as bits in
+ * "flags". Returns 0 on success, -1 on failure
+ */
+int ncf_if_status(struct netcf_if *nif, ncf_if_status_flags *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 61464a5..9180614 100644
--- a/src/netcf_public.syms
+++ b/src/netcf_public.syms
@@ -23,3 +23,8 @@ NETCF_1.2.0 {
global:
ncf_if_xml_state;
} NETCF_1.0.0;
+
+NETCF_1.3.0 {
+ global:
+ ncf_if_status;
+} NETCF_1.2.0;
--
1.6.5.15.gc274d
14 years, 5 months
[PATCH] Report actual mac address in ncf_if_xml_state.
by Laine Stump
Iterate the NETLINK link cache to find the entry for each interface,
extract the mac address, and add it to the XML.
---
src/dutil.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 66 insertions(+), 1 deletions(-)
diff --git a/src/dutil.c b/src/dutil.c
index 1fc6097..a010d27 100644
--- a/src/dutil.c
+++ b/src/dutil.c
@@ -610,6 +610,7 @@ struct nl_callback_data {
xmlNodePtr root;
xmlNodePtr protov4;
xmlNodePtr protov6;
+ xmlNodePtr mac;
struct netcf_if *nif;
};
@@ -708,10 +709,60 @@ error:
return;
}
+static void _add_mac_cb(struct nl_object *obj, void *arg) {
+ struct nl_callback_data *cb_data = arg;
+ struct rtnl_link *iflink = (struct rtnl_link *)obj;
+ struct netcf *ncf = cb_data->nif->ncf;
+
+ struct nl_addr *addr;
+ char mac_str[64];
+ xmlNodePtr cur;
+ xmlAttrPtr prop = NULL;
+
+ if (cb_data->mac != NULL)
+ return;
+
+ addr = rtnl_link_get_addr(iflink);
+ if ((addr == NULL) || nl_addr_iszero(addr))
+ return;
+
+ nl_addr2str(addr, mac_str, sizeof(mac_str));
+
+ for (cur = cb_data->root->children; cur != NULL; cur = cur->next) {
+ if ((cur->type == XML_ELEMENT_NODE) &&
+ xmlStrEqual(cur->name, BAD_CAST "mac")) {
+ cb_data->mac = cur;
+ break;
+ }
+ }
+
+ if (cb_data->mac == NULL) {
+ /* No mac node exists in the document, create a new one.
+ */
+ cb_data->mac = xmlNewDocNode(cb_data->doc, NULL, BAD_CAST "mac", NULL);
+ ERR_NOMEM(cb_data->mac == NULL, ncf);
+
+ cur = xmlAddChild(cb_data->root, cb_data->mac);
+ if (cur == NULL) {
+ xmlFreeNode(cb_data->mac);
+ cb_data->mac = NULL;
+ report_error(ncf, NETCF_ENOMEM, NULL);
+ goto error;
+ }
+ }
+
+ prop = xmlSetProp(cb_data->mac, BAD_CAST "address", BAD_CAST mac_str);
+ ERR_NOMEM(prop == NULL, ncf);
+
+error:
+ return;
+}
+
void add_state_to_xml_doc(struct netcf_if *nif, xmlDocPtr doc) {
- struct nl_callback_data cb_data = { doc, NULL, NULL, NULL, nif };
+ struct nl_callback_data cb_data = { doc, NULL, NULL, NULL, NULL, nif };
struct rtnl_addr *filter_addr = NULL;
+ struct rtnl_link *filter_link = NULL;
int ifindex, code;
cb_data.root = xmlDocGetRootElement(doc);
@@ -735,6 +786,18 @@ void add_state_to_xml_doc(struct netcf_if *nif, xmlDocPtr doc) {
ERR_THROW((ifindex == RTNL_LINK_NOT_FOUND), nif->ncf, ENETLINK,
"Could find ifindex for interface `%s`", nif->name);
+ /* Build an rtnl_link with the interface index set, and use it to
+ * find the entry for this interface and extract the mac
+ * address.
+ */
+ filter_link = rtnl_link_alloc();
+ ERR_NOMEM((filter_link == NULL), nif->ncf);
+
+ rtnl_link_set_ifindex(filter_link, ifindex);
+ nl_cache_foreach_filter(nif->ncf->driver->link_cache,
+ OBJ_CAST(filter_link), _add_mac_cb,
+ &cb_data);
+
/* Build an rtnl_addr with the interface name set. This is used by
* the iterator to filter the contents of the address cache.
*/
@@ -749,6 +812,8 @@ void add_state_to_xml_doc(struct netcf_if *nif, xmlDocPtr doc) {
error:
if (filter_addr)
rtnl_addr_put(filter_addr);
+ if (filter_link)
+ rtnl_link_put(filter_link);
return;
}
--
1.6.5.15.gc274d
14 years, 5 months
[PATCH 0-3] Use NETLINK for for interface IP addresses
by Laine Stump
(I had sent this last night, don't know why it didn't get through).
These patches add a dependency on libnl (a helper library for the
NETLINK socket and API), change the code over to use NETLINK (rather
than ioctl(SIOCGIFADDR) to retrieve interface IP addresses, and
finally remove the old deprecated function (done in a separate patch
to force the diffs into something easy to understand).
14 years, 5 months
Re: [netcf-devel] [PATCH 0-3] Use NETLINK for for interface IP addresses
by David Lutterkort
On Thu, 2009-10-22 at 12:48 -0400, Laine Stump wrote:
> On 10/22/2009 12:34 PM, David Lutterkort wrote:
> > On Thu, 2009-10-22 at 09:43 -0400, Laine Stump wrote:
> >
> >> (I had sent this last night, don't know why it didn't get through).
> >>
> >> These patches add a dependency on libnl (a helper library for the
> >> NETLINK socket and API), change the code over to use NETLINK (rather
> >> than ioctl(SIOCGIFADDR) to retrieve interface IP addresses, and
> >> finally remove the old deprecated function (done in a separate patch
> >> to force the diffs into something easy to understand).
> >>
> > When I try to build with these patches, I get
> >
> > CC dutil_linux.lo
> > cc1: warnings being treated as errors
> > /usr/include/netlink/object.h:58: error: inline function 'nl_object_priv' declared but never defined
> >
> > Is there a newer libnl that cleans up this nonsense ? I have libnl-devel-1.1-6.fc11.x86_64
> >
>
> No, there unfortunately isn't. That warning is caused by really odd code
> - the function in question is only defined in object.c, so I'm unclear
> on how its use elsewhere is actually accomplished.
>
> I dislike having any warnings during the builds too, but am not sure
> what can be done about it in this case (other than defining our own
> nl_object_priv in each file that ends up #including netlink/object.h)
I generally configure with '--enable-compile-warnings=error' which makes
this fatal. Just filed bz 530410 to track that - for the time being,
I'll have to build without -Werror.
David
14 years, 5 months
null MAC address
by Laine Stump
In many cases there is no MAC address in the xml definition for an
interface. When this is the case, ncf_if_mac_string returns NULL, as
well as throwing an error. Should this really be what it does? Perhaps
it should return "", or at least not throw the error?
This is causing an error log message in libvirt when, for example, I
define a bridge interface, then do an iface-list (which ends up
eventually calling ncf_if_mac_string() on the interface with no mac
address). I'm trying to decide whether to fix this in netcf, or in libvirt.
14 years, 5 months