From patchwork Mon Jun 27 16:54:30 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 9200925 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 857FF607D3 for ; Mon, 27 Jun 2016 16:55:19 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7463328581 for ; Mon, 27 Jun 2016 16:55:19 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 66F2B285A1; Mon, 27 Jun 2016 16:55:19 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 3960028581 for ; Mon, 27 Jun 2016 16:55:18 +0000 (UTC) Received: from localhost ([::1]:59981 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bHZob-0005SV-Ek for patchwork-qemu-devel@patchwork.kernel.org; Mon, 27 Jun 2016 12:55:17 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52834) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bHZoF-0005RB-38 for qemu-devel@nongnu.org; Mon, 27 Jun 2016 12:54:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bHZoB-0002UT-Qk for qemu-devel@nongnu.org; Mon, 27 Jun 2016 12:54:55 -0400 Received: from mout.kundenserver.de ([212.227.126.135]:60345) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bHZoB-0002UM-G4 for qemu-devel@nongnu.org; Mon, 27 Jun 2016 12:54:51 -0400 Received: from Quad.localdomain ([78.238.229.36]) by mrelayeu.kundenserver.de (mreue005) with ESMTPSA (Nemesis) id 0Lapqe-1bkL3i0niy-00kPyg; Mon, 27 Jun 2016 18:54:42 +0200 From: Laurent Vivier To: Riku Voipio Date: Mon, 27 Jun 2016 18:54:30 +0200 Message-Id: <1467046470-19713-1-git-send-email-laurent@vivier.eu> X-Mailer: git-send-email 2.5.5 X-Provags-ID: V03:K0:pBDwv0USSzcXPg268BdR0KV3sreMnzW9sG4pL9aU7lAnhXx/6t3 lwwFUnv8FV7o+JSh/dnV5acsf1sMG4STRtBMGWm++f6kiAO+VNo8yFAo1bNHLoB0w6B1vZm U8rop/K6L84aRnNkO2PC+KLOi2JcgzGuZygZnEuMqfYL/WOgkmsWfskiOA6TcVeQr90H44N qJB6elWkX2bloG5qbIzZw== X-UI-Out-Filterresults: notjunk:1; V01:K0:x00t8j/PcA4=:rB6Jb6wJZsFlqb6g5QlO2r 25xarBrsc2TR5Lh5rfF6HTCXt8p+5DRwJap8pcQ75Muy3qy3DFRXs9xR99+PJvB3a+bWu4NEk Q//h1b/9Q1hB54o660sFGiAKIz3WKFo/qDWm6Lklx+1RJe8rlOl//nm7QxhhVJiCnaO8UgFR0 f/uRQutRI7jMBrh9ndbVcvfhYAIwMmxmKx16VmGHaVUuf2eBzjJqV3w01eoTvty3YjT26MLv3 zxrDxqvYe0BCdm28lsV5vnFRMk3dNbezQa6kGHViOLRxY5rqkAhkRes4zi5/lSlrjQwogMZkI 0zlsB67ruK9Hl95uOVAupVOv5qPPKoendgOdnJZ0kqnwpbF8gUvNtVsHFL7xbPg+eoEjwP3F1 vDAVgqFLTgbeX/Td67jFi5Q70NWGUaOmYQzSj/5WOrg5sEI01qbTh3fY+ljROSYomO2hIMXY7 G1jYSGum+dX6IhJ4Q7xAItXUZ2rpwc2pKmbLZZZMi0WlD+QCeD3TqsUaRnVsZJNwxSFj3PckC F5X5xWPyEixv8M2G+3cVAlR1c7DjlYfh8neArUtGAxVkU5UXz7LIETUTxK8Vc/NU2i48ajlz4 JSqJiPAHathFAuJFaD3e3gIYtOvcmfAeJwZbBr0bSXR0Q3kQWM8Mk73a/0+EtGStS11UtGJOH T0cxVqlLEK2fgbUF9zufIvmWykBYAl//n0gl/eCNpYzxrRk2JGWwkIxGLr4NGxSBSeAY= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 212.227.126.135 Subject: [Qemu-devel] [PATCH] linux-user: add nested netlink types X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: qemu-devel@nongnu.org, Laurent Vivier Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Nested types are used by the kernel to send link information and protocol properties. We can see following errors with "ip link show": Unimplemented nested type 26 Unimplemented nested type 26 Unimplemented nested type 18 Unimplemented nested type 26 Unimplemented nested type 18 Unimplemented nested type 26 This patch implements nested types 18 (IFLA_LINKINFO) and 26 (IFLA_AF_SPEC). Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 316 insertions(+), 4 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b6b7917..4385dbf 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -104,6 +104,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #ifdef CONFIG_RTNETLINK #include +#include #endif #include #include "linux_loop.h" @@ -1707,6 +1708,33 @@ static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh, } #ifdef CONFIG_RTNETLINK +static abi_long host_to_target_for_each_nlattr(struct nlattr *nlattr, + size_t len, void *context, + abi_long (*host_to_target_nlattr) + (struct nlattr *, + void *context)) +{ + unsigned short nla_len; + abi_long ret; + + while (len > sizeof(struct nlattr)) { + nla_len = nlattr->nla_len; + if (nla_len < sizeof(struct nlattr) || + nla_len > len) { + break; + } + ret = host_to_target_nlattr(nlattr, context); + nlattr->nla_len = tswap16(nlattr->nla_len); + nlattr->nla_type = tswap16(nlattr->nla_type); + if (ret < 0) { + return ret; + } + len -= NLA_ALIGN(nla_len); + nlattr = (struct nlattr *)(((char *)nlattr) + NLA_ALIGN(nla_len)); + } + return 0; +} + static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr, size_t len, abi_long (*host_to_target_rtattr) @@ -1733,12 +1761,292 @@ static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr, return 0; } +#define NLA_DATA(nla) ((void *)((char *)(nla)) + NLA_HDRLEN) + +static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr, + void *context) +{ + uint16_t *u16; + uint32_t *u32; + uint64_t *u64; + + switch (nlattr->nla_type) { + /* no data */ + case IFLA_BR_FDB_FLUSH: + break; + /* binary */ + case IFLA_BR_GROUP_ADDR: + break; + /* uint8_t */ + case IFLA_BR_VLAN_FILTERING: + case IFLA_BR_TOPOLOGY_CHANGE: + case IFLA_BR_TOPOLOGY_CHANGE_DETECTED: + case IFLA_BR_MCAST_ROUTER: + case IFLA_BR_MCAST_SNOOPING: + case IFLA_BR_MCAST_QUERY_USE_IFADDR: + case IFLA_BR_MCAST_QUERIER: + case IFLA_BR_NF_CALL_IPTABLES: + case IFLA_BR_NF_CALL_IP6TABLES: + case IFLA_BR_NF_CALL_ARPTABLES: + break; + /* uint16_t */ + case IFLA_BR_PRIORITY: + case IFLA_BR_VLAN_PROTOCOL: + case IFLA_BR_GROUP_FWD_MASK: + case IFLA_BR_ROOT_PORT: + case IFLA_BR_VLAN_DEFAULT_PVID: + u16 = NLA_DATA(nlattr); + *u16 = tswap16(*u16); + break; + /* uint32_t */ + case IFLA_BR_FORWARD_DELAY: + case IFLA_BR_HELLO_TIME: + case IFLA_BR_MAX_AGE: + case IFLA_BR_AGEING_TIME: + case IFLA_BR_STP_STATE: + case IFLA_BR_ROOT_PATH_COST: + case IFLA_BR_MCAST_HASH_ELASTICITY: + case IFLA_BR_MCAST_HASH_MAX: + case IFLA_BR_MCAST_LAST_MEMBER_CNT: + case IFLA_BR_MCAST_STARTUP_QUERY_CNT: + u32 = NLA_DATA(nlattr); + *u32 = tswap32(*u32); + break; + /* uint64_t */ + case IFLA_BR_HELLO_TIMER: + case IFLA_BR_TCN_TIMER: + case IFLA_BR_GC_TIMER: + case IFLA_BR_TOPOLOGY_CHANGE_TIMER: + case IFLA_BR_MCAST_LAST_MEMBER_INTVL: + case IFLA_BR_MCAST_MEMBERSHIP_INTVL: + case IFLA_BR_MCAST_QUERIER_INTVL: + case IFLA_BR_MCAST_QUERY_INTVL: + case IFLA_BR_MCAST_QUERY_RESPONSE_INTVL: + case IFLA_BR_MCAST_STARTUP_QUERY_INTVL: + u64 = NLA_DATA(nlattr); + *u64 = tswap64(*u64); + break; + /* ifla_bridge_id: uin8_t[] */ + case IFLA_BR_ROOT_ID: + case IFLA_BR_BRIDGE_ID: + break; + default: + gemu_log("Unknown IFLA_BR type %d\n", nlattr->nla_type); + break; + } + return 0; +} + +static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr, + void *context) +{ + uint16_t *u16; + uint32_t *u32; + uint64_t *u64; + + switch (nlattr->nla_type) { + /* uint8_t */ + case IFLA_BRPORT_STATE: + case IFLA_BRPORT_MODE: + case IFLA_BRPORT_GUARD: + case IFLA_BRPORT_PROTECT: + case IFLA_BRPORT_FAST_LEAVE: + case IFLA_BRPORT_LEARNING: + case IFLA_BRPORT_UNICAST_FLOOD: + case IFLA_BRPORT_PROXYARP: + case IFLA_BRPORT_LEARNING_SYNC: + case IFLA_BRPORT_PROXYARP_WIFI: + case IFLA_BRPORT_TOPOLOGY_CHANGE_ACK: + case IFLA_BRPORT_CONFIG_PENDING: + case IFLA_BRPORT_MULTICAST_ROUTER: + break; + /* uint16_t */ + case IFLA_BRPORT_PRIORITY: + case IFLA_BRPORT_DESIGNATED_PORT: + case IFLA_BRPORT_DESIGNATED_COST: + case IFLA_BRPORT_ID: + case IFLA_BRPORT_NO: + u16 = NLA_DATA(nlattr); + *u16 = tswap16(*u16); + break; + /* uin32_t */ + case IFLA_BRPORT_COST: + u32 = NLA_DATA(nlattr); + *u32 = tswap32(*u32); + break; + /* uint64_t */ + case IFLA_BRPORT_MESSAGE_AGE_TIMER: + case IFLA_BRPORT_FORWARD_DELAY_TIMER: + case IFLA_BRPORT_HOLD_TIMER: + u64 = NLA_DATA(nlattr); + *u64 = tswap64(*u64); + break; + /* ifla_bridge_id: uint8_t[] */ + case IFLA_BRPORT_ROOT_ID: + case IFLA_BRPORT_BRIDGE_ID: + break; + default: + gemu_log("Unknown IFLA_BRPORT type %d\n", nlattr->nla_type); + break; + } + return 0; +} + +struct linkinfo_context { + int len; + char *name; + int slave_len; + char *slave_name; +}; + +static abi_long host_to_target_data_linkinfo_nlattr(struct nlattr *nlattr, + void *context) +{ + struct linkinfo_context *li_context = context; + + switch (nlattr->nla_type) { + /* string */ + case IFLA_INFO_KIND: + li_context->name = NLA_DATA(nlattr); + li_context->len = nlattr->nla_len - NLA_HDRLEN; + break; + case IFLA_INFO_SLAVE_KIND: + li_context->slave_name = NLA_DATA(nlattr); + li_context->slave_len = nlattr->nla_len - NLA_HDRLEN; + break; + /* stats */ + case IFLA_INFO_XSTATS: + /* FIXME: only used by CAN */ + break; + /* nested */ + case IFLA_INFO_DATA: + if (strncmp(li_context->name, "bridge", + li_context->len) == 0) { + return host_to_target_for_each_nlattr(NLA_DATA(nlattr), + nlattr->nla_len, + NULL, + host_to_target_data_bridge_nlattr); + } else { + gemu_log("Unknown IFLA_INFO_KIND %s\n", li_context->name); + } + break; + case IFLA_INFO_SLAVE_DATA: + if (strncmp(li_context->slave_name, "bridge", + li_context->slave_len) == 0) { + return host_to_target_for_each_nlattr(NLA_DATA(nlattr), + nlattr->nla_len, + NULL, + host_to_target_slave_data_bridge_nlattr); + } else { + gemu_log("Unknown IFLA_INFO_SLAVE_KIND %s\n", + li_context->slave_name); + } + break; + default: + gemu_log("Unknown host IFLA_INFO type: %d\n", nlattr->nla_type); + break; + } + + return 0; +} + +static abi_long host_to_target_data_inet_nlattr(struct nlattr *nlattr, + void *context) +{ + uint32_t *u32; + int i; + + switch (nlattr->nla_type) { + case IFLA_INET_CONF: + u32 = NLA_DATA(nlattr); + for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32); + i++) { + u32[i] = tswap32(u32[i]); + } + break; + default: + gemu_log("Unknown host AF_INET type: %d\n", nlattr->nla_type); + } + return 0; +} + +static abi_long host_to_target_data_inet6_nlattr(struct nlattr *nlattr, + void *context) +{ + uint32_t *u32; + uint64_t *u64; + struct ifla_cacheinfo *ci; + int i; + + switch (nlattr->nla_type) { + /* binaries */ + case IFLA_INET6_TOKEN: + break; + /* uint8_t */ + case IFLA_INET6_ADDR_GEN_MODE: + break; + /* uint32_t */ + case IFLA_INET6_FLAGS: + u32 = NLA_DATA(nlattr); + *u32 = tswap32(*u32); + break; + /* uint32_t[] */ + case IFLA_INET6_CONF: + u32 = NLA_DATA(nlattr); + for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32); + i++) { + u32[i] = tswap32(u32[i]); + } + break; + /* ifla_cacheinfo */ + case IFLA_INET6_CACHEINFO: + ci = NLA_DATA(nlattr); + ci->max_reasm_len = tswap32(ci->max_reasm_len); + ci->tstamp = tswap32(ci->tstamp); + ci->reachable_time = tswap32(ci->reachable_time); + ci->retrans_time = tswap32(ci->retrans_time); + break; + /* uint64_t[] */ + case IFLA_INET6_STATS: + case IFLA_INET6_ICMP6STATS: + u64 = NLA_DATA(nlattr); + for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u64); + i++) { + u64[i] = tswap64(u64[i]); + } + break; + default: + gemu_log("Unknown host AF_INET6 type: %d\n", nlattr->nla_type); + } + return 0; +} + +static abi_long host_to_target_data_spec_nlattr(struct nlattr *nlattr, + void *context) +{ + switch (nlattr->nla_type) { + case AF_INET: + return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len, + NULL, + host_to_target_data_inet_nlattr); + case AF_INET6: + return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len, + NULL, + host_to_target_data_inet6_nlattr); + default: + gemu_log("Unknown host AF_SPEC type: %d\n", nlattr->nla_type); + break; + } + return 0; +} + static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr) { uint32_t *u32; struct rtnl_link_stats *st; struct rtnl_link_stats64 *st64; struct rtnl_link_ifmap *map; + struct linkinfo_context li_context; switch (rtattr->rta_type) { /* binary stream */ @@ -1846,11 +2154,15 @@ static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr) map->irq = tswap16(map->irq); break; /* nested */ - case IFLA_AF_SPEC: case IFLA_LINKINFO: - /* FIXME: implement nested type */ - gemu_log("Unimplemented nested type %d\n", rtattr->rta_type); - break; + memset(&li_context, 0, sizeof(li_context)); + return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len, + &li_context, + host_to_target_data_linkinfo_nlattr); + case IFLA_AF_SPEC: + return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len, + NULL, + host_to_target_data_spec_nlattr); default: gemu_log("Unknown host IFLA type: %d\n", rtattr->rta_type); break;