The functionality to translate VLAN interfaces to mesh interfaces and VID is using NETLINK_ROUTE like the query_rtnl_link_single helper function. Only minimal changes are required to also provide the link to the underlying device and the VID.
Signed-off-by: Sven Eckelmann sven@narfation.org --- functions.c | 229 ++++++++++++++++------------------------------------ 1 file changed, 71 insertions(+), 158 deletions(-)
diff --git a/functions.c b/functions.c index b52db08..bb7f517 100644 --- a/functions.c +++ b/functions.c @@ -760,149 +760,6 @@ struct ether_addr *resolve_mac(const char *asc) return mac_result; }
-struct vlan_get_link_nl_arg { - char *iface; - int vid; -}; - -static struct nla_policy info_data_link_policy[IFLA_MAX + 1] = { - [IFLA_LINKINFO] = { .type = NLA_NESTED }, - [IFLA_LINK] = { .type = NLA_U32 }, -}; - -static struct nla_policy info_data_link_info_policy[IFLA_INFO_MAX + 1] = { - [IFLA_INFO_DATA] = { .type = NLA_NESTED }, -}; - -static struct nla_policy vlan_policy[IFLA_VLAN_MAX + 1] = { - [IFLA_VLAN_ID] = { .type = NLA_U16 }, -}; - -/** - * vlan_get_link_parse - parse a get_link rtnl message and extract the important - * data - * @msg: the reply msg - * @arg: pointer to the buffer which will store the return values - * - * Saves the vid in arg::vid in case of success or -1 otherwise - */ -static int vlan_get_link_parse(struct nl_msg *msg, void *arg) -{ - struct vlan_get_link_nl_arg *nl_arg = arg; - struct nlmsghdr *n = nlmsg_hdr(msg); - struct nlattr *tb[IFLA_MAX + 1]; - struct nlattr *li[IFLA_INFO_MAX + 1]; - struct nlattr *vi[IFLA_VLAN_MAX + 1]; - int ret; - int idx; - - if (!nlmsg_valid_hdr(n, sizeof(struct ifinfomsg))) - return -NLE_MSG_TOOSHORT; - - ret = nlmsg_parse(n, sizeof(struct ifinfomsg), tb, IFLA_MAX, - info_data_link_policy); - if (ret < 0) - return ret; - - if (!tb[IFLA_LINK]) - return -NLE_MISSING_ATTR; - - /* parse subattributes linkinfo */ - if (!tb[IFLA_LINKINFO]) - return -NLE_MISSING_ATTR; - - ret = nla_parse_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], - info_data_link_info_policy); - if (ret < 0) - return ret; - - if (!li[IFLA_INFO_KIND]) - return -NLE_MISSING_ATTR; - - if (strcmp(nla_data(li[IFLA_INFO_KIND]), "vlan") != 0) - goto err; - - /* parse subattributes info_data for vlan */ - if (!li[IFLA_INFO_DATA]) - return -NLE_MISSING_ATTR; - - ret = nla_parse_nested(vi, IFLA_VLAN_MAX, li[IFLA_INFO_DATA], - vlan_policy); - if (ret < 0) - return ret; - - if (!vi[IFLA_VLAN_ID]) - return -NLE_MISSING_ATTR; - - /* get parent link name */ - idx = *(int *)nla_data(tb[IFLA_LINK]); - - if (!if_indextoname(idx, nl_arg->iface)) - goto err; - - /* get the corresponding vid */ - nl_arg->vid = *(int *)nla_data(vi[IFLA_VLAN_ID]); - -err: - if (nl_arg->vid >= 0) - return NL_STOP; - else - return NL_OK; -} - -/** - * vlan_get_link - convert a VLAN interface into its parent one - * @ifname: the interface to convert - * @parent: buffer where the parent interface name will be written - * (minimum IF_NAMESIZE) - * - * Returns the vlan identifier on success or -1 on error - */ -static int vlan_get_link(const char *ifname, char *parent) -{ - struct nl_sock *sock; - int ret; - struct ifinfomsg ifinfo = { - .ifi_family = AF_UNSPEC, - .ifi_index = if_nametoindex(ifname), - }; - struct nl_cb *cb = NULL; - struct vlan_get_link_nl_arg arg = { - .iface = parent, - .vid = -1, - }; - - sock = nl_socket_alloc(); - if (!sock) - goto err; - - ret = nl_connect(sock, NETLINK_ROUTE); - if (ret < 0) - goto err; - - ret = nl_send_simple(sock, RTM_GETLINK, NLM_F_REQUEST, - &ifinfo, sizeof(ifinfo)); - if (ret < 0) - goto err; - - cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!cb) - goto err; - - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, vlan_get_link_parse, &arg); - ret = nl_recvmsgs(sock, cb); - if (ret < 0) - goto err; - -err: - if (cb) - nl_cb_put(cb); - if (sock) - nl_socket_free(sock); - - return arg.vid; -} - int query_rtnl_link(int ifindex, nl_recvmsg_msg_cb_t func, void *arg) { struct ifinfomsg rt_hdr = { @@ -1025,25 +882,15 @@ int netlink_simple_request(struct nl_msg *msg) return err; }
-int translate_mesh_iface(struct state *state) -{ - state->vid = vlan_get_link(state->arg_iface, state->mesh_iface); - if (state->vid < 0) { - /* if there is no iface then the argument must be the - * mesh interface - */ - snprintf(state->mesh_iface, sizeof(state->mesh_iface), "%s", - state->arg_iface); - } - - return 0; -} - struct rtnl_link_iface_data { uint8_t kind_found:1; uint8_t master_found:1; + uint8_t link_found:1; + uint8_t vid_found:1; char kind[IF_NAMESIZE]; unsigned int master; + unsigned int link; + uint16_t vid; };
static int query_rtnl_link_single_parse(struct nl_msg *msg, void *arg) @@ -1051,13 +898,19 @@ static int query_rtnl_link_single_parse(struct nl_msg *msg, void *arg) static struct nla_policy link_policy[IFLA_MAX + 1] = { [IFLA_LINKINFO] = { .type = NLA_NESTED }, [IFLA_MASTER] = { .type = NLA_U32 }, + [IFLA_LINK] = { .type = NLA_U32 }, }; static struct nla_policy link_info_policy[IFLA_INFO_MAX + 1] = { [IFLA_INFO_KIND] = { .type = NLA_STRING }, + [IFLA_INFO_DATA] = { .type = NLA_NESTED }, + }; + static struct nla_policy vlan_policy[IFLA_VLAN_MAX + 1] = { + [IFLA_VLAN_ID] = { .type = NLA_U16 }, };
struct rtnl_link_iface_data *link_data = arg; struct nlattr *li[IFLA_INFO_MAX + 1]; + struct nlattr *vi[IFLA_VLAN_MAX + 1]; struct nlmsghdr *n = nlmsg_hdr(msg); struct nlattr *tb[IFLA_MAX + 1]; char *type; @@ -1076,6 +929,11 @@ static int query_rtnl_link_single_parse(struct nl_msg *msg, void *arg) link_data->master_found = true; }
+ if (tb[IFLA_LINK]) { + link_data->link = nla_get_u32(tb[IFLA_LINK]); + link_data->link_found = true; + } + /* parse subattributes linkinfo */ if (!tb[IFLA_LINKINFO]) return NL_OK; @@ -1093,6 +951,19 @@ static int query_rtnl_link_single_parse(struct nl_msg *msg, void *arg) link_data->kind_found = true; }
+ if (!li[IFLA_INFO_DATA]) + return NL_OK; + + ret = nla_parse_nested(vi, IFLA_VLAN_MAX, li[IFLA_INFO_DATA], + vlan_policy); + if (ret < 0) + return NL_OK; + + if (vi[IFLA_VLAN_ID]) { + link_data->vid = nla_get_u16(vi[IFLA_VLAN_ID]); + link_data->vid_found = true; + } + return NL_STOP; }
@@ -1109,6 +980,8 @@ static int query_rtnl_link_single(int mesh_ifindex,
link_data->kind_found = false; link_data->master_found = false; + link_data->link_found = false; + link_data->vid_found = false;
sock = nl_socket_alloc(); if (!sock) @@ -1138,7 +1011,47 @@ static int query_rtnl_link_single(int mesh_ifindex, return 0; }
-int check_mesh_iface_netlink(struct state *state) +int translate_mesh_iface(struct state *state) +{ + struct rtnl_link_iface_data link_data; + unsigned int arg_ifindex; + + arg_ifindex = if_nametoindex(state->arg_iface); + if (arg_ifindex == 0) + goto fallback_meshif; + + query_rtnl_link_single(arg_ifindex, &link_data); + if (!link_data.vid_found) + goto fallback_meshif; + + if (!link_data.link_found) + goto fallback_meshif; + + if (!link_data.kind_found) + goto fallback_meshif; + + if (strcmp(link_data.kind, "vlan") != 0) + goto fallback_meshif; + + if (!if_indextoname(link_data.link, state->mesh_iface)) + goto fallback_meshif; + + state->vid = link_data.vid; + + return 0; + +fallback_meshif: + /* if there is no vid then the argument must be the + * mesh interface + */ + snprintf(state->mesh_iface, sizeof(state->mesh_iface), "%s", + state->arg_iface); + state->vid = -1; + + return 0; +} + +static int check_mesh_iface_netlink(struct state *state) { struct rtnl_link_iface_data link_data;