[netcf-devel] [PATCH 2/3] Use netlink to get interface IP addresses.
Laine Stump
laine at laine.org
Thu Oct 22 17:13:04 UTC 2009
On 10/22/2009 12:49 PM, David Lutterkort wrote:
> On Thu, 2009-10-22 at 09:43 -0400, Laine Stump wrote:
>
>> While the SIOCGIFADDR ioctl can only get the first IPv4 address on an
>> interface, netlink reports all addresses, both IPv4 and IPv6 on the
>> interface.
>>
> A couple of issues:
>
>
>> diff --git a/src/dutil.c b/src/dutil.c
>> index 9ae80bf..d12d656 100644
>> --- a/src/dutil.c
>> +++ b/src/dutil.c
>> @@ -685,6 +735,155 @@ error:
>> return;
>> }
>>
>> +/* Data that needs to be preserved between calls to the libnl iterator
>> + * callback.
>> + */
>> +struct nl_callback_data {
>> + xmlDocPtr doc;
>> + xmlNodePtr root;
>> + xmlNodePtr protov4;
>> + xmlNodePtr protov6;
>> + struct netcf_if *nif;
>> +};
>> +
>> +/* add all ip addresses for the given interface to the xml document
>> +*/
>> +static void _add_ips_cb(struct nl_object *obj, void *arg) {
>> + struct nl_callback_data *cb_data = arg;
>> + struct rtnl_addr *addr = (struct rtnl_addr *)obj;
>> + struct netcf *ncf = cb_data->nif->ncf;
>> +
>> + struct nl_addr *local_addr;
>> + int family, prefix;
>> + const char *family_str;
>> + char ip_str[48];
>> + char prefix_str[16];
>> + xmlNodePtr *proto, ip_node, cur;
>> + xmlAttrPtr prop = NULL;
>> +
>> + local_addr = rtnl_addr_get_local(addr);
>> + family = nl_addr_get_family(local_addr);
>> + switch (family) {
>> + case AF_INET:
>> + family_str = "ipv4";
>> + proto =&cb_data->protov4;
>> + break;
>> + case AF_INET6:
>> + family_str = "ipv6";
>> + proto =&cb_data->protov6;
>> + break;
>> +
>> + default:
>> + /* Nothing that interests us in this entry */
>> + return;
>> + }
>> +
>> + inet_ntop(family, nl_addr_get_binary_addr(local_addr),
>> + ip_str, sizeof(ip_str));
>> + prefix = nl_addr_get_prefixlen(local_addr);
>> +
>> + if (*proto == NULL) {
>> + /* We haven't dont anything with this proto yet. Search for an
>> + * existing node.
>> + */
>> + for (cur = cb_data->root->children; cur != NULL; cur = cur->next) {
>> + if ((cur->type == XML_ELEMENT_NODE)&&
>> + xmlStrEqual(cur->name, BAD_CAST "protocol")) {
>> + xmlChar *node_family = xmlGetProp(cur, BAD_CAST "family");
>> + if (node_family != NULL) {
>> + if (xmlStrEqual(node_family, BAD_CAST family_str))
>> + *proto = cur;
>> + xmlFree(node_family);
>> + if (*proto != NULL) {
>> + break;
>> + }
>> + }
>> + }
>> + }
>> + }
>> +
>> + if (*proto == NULL) {
>> + /* No node exists for this protocol family. Create one.
>> + */
>> + *proto = xmlNewDocNode(cb_data->doc, NULL, BAD_CAST "protocol", NULL);
>> + ERR_NOMEM(*proto == NULL, ncf);
>> +
>> + cur = xmlAddChild(cb_data->root, *proto);
>> + if (cur == NULL) {
>> + xmlFreeNode(*proto);
>> + *proto = NULL;
>> + report_error(ncf, NETCF_ENOMEM, NULL);
>> + goto error;
>> + }
>> + prop = xmlSetProp(*proto, BAD_CAST "family", BAD_CAST family_str);
>> + ERR_NOMEM(prop == NULL, ncf);
>> +
>> + }
>> +
>> + /* Create a new ip node for this address/prefix, and set the
>> + * properties
>> + */
>> + ip_node = xmlNewDocNode(cb_data->doc, NULL, BAD_CAST "ip", NULL);
>> + ERR_NOMEM((ip_node == NULL), ncf);
>> + cur = xmlAddChild(*proto, ip_node);
>> + if (cur == NULL) {
>> + xmlFreeNode(ip_node);
>> + report_error(ncf, NETCF_ENOMEM, NULL);
>> + goto error;
>> + }
>> + prop = xmlSetProp(ip_node, BAD_CAST "address", BAD_CAST ip_str);
>> + ERR_NOMEM((prop == NULL), ncf);
>> + snprintf(prefix_str, sizeof(prefix_str), "%d", prefix);
>> + prop = xmlSetProp(ip_node, BAD_CAST "prefix", BAD_CAST prefix_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 rtnl_addr *filter_addr = NULL;
>> + int ifindex, code;
>> +
>> + cb_data.root = xmlDocGetRootElement(doc);
>> + ERR_THROW((cb_data.root == NULL), nif->ncf, EINTERNAL,
>> + "failed to get document root element");
>> + ERR_THROW(!xmlStrEqual(cb_data.root->name, BAD_CAST "interface"),
>> + nif->ncf, EINTERNAL, "root document is not an interface");
>> +
>> + /* Build an rtnl_addr with the interface name set. This is used by
>> + * the iterator to filter the contents of the address cache.
>> + */
>> + filter_addr = rtnl_addr_alloc();
>> + ERR_NOMEM((filter_addr == NULL), nif->ncf);
>> +
>> + code = nl_cache_refill(nif->ncf->driver->nl_sock,
>> + nif->ncf->driver->link_cache);
>> + ERR_THROW((code< 0), nif->ncf, ENETLINK,
>> + "failed to refill interface index cache");
>> + code = nl_cache_refill(nif->ncf->driver->nl_sock,
>> + nif->ncf->driver->addr_cache);
>> + ERR_THROW((code< 0), nif->ncf, ENETLINK,
>> + "failed to refill interface address cache");
>> +
>> + ifindex = rtnl_link_name2i(nif->ncf->driver->link_cache, nif->name);
>> + ERR_THROW((ifindex == RTNL_LINK_NOT_FOUND), nif->ncf, ENETLINK,
>> + "Could find ifindex for interface `%s`", nif->name);
>> + rtnl_addr_set_ifindex(filter_addr, ifindex);
>> +
>> +printf("found index %d for %s\n", ifindex, nif->name);
>>
> That needs to go.
>
Oops! I thought I'd nuked all of those...
>
>> + nl_cache_foreach_filter(nif->ncf->driver->addr_cache,
>> + OBJ_CAST(filter_addr), _add_ips_cb,
>> +&cb_data);
>> +error:
>> + if (filter_addr)
>> + rtnl_addr_put(filter_addr);
>> + return;
>> +}
>> +
>> /*
>> * Bringing interfaces up/down
>> */
>> diff --git a/src/netcf.h b/src/netcf.h
>> index 4219cc1..a8619f5 100644
>> --- a/src/netcf.h
>> +++ b/src/netcf.h
>> @@ -52,7 +52,8 @@ typedef enum {
>> * used by other data structures */
>> NETCF_EXSLTFAILED, /* XSLT transformation failed */
>> NETCF_EFILE, /* Some file access failed */
>> - NETCF_EIOCTL /* An ioctl call failed */
>> + NETCF_EIOCTL, /* An ioctl call failed */
>> + NETCF_ENETLINK /* something related to the netlink socket failed */
>> } netcf_errcode_t;
>>
> When you add an entry here, also add a corresponding message to errmsgs
> in netcf.c (which I think we also forgot for NETCF_EIOCTL)
>
Okay, I didn't know about that. I'll add in a message for EIOCTL in a
separate patch (which I'll shove into the middle of the series. Isn't
git just the greatest thing since beer on tap?)
More information about the netcf-devel
mailing list