|
@@ -25,12 +25,32 @@
|
|
|
#ifdef CONFIG_RTNETLINK
|
|
|
#include <linux/rtnetlink.h>
|
|
|
#include <linux/if_bridge.h>
|
|
|
+#include <linux/neighbour.h>
|
|
|
#endif
|
|
|
#include "qemu.h"
|
|
|
#include "user-internals.h"
|
|
|
#include "fd-trans.h"
|
|
|
#include "signal-common.h"
|
|
|
|
|
|
+#define NDM_RTA(r) ((struct rtattr*)(((char*)(r)) + \
|
|
|
+ NLMSG_ALIGN(sizeof(struct ndmsg))))
|
|
|
+
|
|
|
+enum {
|
|
|
+ QEMU_IFA_UNSPEC,
|
|
|
+ QEMU_IFA_ADDRESS,
|
|
|
+ QEMU_IFA_LOCAL,
|
|
|
+ QEMU_IFA_LABEL,
|
|
|
+ QEMU_IFA_BROADCAST,
|
|
|
+ QEMU_IFA_ANYCAST,
|
|
|
+ QEMU_IFA_CACHEINFO,
|
|
|
+ QEMU_IFA_MULTICAST,
|
|
|
+ QEMU_IFA_FLAGS,
|
|
|
+ QEMU_IFA_RT_PRIORITY,
|
|
|
+ QEMU_IFA_TARGET_NETNSID,
|
|
|
+ QEMU_IFA_PROTO,
|
|
|
+ QEMU__IFA__MAX,
|
|
|
+};
|
|
|
+
|
|
|
enum {
|
|
|
QEMU_IFLA_BR_UNSPEC,
|
|
|
QEMU_IFLA_BR_FORWARD_DELAY,
|
|
@@ -141,6 +161,14 @@ enum {
|
|
|
QEMU_IFLA_PROTO_DOWN_REASON,
|
|
|
QEMU_IFLA_PARENT_DEV_NAME,
|
|
|
QEMU_IFLA_PARENT_DEV_BUS_NAME,
|
|
|
+ QEMU_IFLA_GRO_MAX_SIZE,
|
|
|
+ QEMU_IFLA_TSO_MAX_SIZE,
|
|
|
+ QEMU_IFLA_TSO_MAX_SEGS,
|
|
|
+ QEMU_IFLA_ALLMULTI,
|
|
|
+ QEMU_IFLA_DEVLINK_PORT,
|
|
|
+ QEMU_IFLA_GSO_IPV4_MAX_SIZE,
|
|
|
+ QEMU_IFLA_GRO_IPV4_MAX_SIZE,
|
|
|
+ QEMU_IFLA_DPLL_PIN,
|
|
|
QEMU___IFLA_MAX
|
|
|
};
|
|
|
|
|
@@ -982,6 +1010,22 @@ static abi_long host_to_target_data_vfinfo_nlattr(struct nlattr *nlattr,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static abi_long host_to_target_data_prop_nlattr(struct nlattr *nlattr,
|
|
|
+ void *context)
|
|
|
+{
|
|
|
+ switch (nlattr->nla_type) {
|
|
|
+ /* string */
|
|
|
+ case QEMU_IFLA_ALT_IFNAME:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ qemu_log_mask(LOG_UNIMP, "Unknown host PROP type: %d\n",
|
|
|
+ nlattr->nla_type);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
|
|
|
{
|
|
|
uint32_t *u32;
|
|
@@ -990,7 +1034,7 @@ static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
|
|
|
struct rtnl_link_ifmap *map;
|
|
|
struct linkinfo_context li_context;
|
|
|
|
|
|
- switch (rtattr->rta_type) {
|
|
|
+ switch (rtattr->rta_type & NLA_TYPE_MASK) {
|
|
|
/* binary stream */
|
|
|
case QEMU_IFLA_ADDRESS:
|
|
|
case QEMU_IFLA_BROADCAST:
|
|
@@ -1028,6 +1072,12 @@ static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
|
|
|
case QEMU_IFLA_CARRIER_DOWN_COUNT:
|
|
|
case QEMU_IFLA_MIN_MTU:
|
|
|
case QEMU_IFLA_MAX_MTU:
|
|
|
+ case QEMU_IFLA_GRO_MAX_SIZE:
|
|
|
+ case QEMU_IFLA_TSO_MAX_SIZE:
|
|
|
+ case QEMU_IFLA_TSO_MAX_SEGS:
|
|
|
+ case QEMU_IFLA_ALLMULTI:
|
|
|
+ case QEMU_IFLA_GSO_IPV4_MAX_SIZE:
|
|
|
+ case QEMU_IFLA_GRO_IPV4_MAX_SIZE:
|
|
|
u32 = RTA_DATA(rtattr);
|
|
|
*u32 = tswap32(*u32);
|
|
|
break;
|
|
@@ -1123,6 +1173,10 @@ static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
|
|
|
return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
|
|
|
NULL,
|
|
|
host_to_target_data_vfinfo_nlattr);
|
|
|
+ case QEMU_IFLA_PROP_LIST:
|
|
|
+ return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len,
|
|
|
+ NULL,
|
|
|
+ host_to_target_data_prop_nlattr);
|
|
|
default:
|
|
|
qemu_log_mask(LOG_UNIMP, "Unknown host QEMU_IFLA type: %d\n",
|
|
|
rtattr->rta_type);
|
|
@@ -1138,20 +1192,21 @@ static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr)
|
|
|
|
|
|
switch (rtattr->rta_type) {
|
|
|
/* binary: depends on family type */
|
|
|
- case IFA_ADDRESS:
|
|
|
- case IFA_LOCAL:
|
|
|
+ case QEMU_IFA_ADDRESS:
|
|
|
+ case QEMU_IFA_LOCAL:
|
|
|
+ case QEMU_IFA_PROTO:
|
|
|
break;
|
|
|
/* string */
|
|
|
- case IFA_LABEL:
|
|
|
+ case QEMU_IFA_LABEL:
|
|
|
break;
|
|
|
/* u32 */
|
|
|
- case IFA_FLAGS:
|
|
|
- case IFA_BROADCAST:
|
|
|
+ case QEMU_IFA_FLAGS:
|
|
|
+ case QEMU_IFA_BROADCAST:
|
|
|
u32 = RTA_DATA(rtattr);
|
|
|
*u32 = tswap32(*u32);
|
|
|
break;
|
|
|
/* struct ifa_cacheinfo */
|
|
|
- case IFA_CACHEINFO:
|
|
|
+ case QEMU_IFA_CACHEINFO:
|
|
|
ci = RTA_DATA(rtattr);
|
|
|
ci->ifa_prefered = tswap32(ci->ifa_prefered);
|
|
|
ci->ifa_valid = tswap32(ci->ifa_valid);
|
|
@@ -1209,6 +1264,35 @@ static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static abi_long host_to_target_data_neigh_rtattr(struct rtattr *rtattr)
|
|
|
+{
|
|
|
+ struct nda_cacheinfo *ndac;
|
|
|
+ uint32_t *u32;
|
|
|
+
|
|
|
+ switch (rtattr->rta_type) {
|
|
|
+ case NDA_UNSPEC:
|
|
|
+ case NDA_DST:
|
|
|
+ case NDA_LLADDR:
|
|
|
+ break;
|
|
|
+ case NDA_PROBES:
|
|
|
+ u32 = RTA_DATA(rtattr);
|
|
|
+ *u32 = tswap32(*u32);
|
|
|
+ break;
|
|
|
+ case NDA_CACHEINFO:
|
|
|
+ ndac = RTA_DATA(rtattr);
|
|
|
+ ndac->ndm_confirmed = tswap32(ndac->ndm_confirmed);
|
|
|
+ ndac->ndm_used = tswap32(ndac->ndm_used);
|
|
|
+ ndac->ndm_updated = tswap32(ndac->ndm_updated);
|
|
|
+ ndac->ndm_refcnt = tswap32(ndac->ndm_refcnt);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ qemu_log_mask(LOG_UNIMP, "Unknown host to target NEIGH type: %d\n",
|
|
|
+ rtattr->rta_type);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static abi_long host_to_target_link_rtattr(struct rtattr *rtattr,
|
|
|
uint32_t rtattr_len)
|
|
|
{
|
|
@@ -1230,12 +1314,20 @@ static abi_long host_to_target_route_rtattr(struct rtattr *rtattr,
|
|
|
host_to_target_data_route_rtattr);
|
|
|
}
|
|
|
|
|
|
+static abi_long host_to_target_neigh_rtattr(struct rtattr *rtattr,
|
|
|
+ uint32_t rtattr_len)
|
|
|
+{
|
|
|
+ return host_to_target_for_each_rtattr(rtattr, rtattr_len,
|
|
|
+ host_to_target_data_neigh_rtattr);
|
|
|
+}
|
|
|
+
|
|
|
static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
|
|
|
{
|
|
|
uint32_t nlmsg_len;
|
|
|
struct ifinfomsg *ifi;
|
|
|
struct ifaddrmsg *ifa;
|
|
|
struct rtmsg *rtm;
|
|
|
+ struct ndmsg *ndm;
|
|
|
|
|
|
nlmsg_len = nlh->nlmsg_len;
|
|
|
switch (nlh->nlmsg_type) {
|
|
@@ -1262,6 +1354,17 @@ static abi_long host_to_target_data_route(struct nlmsghdr *nlh)
|
|
|
nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
|
|
|
}
|
|
|
break;
|
|
|
+ case RTM_NEWNEIGH:
|
|
|
+ case RTM_DELNEIGH:
|
|
|
+ case RTM_GETNEIGH:
|
|
|
+ if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ndm))) {
|
|
|
+ ndm = NLMSG_DATA(nlh);
|
|
|
+ ndm->ndm_ifindex = tswap32(ndm->ndm_ifindex);
|
|
|
+ ndm->ndm_state = tswap16(ndm->ndm_state);
|
|
|
+ host_to_target_neigh_rtattr(NDM_RTA(ndm),
|
|
|
+ nlmsg_len - NLMSG_LENGTH(sizeof(*ndm)));
|
|
|
+ }
|
|
|
+ break;
|
|
|
case RTM_NEWROUTE:
|
|
|
case RTM_DELROUTE:
|
|
|
case RTM_GETROUTE:
|
|
@@ -1398,8 +1501,8 @@ static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
|
|
|
{
|
|
|
switch (rtattr->rta_type) {
|
|
|
/* binary: depends on family type */
|
|
|
- case IFA_LOCAL:
|
|
|
- case IFA_ADDRESS:
|
|
|
+ case QEMU_IFA_LOCAL:
|
|
|
+ case QEMU_IFA_ADDRESS:
|
|
|
break;
|
|
|
default:
|
|
|
qemu_log_mask(LOG_UNIMP, "Unknown target IFA type: %d\n",
|
|
@@ -1409,6 +1512,35 @@ static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static abi_long target_to_host_data_neigh_rtattr(struct rtattr *rtattr)
|
|
|
+{
|
|
|
+ struct nda_cacheinfo *ndac;
|
|
|
+ uint32_t *u32;
|
|
|
+
|
|
|
+ switch (rtattr->rta_type) {
|
|
|
+ case NDA_UNSPEC:
|
|
|
+ case NDA_DST:
|
|
|
+ case NDA_LLADDR:
|
|
|
+ break;
|
|
|
+ case NDA_PROBES:
|
|
|
+ u32 = RTA_DATA(rtattr);
|
|
|
+ *u32 = tswap32(*u32);
|
|
|
+ break;
|
|
|
+ case NDA_CACHEINFO:
|
|
|
+ ndac = RTA_DATA(rtattr);
|
|
|
+ ndac->ndm_confirmed = tswap32(ndac->ndm_confirmed);
|
|
|
+ ndac->ndm_used = tswap32(ndac->ndm_used);
|
|
|
+ ndac->ndm_updated = tswap32(ndac->ndm_updated);
|
|
|
+ ndac->ndm_refcnt = tswap32(ndac->ndm_refcnt);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ qemu_log_mask(LOG_UNIMP, "Unknown target NEIGH type: %d\n",
|
|
|
+ rtattr->rta_type);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr)
|
|
|
{
|
|
|
uint32_t *u32;
|
|
@@ -1447,6 +1579,13 @@ static void target_to_host_addr_rtattr(struct rtattr *rtattr,
|
|
|
target_to_host_data_addr_rtattr);
|
|
|
}
|
|
|
|
|
|
+static void target_to_host_neigh_rtattr(struct rtattr *rtattr,
|
|
|
+ uint32_t rtattr_len)
|
|
|
+{
|
|
|
+ target_to_host_for_each_rtattr(rtattr, rtattr_len,
|
|
|
+ target_to_host_data_neigh_rtattr);
|
|
|
+}
|
|
|
+
|
|
|
static void target_to_host_route_rtattr(struct rtattr *rtattr,
|
|
|
uint32_t rtattr_len)
|
|
|
{
|
|
@@ -1459,6 +1598,7 @@ static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
|
|
|
struct ifinfomsg *ifi;
|
|
|
struct ifaddrmsg *ifa;
|
|
|
struct rtmsg *rtm;
|
|
|
+ struct ndmsg *ndm;
|
|
|
|
|
|
switch (nlh->nlmsg_type) {
|
|
|
case RTM_NEWLINK:
|
|
@@ -1485,6 +1625,17 @@ static abi_long target_to_host_data_route(struct nlmsghdr *nlh)
|
|
|
NLMSG_LENGTH(sizeof(*ifa)));
|
|
|
}
|
|
|
break;
|
|
|
+ case RTM_NEWNEIGH:
|
|
|
+ case RTM_DELNEIGH:
|
|
|
+ case RTM_GETNEIGH:
|
|
|
+ if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ndm))) {
|
|
|
+ ndm = NLMSG_DATA(nlh);
|
|
|
+ ndm->ndm_ifindex = tswap32(ndm->ndm_ifindex);
|
|
|
+ ndm->ndm_state = tswap16(ndm->ndm_state);
|
|
|
+ target_to_host_neigh_rtattr(NDM_RTA(ndm), nlh->nlmsg_len -
|
|
|
+ NLMSG_LENGTH(sizeof(*ndm)));
|
|
|
+ }
|
|
|
+ break;
|
|
|
case RTM_NEWROUTE:
|
|
|
case RTM_DELROUTE:
|
|
|
case RTM_GETROUTE:
|