[netcf-devel] [PATCH 2/3] Use netlink to get interface IP addresses.

David Lutterkort lutter at redhat.com
Thu Oct 22 16:49:18 UTC 2009


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.

> +    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)

David





More information about the netcf-devel mailing list