From e81814a29fb4a43035112e318cdcc8fb85a28cc8 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Fri, 15 Apr 2011 15:30:46 +0200 Subject: Support for rtnl_link_add() API for adding virtual links --- lib/route/link.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/lib/route/link.c b/lib/route/link.c index 3c5b219..9dfa5e1 100644 --- a/lib/route/link.c +++ b/lib/route/link.c @@ -303,7 +303,8 @@ static void release_link_info(struct rtnl_link *link) struct rtnl_link_info_ops *io = link->l_info_ops; if (io != NULL) { - io->io_free(link); + if (io->io_free) + io->io_free(link); rtnl_link_info_ops_put(io); link->l_info_ops = NULL; } @@ -599,7 +600,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, kind = nla_get_string(li[IFLA_INFO_KIND]); ops = rtnl_link_info_ops_lookup(kind); - if (ops != NULL) { + if (ops && ops->io_parse) { link->l_info_ops = ops; err = ops->io_parse(link, li[IFLA_INFO_DATA], li[IFLA_INFO_XSTATS]); @@ -1071,8 +1072,7 @@ static int build_link_msg(int cmd, struct ifinfomsg *hdr, if (link->ce_mask & LINK_ATTR_IFALIAS) NLA_PUT_STRING(msg, IFLA_IFALIAS, link->l_ifalias); - if ((link->ce_mask & LINK_ATTR_LINKINFO) && link->l_info_ops && - link->l_info_ops->io_put_attrs) { + if ((link->ce_mask & LINK_ATTR_LINKINFO) && link->l_info_ops) { struct nlattr *info; if (!(info = nla_nest_start(msg, IFLA_LINKINFO))) @@ -1080,7 +1080,8 @@ static int build_link_msg(int cmd, struct ifinfomsg *hdr, NLA_PUT_STRING(msg, IFLA_INFO_KIND, link->l_info_ops->io_name); - if (link->l_info_ops->io_put_attrs(msg, link) < 0) + if (link->l_info_ops->io_put_attrs && + link->l_info_ops->io_put_attrs(msg, link) < 0) goto nla_put_failure; nla_nest_end(msg, info); @@ -1102,6 +1103,71 @@ nla_put_failure: return -NLE_MSGSIZE; } +/** + * Build a netlink message requesting the addition of a new virtual link + * @arg link new link to add + * @arg flags additional netlink message flags + * @arg result pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_link_add() with + * the exception that it will not send the message but return it in the + * provided return pointer instead. + * + * @see rtnl_link_add() + * + * @note This operation is not supported on all kernel versions. + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_build_add_request(struct rtnl_link *link, int flags, + struct nl_msg **result) +{ + struct ifinfomsg ifi = { + .ifi_family = link->l_family, + .ifi_index = link->l_index, + .ifi_flags = link->l_flags, + }; + + return build_link_msg(RTM_NEWLINK, &ifi, link, flags, result); +} + +/** + * Add virtual link + * @arg sk netlink socket. + * @arg link new link to add + * @arg flags additional netlink message flags + * + * Builds a \c RTM_NEWLINK netlink message requesting the addition of + * a new virtual link. + * + * After sending, the function will wait for the ACK or an eventual + * error message to be received and will therefore block until the + * operation has been completed. + * + * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause + * this function to return immediately after sending. In this case, + * it is the responsibility of the caller to handle any error + * messages returned. + * + * @return 0 on success or a negative error code. + */ +int rtnl_link_add(struct nl_sock *sk, struct rtnl_link *link, int flags) +{ + struct nl_msg *msg; + int err; + + err = rtnl_link_build_add_request(link, flags, &msg); + if (err < 0) + return err; + + err = nl_send_auto_complete(sk, msg); + nlmsg_free(msg); + if (err < 0) + return err; + + return wait_for_ack(sk); +} + /** * Build a netlink message requesting the modification of a link * @arg orig original link to change @@ -1928,9 +1994,10 @@ int rtnl_link_set_info_type(struct rtnl_link *link, const char *type) if (link->l_info_ops) release_link_info(link); - if ((err = io->io_alloc(link)) < 0) + if (io->io_alloc && (err = io->io_alloc(link)) < 0) return err; + link->ce_mask |= LINK_ATTR_LINKINFO; link->l_info_ops = io; return 0; -- cgit v1.2.1