[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