[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 05/16] linux-user: add nested netlink types
From: |
riku . voipio |
Subject: |
[Qemu-devel] [PULL 05/16] linux-user: add nested netlink types |
Date: |
Tue, 19 Jul 2016 15:54:03 +0300 |
From: Laurent Vivier <address@hidden>
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 <address@hidden>
Signed-off-by: Riku Voipio <address@hidden>
---
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 919b589..761d8fb 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 <linux/netlink.h>
#ifdef CONFIG_RTNETLINK
#include <linux/rtnetlink.h>
+#include <linux/if_bridge.h>
#endif
#include <linux/audit.h>
#include "linux_loop.h"
@@ -1712,6 +1713,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)
@@ -1738,12 +1766,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 */
@@ -1851,11 +2159,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;
--
2.1.4
- [Qemu-devel] [PULL 00/16] linux-user before 2.7 hardfreeze, riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 03/16] linux-user: add fd_trans helper in do_recvfrom(), riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 01/16] linux-user: fd_trans_*_data() returns the length, riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 04/16] linux-user: convert sockaddr_ll from host to target, riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 02/16] linux-user: fix netlink memory corruption, riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 06/16] linux-user: Check sigsetsize argument to syscalls, riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 07/16] linux-user: Add loop control ioctls, riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 08/16] linux-user: Correct type for BLKSSZGET, riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 10/16] linux-user: Forget about synchronous signal once it is delivered, riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 05/16] linux-user: add nested netlink types,
riku . voipio <=
- [Qemu-devel] [PULL 11/16] linux-user: Handle short lengths in host_to_target_sockaddr(), riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 09/16] linux-user: Correct type for LOOP_GET_STATUS{, 64} ioctls, riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 12/16] linux-user: Add some new blk ioctls, riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 13/16] TIOCGPTN and related terminal control ioctls were not converted to the guest ioctl format on x86_64 targets. Convert these ioctls to enable terminal functionality on x86_64 guests., riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 15/16] linux-user: Fix type for SIOCATMARK ioctl, riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 14/16] linux-user: define missing sparc syscalls, riku . voipio, 2016/07/19
- [Qemu-devel] [PULL 16/16] linux-user: AArch64 has sync_file_range, not sync_file_range2, riku . voipio, 2016/07/19