Import QEMU upstream snapshot d2e570c
Upstream: https://gitlab.com/qemu-project/qemu.git Upstream-Commit: d2e570cc0f97b936902a5b1b86b73c0f5998b475
This commit is contained in:
commit
cf256aa081
11315 files changed
+3598369
No files matched your search
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Self-announce facility
|
||||
* (c) 2017-2019 Red Hat, Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_NET_ANNOUNCE_H
|
||||
#define QEMU_NET_ANNOUNCE_H
|
||||
|
||||
#include "qapi/qapi-types-net.h"
|
||||
#include "qemu/timer.h"
|
||||
|
||||
typedef struct AnnounceTimer {
|
||||
QEMUTimer *tm;
|
||||
AnnounceParameters params;
|
||||
QEMUClockType type;
|
||||
int round;
|
||||
} AnnounceTimer;
|
||||
|
||||
/* Returns: update the timer to the next time point */
|
||||
int64_t qemu_announce_timer_step(AnnounceTimer *timer);
|
||||
|
||||
/*
|
||||
* Delete the underlying timer and other data
|
||||
* If 'free_named' true and the timer is a named timer, then remove
|
||||
* it from the list of named timers and free the AnnounceTimer itself.
|
||||
*/
|
||||
void qemu_announce_timer_del(AnnounceTimer *timer, bool free_named);
|
||||
|
||||
/*
|
||||
* Under BQL/main thread
|
||||
* Reset the timer to the given parameters/type/notifier.
|
||||
*/
|
||||
void qemu_announce_timer_reset(AnnounceTimer *timer,
|
||||
AnnounceParameters *params,
|
||||
QEMUClockType type,
|
||||
QEMUTimerCB *cb,
|
||||
void *opaque);
|
||||
|
||||
void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* CAN common CAN bus emulation support
|
||||
*
|
||||
* Copyright (c) 2013-2014 Jin Yang
|
||||
* Copyright (c) 2014-2018 Pavel Pisa
|
||||
*
|
||||
* Initial development supported by Google GSoC 2013 from RTEMS project slot
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef NET_CAN_EMU_H
|
||||
#define NET_CAN_EMU_H
|
||||
|
||||
#include "qemu/queue.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/* NOTE: the following two structures is copied from <linux/can.h>. */
|
||||
|
||||
/*
|
||||
* Controller Area Network Identifier structure
|
||||
*
|
||||
* bit 0-28 : CAN identifier (11/29 bit)
|
||||
* bit 29 : error frame flag (0 = data frame, 1 = error frame)
|
||||
* bit 30 : remote transmission request flag (1 = rtr frame)
|
||||
* bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
|
||||
*/
|
||||
typedef uint32_t qemu_canid_t;
|
||||
|
||||
typedef struct qemu_can_frame {
|
||||
qemu_canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
|
||||
uint8_t can_dlc; /* data length code: 0 .. 8 */
|
||||
uint8_t flags;
|
||||
uint8_t data[64] QEMU_ALIGNED(8);
|
||||
} qemu_can_frame;
|
||||
|
||||
/* Keep defines for QEMU separate from Linux ones for now */
|
||||
|
||||
#define QEMU_CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
|
||||
#define QEMU_CAN_RTR_FLAG 0x40000000U /* remote transmission request */
|
||||
#define QEMU_CAN_ERR_FLAG 0x20000000U /* error message frame */
|
||||
|
||||
#define QEMU_CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
|
||||
#define QEMU_CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
|
||||
|
||||
#define QEMU_CAN_FRMF_BRS 0x01 /* bit rate switch (2nd bitrate for data) */
|
||||
#define QEMU_CAN_FRMF_ESI 0x02 /* error state ind. of transmitting node */
|
||||
#define QEMU_CAN_FRMF_TYPE_FD 0x10 /* internal bit ind. of CAN FD frame */
|
||||
|
||||
/**
|
||||
* struct qemu_can_filter - CAN ID based filter in can_register().
|
||||
* @can_id: relevant bits of CAN ID which are not masked out.
|
||||
* @can_mask: CAN mask (see description)
|
||||
*
|
||||
* Description:
|
||||
* A filter matches, when
|
||||
*
|
||||
* <received_can_id> & mask == can_id & mask
|
||||
*
|
||||
* The filter can be inverted (QEMU_CAN_INV_FILTER bit set in can_id) or it can
|
||||
* filter for error message frames (QEMU_CAN_ERR_FLAG bit set in mask).
|
||||
*/
|
||||
typedef struct qemu_can_filter {
|
||||
qemu_canid_t can_id;
|
||||
qemu_canid_t can_mask;
|
||||
} qemu_can_filter;
|
||||
|
||||
/* QEMU_CAN_INV_FILTER can be set in qemu_can_filter.can_id */
|
||||
#define QEMU_CAN_INV_FILTER 0x20000000U
|
||||
|
||||
typedef struct CanBusClientState CanBusClientState;
|
||||
|
||||
#define TYPE_CAN_BUS "can-bus"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(CanBusState, CAN_BUS)
|
||||
|
||||
typedef struct CanBusClientInfo {
|
||||
bool (*can_receive)(CanBusClientState *);
|
||||
ssize_t (*receive)(CanBusClientState *,
|
||||
const struct qemu_can_frame *frames, size_t frames_cnt);
|
||||
} CanBusClientInfo;
|
||||
|
||||
struct CanBusClientState {
|
||||
CanBusClientInfo *info;
|
||||
CanBusState *bus;
|
||||
int link_down;
|
||||
QTAILQ_ENTRY(CanBusClientState) next;
|
||||
CanBusClientState *peer;
|
||||
char *model;
|
||||
char *name;
|
||||
void (*destructor)(CanBusClientState *);
|
||||
bool fd_mode;
|
||||
};
|
||||
|
||||
int can_bus_filter_match(struct qemu_can_filter *filter, qemu_canid_t can_id);
|
||||
|
||||
int can_bus_insert_client(CanBusState *bus, CanBusClientState *client);
|
||||
|
||||
int can_bus_remove_client(CanBusClientState *client);
|
||||
|
||||
ssize_t can_bus_client_send(CanBusClientState *,
|
||||
const struct qemu_can_frame *frames,
|
||||
size_t frames_cnt);
|
||||
|
||||
int can_bus_client_set_filters(CanBusClientState *,
|
||||
const struct qemu_can_filter *filters,
|
||||
size_t filters_cnt);
|
||||
|
||||
uint8_t can_dlc2len(uint8_t can_dlc);
|
||||
|
||||
uint8_t can_len2dlc(uint8_t len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* CAN common CAN bus emulation support
|
||||
*
|
||||
* Copyright (c) 2013-2014 Jin Yang
|
||||
* Copyright (c) 2014-2018 Pavel Pisa
|
||||
*
|
||||
* Initial development supported by Google GSoC 2013 from RTEMS project slot
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef NET_CAN_HOST_H
|
||||
#define NET_CAN_HOST_H
|
||||
|
||||
#include "net/can_emu.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_CAN_HOST "can-host"
|
||||
OBJECT_DECLARE_TYPE(CanHostState, CanHostClass, CAN_HOST)
|
||||
|
||||
struct CanHostState {
|
||||
Object oc;
|
||||
|
||||
CanBusState *bus;
|
||||
CanBusClientState bus_client;
|
||||
};
|
||||
|
||||
struct CanHostClass {
|
||||
ObjectClass oc;
|
||||
|
||||
void (*connect)(CanHostState *ch, Error **errp);
|
||||
void (*disconnect)(CanHostState *ch);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* IP checksumming functions.
|
||||
* (c) 2008 Gerd Hoffmann <[email protected]>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; under version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_NET_CHECKSUM_H
|
||||
#define QEMU_NET_CHECKSUM_H
|
||||
|
||||
#include "qemu/bswap.h"
|
||||
struct iovec;
|
||||
|
||||
#define CSUM_IP 0x01
|
||||
#define CSUM_TCP 0x02
|
||||
#define CSUM_UDP 0x04
|
||||
#define CSUM_ALL (CSUM_IP | CSUM_TCP | CSUM_UDP)
|
||||
|
||||
uint32_t net_checksum_add_cont(int len, uint8_t *buf, int seq);
|
||||
uint16_t net_checksum_finish(uint32_t sum);
|
||||
uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto,
|
||||
uint8_t *addrs, uint8_t *buf);
|
||||
void net_checksum_calculate(void *data, int length, int csum_flag);
|
||||
|
||||
static inline uint32_t
|
||||
net_checksum_add(int len, uint8_t *buf)
|
||||
{
|
||||
return net_checksum_add_cont(len, buf, 0);
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
net_checksum_finish_nozero(uint32_t sum)
|
||||
{
|
||||
return net_checksum_finish(sum) ?: 0xFFFF;
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
net_raw_checksum(uint8_t *data, int length)
|
||||
{
|
||||
return net_checksum_finish(net_checksum_add(length, data));
|
||||
}
|
||||
|
||||
/**
|
||||
* net_checksum_add_iov: scatter-gather vector checksumming
|
||||
*
|
||||
* @iov: input scatter-gather array
|
||||
* @iov_cnt: number of array elements
|
||||
* @iov_off: starting iov offset for checksumming
|
||||
* @size: length of data to be checksummed
|
||||
* @csum_offset: offset of the checksum chunk
|
||||
*/
|
||||
uint32_t net_checksum_add_iov(const struct iovec *iov,
|
||||
const unsigned int iov_cnt,
|
||||
uint32_t iov_off, uint32_t size,
|
||||
uint32_t csum_offset);
|
||||
|
||||
typedef struct toeplitz_key_st {
|
||||
uint32_t leftmost_32_bits;
|
||||
uint8_t *next_byte;
|
||||
} net_toeplitz_key;
|
||||
|
||||
static inline
|
||||
void net_toeplitz_key_init(net_toeplitz_key *key, uint8_t *key_bytes)
|
||||
{
|
||||
key->leftmost_32_bits = be32_to_cpu(*(uint32_t *)key_bytes);
|
||||
key->next_byte = key_bytes + sizeof(uint32_t);
|
||||
}
|
||||
|
||||
static inline
|
||||
void net_toeplitz_add(uint32_t *result,
|
||||
uint8_t *input,
|
||||
uint32_t len,
|
||||
net_toeplitz_key *key)
|
||||
{
|
||||
register uint32_t accumulator = *result;
|
||||
register uint32_t leftmost_32_bits = key->leftmost_32_bits;
|
||||
register uint32_t byte;
|
||||
|
||||
for (byte = 0; byte < len; byte++) {
|
||||
register uint8_t input_byte = input[byte];
|
||||
register uint8_t key_byte = *(key->next_byte++);
|
||||
register uint8_t bit;
|
||||
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
if (input_byte & (1 << 7)) {
|
||||
accumulator ^= leftmost_32_bits;
|
||||
}
|
||||
|
||||
leftmost_32_bits =
|
||||
(leftmost_32_bits << 1) | ((key_byte & (1 << 7)) >> 7);
|
||||
|
||||
input_byte <<= 1;
|
||||
key_byte <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
key->leftmost_32_bits = leftmost_32_bits;
|
||||
*result = accumulator;
|
||||
}
|
||||
|
||||
#endif /* QEMU_NET_CHECKSUM_H */
|
||||
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
* QEMU network structures definitions and helper functions
|
||||
*
|
||||
* Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
|
||||
*
|
||||
* Developed by Daynix Computing LTD (http://www.daynix.com)
|
||||
*
|
||||
* Portions developed by Free Software Foundation, Inc
|
||||
* Copyright (C) 1991-1997, 2001, 2003, 2006 Free Software Foundation, Inc.
|
||||
* See netinet/ip6.h and netinet/in.h (GNU C Library)
|
||||
*
|
||||
* Portions developed by Igor Kovalenko
|
||||
* Copyright (c) 2006 Igor Kovalenko
|
||||
* See hw/rtl8139.c (QEMU)
|
||||
*
|
||||
* Authors:
|
||||
* Dmitry Fleytman <[email protected]>
|
||||
* Tamir Shomer <[email protected]>
|
||||
* Yan Vugenfirer <[email protected]>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QEMU_ETH_H
|
||||
#define QEMU_ETH_H
|
||||
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/iov.h"
|
||||
|
||||
#define ETH_ALEN 6
|
||||
#define ETH_HLEN 14
|
||||
#define ETH_ZLEN 60 /* Min. octets in frame without FCS */
|
||||
#define ETH_FCS_LEN 4
|
||||
#define ETH_MTU 1500
|
||||
|
||||
struct eth_header {
|
||||
uint8_t h_dest[ETH_ALEN]; /* destination eth addr */
|
||||
uint8_t h_source[ETH_ALEN]; /* source ether addr */
|
||||
uint16_t h_proto; /* packet type ID field */
|
||||
} QEMU_PACKED;
|
||||
|
||||
struct vlan_header {
|
||||
uint16_t h_tci; /* priority and VLAN ID */
|
||||
uint16_t h_proto; /* encapsulated protocol */
|
||||
};
|
||||
|
||||
struct ip_header {
|
||||
uint8_t ip_ver_len; /* version and header length */
|
||||
uint8_t ip_tos; /* type of service */
|
||||
uint16_t ip_len; /* total length */
|
||||
uint16_t ip_id; /* identification */
|
||||
uint16_t ip_off; /* fragment offset field */
|
||||
uint8_t ip_ttl; /* time to live */
|
||||
uint8_t ip_p; /* protocol */
|
||||
uint16_t ip_sum; /* checksum */
|
||||
uint32_t ip_src, ip_dst; /* source and destination address */
|
||||
} QEMU_PACKED;
|
||||
|
||||
typedef struct tcp_header {
|
||||
uint16_t th_sport; /* source port */
|
||||
uint16_t th_dport; /* destination port */
|
||||
uint32_t th_seq; /* sequence number */
|
||||
uint32_t th_ack; /* acknowledgment number */
|
||||
uint16_t th_offset_flags; /* data offset, reserved 6 bits, */
|
||||
/* TCP protocol flags */
|
||||
uint16_t th_win; /* window */
|
||||
uint16_t th_sum; /* checksum */
|
||||
uint16_t th_urp; /* urgent pointer */
|
||||
} QEMU_PACKED tcp_header;
|
||||
|
||||
#define TCP_FLAGS_ONLY(flags) ((flags) & 0x3f)
|
||||
|
||||
#define TCP_HEADER_FLAGS(tcp) \
|
||||
TCP_FLAGS_ONLY(be16_to_cpu((tcp)->th_offset_flags))
|
||||
|
||||
#define TCP_FLAG_ACK 0x10
|
||||
|
||||
#define TCP_HEADER_DATA_OFFSET(tcp) \
|
||||
(((be16_to_cpu((tcp)->th_offset_flags) >> 12) & 0xf) << 2)
|
||||
|
||||
typedef struct udp_header {
|
||||
uint16_t uh_sport; /* source port */
|
||||
uint16_t uh_dport; /* destination port */
|
||||
uint16_t uh_ulen; /* udp length */
|
||||
uint16_t uh_sum; /* udp checksum */
|
||||
} QEMU_PACKED udp_header;
|
||||
|
||||
typedef struct ip_pseudo_header {
|
||||
uint32_t ip_src;
|
||||
uint32_t ip_dst;
|
||||
uint8_t zeros;
|
||||
uint8_t ip_proto;
|
||||
uint16_t ip_payload;
|
||||
} ip_pseudo_header;
|
||||
|
||||
/* IPv6 address */
|
||||
struct in6_address {
|
||||
union {
|
||||
uint8_t __u6_addr8[16];
|
||||
} __in6_u;
|
||||
};
|
||||
|
||||
struct ip6_header {
|
||||
union {
|
||||
struct ip6_hdrctl {
|
||||
uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC,
|
||||
20 bits flow-ID */
|
||||
uint16_t ip6_un1_plen; /* payload length */
|
||||
uint8_t ip6_un1_nxt; /* next header */
|
||||
uint8_t ip6_un1_hlim; /* hop limit */
|
||||
} ip6_un1;
|
||||
uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits tclass */
|
||||
struct ip6_ecn_access {
|
||||
uint8_t ip6_un3_vfc; /* 4 bits version, top 4 bits tclass */
|
||||
uint8_t ip6_un3_ecn; /* 2 bits ECN, top 6 bits payload length */
|
||||
} ip6_un3;
|
||||
} ip6_ctlun;
|
||||
struct in6_address ip6_src; /* source address */
|
||||
struct in6_address ip6_dst; /* destination address */
|
||||
} QEMU_PACKED;
|
||||
|
||||
typedef struct ip6_pseudo_header {
|
||||
struct in6_address ip6_src;
|
||||
struct in6_address ip6_dst;
|
||||
uint32_t len;
|
||||
uint8_t zero[3];
|
||||
uint8_t next_hdr;
|
||||
} ip6_pseudo_header;
|
||||
|
||||
struct ip6_ext_hdr {
|
||||
uint8_t ip6r_nxt; /* next header */
|
||||
uint8_t ip6r_len; /* length in units of 8 octets */
|
||||
};
|
||||
|
||||
struct ip6_ext_hdr_routing {
|
||||
uint8_t nxt;
|
||||
uint8_t len;
|
||||
uint8_t rtype;
|
||||
uint8_t segleft;
|
||||
uint8_t rsvd[4];
|
||||
};
|
||||
|
||||
struct ip6_option_hdr {
|
||||
#define IP6_OPT_PAD1 (0x00)
|
||||
#define IP6_OPT_HOME (0xC9)
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
};
|
||||
|
||||
struct udp_hdr {
|
||||
uint16_t uh_sport; /* source port */
|
||||
uint16_t uh_dport; /* destination port */
|
||||
uint16_t uh_ulen; /* udp length */
|
||||
uint16_t uh_sum; /* udp checksum */
|
||||
};
|
||||
|
||||
struct tcp_hdr {
|
||||
u_short th_sport; /* source port */
|
||||
u_short th_dport; /* destination port */
|
||||
uint32_t th_seq; /* sequence number */
|
||||
uint32_t th_ack; /* acknowledgment number */
|
||||
#if HOST_BIG_ENDIAN
|
||||
u_char th_off : 4, /* data offset */
|
||||
th_x2:4; /* (unused) */
|
||||
#else
|
||||
u_char th_x2 : 4, /* (unused) */
|
||||
th_off:4; /* data offset */
|
||||
#endif
|
||||
|
||||
#define TH_ELN 0x1 /* explicit loss notification */
|
||||
#define TH_ECN 0x2 /* explicit congestion notification */
|
||||
#define TH_FS 0x4 /* fast start */
|
||||
|
||||
u_char th_flags;
|
||||
#define TH_FIN 0x01
|
||||
#define TH_SYN 0x02
|
||||
#define TH_RST 0x04
|
||||
#define TH_PUSH 0x08
|
||||
#define TH_ACK 0x10
|
||||
#define TH_URG 0x20
|
||||
#define TH_ECE 0x40
|
||||
#define TH_CWR 0x80
|
||||
u_short th_win; /* window */
|
||||
u_short th_sum; /* checksum */
|
||||
u_short th_urp; /* urgent pointer */
|
||||
};
|
||||
|
||||
#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
|
||||
#define ip6_ecn_acc ip6_ctlun.ip6_un3.ip6_un3_ecn
|
||||
#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
|
||||
|
||||
#define PKT_GET_ETH_HDR(p) \
|
||||
((struct eth_header *)(p))
|
||||
#define PKT_GET_VLAN_HDR(p) \
|
||||
((struct vlan_header *) (((uint8_t *)(p)) + sizeof(struct eth_header)))
|
||||
#define PKT_GET_DVLAN_HDR(p) \
|
||||
(PKT_GET_VLAN_HDR(p) + 1)
|
||||
#define PKT_GET_IP_HDR(p) \
|
||||
((struct ip_header *)(((uint8_t *)(p)) + eth_get_l2_hdr_length(p)))
|
||||
#define IP_HDR_GET_LEN(p) \
|
||||
((ldub_p(p + offsetof(struct ip_header, ip_ver_len)) & 0x0F) << 2)
|
||||
#define IP_HDR_GET_P(p) \
|
||||
(ldub_p(p + offsetof(struct ip_header, ip_p)))
|
||||
#define PKT_GET_IP_HDR_LEN(p) \
|
||||
(IP_HDR_GET_LEN(PKT_GET_IP_HDR(p)))
|
||||
#define PKT_GET_IP6_HDR(p) \
|
||||
((struct ip6_header *) (((uint8_t *)(p)) + eth_get_l2_hdr_length(p)))
|
||||
#define IP_HEADER_VERSION(ip) \
|
||||
(((ip)->ip_ver_len >> 4) & 0xf)
|
||||
#define IP4_IS_FRAGMENT(ip) \
|
||||
((be16_to_cpu((ip)->ip_off) & (IP_OFFMASK | IP_MF)) != 0)
|
||||
|
||||
#define ETH_P_IP (0x0800) /* Internet Protocol packet */
|
||||
#define ETH_P_ARP (0x0806) /* Address Resolution packet */
|
||||
#define ETH_P_IPV6 (0x86dd)
|
||||
#define ETH_P_VLAN (0x8100)
|
||||
#define ETH_P_DVLAN (0x88a8)
|
||||
#define ETH_P_NCSI (0x88f8)
|
||||
#define ETH_P_UNKNOWN (0xffff)
|
||||
#define VLAN_VID_MASK 0x0fff
|
||||
#define IP_HEADER_VERSION_4 (4)
|
||||
#define IP_HEADER_VERSION_6 (6)
|
||||
#define IP_PROTO_TCP (6)
|
||||
#define IP_PROTO_UDP (17)
|
||||
#define IP_PROTO_SCTP (132)
|
||||
#define IPTOS_ECN_MASK 0x03
|
||||
#define IPTOS_ECN(x) ((x) & IPTOS_ECN_MASK)
|
||||
#define IPTOS_ECN_CE 0x03
|
||||
#define IP6_ECN_MASK 0xC0
|
||||
#define IP6_ECN(x) ((x) & IP6_ECN_MASK)
|
||||
#define IP6_ECN_CE 0xC0
|
||||
#define IP4_DONT_FRAGMENT_FLAG (1 << 14)
|
||||
|
||||
#define IS_SPECIAL_VLAN_ID(x) \
|
||||
(((x) == 0) || ((x) == 0xFFF))
|
||||
|
||||
#define ETH_MAX_L2_HDR_LEN \
|
||||
(sizeof(struct eth_header) + 2 * sizeof(struct vlan_header))
|
||||
|
||||
#define ETH_MAX_IP4_HDR_LEN (60)
|
||||
#define ETH_MAX_IP_DGRAM_LEN (0xFFFF)
|
||||
|
||||
#define IP_FRAG_UNIT_SIZE (8)
|
||||
#define IP_FRAG_ALIGN_SIZE(x) ((x) & ~0x7)
|
||||
#define IP_RF 0x8000 /* reserved fragment flag */
|
||||
#define IP_DF 0x4000 /* don't fragment flag */
|
||||
#define IP_MF 0x2000 /* more fragments flag */
|
||||
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
|
||||
|
||||
#define IP6_EXT_GRANULARITY (8) /* Size granularity for
|
||||
IPv6 extension headers */
|
||||
|
||||
/* IP6 extension header types */
|
||||
#define IP6_HOP_BY_HOP (0)
|
||||
#define IP6_ROUTING (43)
|
||||
#define IP6_FRAGMENT (44)
|
||||
#define IP6_ESP (50)
|
||||
#define IP6_AUTHENTICATION (51)
|
||||
#define IP6_NONE (59)
|
||||
#define IP6_DESTINATON (60)
|
||||
#define IP6_MOBILITY (135)
|
||||
|
||||
static inline int is_multicast_ether_addr(const uint8_t *addr)
|
||||
{
|
||||
return 0x01 & addr[0];
|
||||
}
|
||||
|
||||
static inline int is_broadcast_ether_addr(const uint8_t *addr)
|
||||
{
|
||||
return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff;
|
||||
}
|
||||
|
||||
static inline int is_unicast_ether_addr(const uint8_t *addr)
|
||||
{
|
||||
return !is_multicast_ether_addr(addr);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
ETH_PKT_UCAST = 0xAABBCC00,
|
||||
ETH_PKT_BCAST,
|
||||
ETH_PKT_MCAST
|
||||
} eth_pkt_types_e;
|
||||
|
||||
static inline eth_pkt_types_e
|
||||
get_eth_packet_type(const struct eth_header *ehdr)
|
||||
{
|
||||
if (is_broadcast_ether_addr(ehdr->h_dest)) {
|
||||
return ETH_PKT_BCAST;
|
||||
} else if (is_multicast_ether_addr(ehdr->h_dest)) {
|
||||
return ETH_PKT_MCAST;
|
||||
} else { /* unicast */
|
||||
return ETH_PKT_UCAST;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
eth_get_l2_hdr_length(const void *p)
|
||||
{
|
||||
uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto);
|
||||
struct vlan_header *hvlan = PKT_GET_VLAN_HDR(p);
|
||||
switch (proto) {
|
||||
case ETH_P_VLAN:
|
||||
return sizeof(struct eth_header) + sizeof(struct vlan_header);
|
||||
case ETH_P_DVLAN:
|
||||
if (be16_to_cpu(hvlan->h_proto) == ETH_P_VLAN) {
|
||||
return sizeof(struct eth_header) + 2 * sizeof(struct vlan_header);
|
||||
} else {
|
||||
return sizeof(struct eth_header) + sizeof(struct vlan_header);
|
||||
}
|
||||
default:
|
||||
return sizeof(struct eth_header);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
eth_get_l2_hdr_length_iov(const struct iovec *iov, size_t iovcnt, size_t iovoff)
|
||||
{
|
||||
uint8_t p[sizeof(struct eth_header) + sizeof(struct vlan_header)];
|
||||
size_t copied = iov_to_buf(iov, iovcnt, iovoff, p, ARRAY_SIZE(p));
|
||||
|
||||
if (copied < ARRAY_SIZE(p)) {
|
||||
return copied;
|
||||
}
|
||||
|
||||
return eth_get_l2_hdr_length(p);
|
||||
}
|
||||
|
||||
static inline uint16_t
|
||||
eth_get_pkt_tci(const void *p)
|
||||
{
|
||||
uint16_t proto = be16_to_cpu(PKT_GET_ETH_HDR(p)->h_proto);
|
||||
struct vlan_header *hvlan = PKT_GET_VLAN_HDR(p);
|
||||
switch (proto) {
|
||||
case ETH_P_VLAN:
|
||||
case ETH_P_DVLAN:
|
||||
return be16_to_cpu(hvlan->h_tci);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||
void *new_ehdr_buf,
|
||||
uint16_t *payload_offset, uint16_t *tci);
|
||||
|
||||
size_t
|
||||
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff, int index,
|
||||
uint16_t vet, uint16_t vet_ext, void *new_ehdr_buf,
|
||||
uint16_t *payload_offset, uint16_t *tci);
|
||||
|
||||
uint16_t
|
||||
eth_get_l3_proto(const struct iovec *l2hdr_iov, int iovcnt, size_t l2hdr_len);
|
||||
|
||||
void eth_setup_vlan_headers(struct eth_header *ehdr, size_t *ehdr_size,
|
||||
uint16_t vlan_tag, uint16_t vlan_ethtype);
|
||||
|
||||
|
||||
uint8_t eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto);
|
||||
|
||||
typedef struct eth_ip6_hdr_info_st {
|
||||
uint8_t l4proto;
|
||||
size_t full_hdr_len;
|
||||
struct ip6_header ip6_hdr;
|
||||
bool has_ext_hdrs;
|
||||
bool rss_ex_src_valid;
|
||||
struct in6_address rss_ex_src;
|
||||
bool rss_ex_dst_valid;
|
||||
struct in6_address rss_ex_dst;
|
||||
bool fragment;
|
||||
} eth_ip6_hdr_info;
|
||||
|
||||
typedef struct eth_ip4_hdr_info_st {
|
||||
struct ip_header ip4_hdr;
|
||||
bool fragment;
|
||||
} eth_ip4_hdr_info;
|
||||
|
||||
typedef enum EthL4HdrProto {
|
||||
ETH_L4_HDR_PROTO_INVALID,
|
||||
ETH_L4_HDR_PROTO_TCP,
|
||||
ETH_L4_HDR_PROTO_UDP,
|
||||
ETH_L4_HDR_PROTO_SCTP
|
||||
} EthL4HdrProto;
|
||||
|
||||
typedef struct eth_l4_hdr_info_st {
|
||||
union {
|
||||
struct tcp_header tcp;
|
||||
struct udp_header udp;
|
||||
} hdr;
|
||||
|
||||
EthL4HdrProto proto;
|
||||
bool has_tcp_data;
|
||||
} eth_l4_hdr_info;
|
||||
|
||||
void eth_get_protocols(const struct iovec *iov, size_t iovcnt, size_t iovoff,
|
||||
bool *hasip4, bool *hasip6,
|
||||
size_t *l3hdr_off,
|
||||
size_t *l4hdr_off,
|
||||
size_t *l5hdr_off,
|
||||
eth_ip6_hdr_info *ip6hdr_info,
|
||||
eth_ip4_hdr_info *ip4hdr_info,
|
||||
eth_l4_hdr_info *l4hdr_info);
|
||||
|
||||
void
|
||||
eth_fix_ip4_checksum(void *l3hdr, size_t l3hdr_len);
|
||||
|
||||
uint32_t
|
||||
eth_calc_ip4_pseudo_hdr_csum(struct ip_header *iphdr,
|
||||
uint16_t csl,
|
||||
uint32_t *cso);
|
||||
|
||||
uint32_t
|
||||
eth_calc_ip6_pseudo_hdr_csum(struct ip6_header *iphdr,
|
||||
uint16_t csl,
|
||||
uint8_t l4_proto,
|
||||
uint32_t *cso);
|
||||
|
||||
bool
|
||||
eth_parse_ipv6_hdr(const struct iovec *pkt, int pkt_frags,
|
||||
size_t ip6hdr_off, eth_ip6_hdr_info *info);
|
||||
|
||||
/**
|
||||
* eth_pad_short_frame - pad a short frame to the minimum Ethernet frame length
|
||||
*
|
||||
* If the Ethernet frame size is shorter than 60 bytes, it will be padded to
|
||||
* 60 bytes at the address @padded_pkt.
|
||||
*
|
||||
* @padded_pkt: buffer address to hold the padded frame
|
||||
* @padded_buflen: pointer holding length of @padded_pkt. If the frame is
|
||||
* padded, the length will be updated to the padded one.
|
||||
* @pkt: address to hold the original Ethernet frame
|
||||
* @pkt_size: size of the original Ethernet frame
|
||||
* @return true if the frame is padded, otherwise false
|
||||
*/
|
||||
bool eth_pad_short_frame(uint8_t *padded_pkt, size_t *padded_buflen,
|
||||
const void *pkt, size_t pkt_size);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2015 FUJITSU LIMITED
|
||||
* Author: Yang Hongyang <[email protected]>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
* later. See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_NET_FILTER_H
|
||||
#define QEMU_NET_FILTER_H
|
||||
|
||||
#include "qapi/qapi-types-common.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "qom/object.h"
|
||||
#include "net/queue.h"
|
||||
|
||||
#define TYPE_NETFILTER "netfilter"
|
||||
OBJECT_DECLARE_TYPE(NetFilterState, NetFilterClass, NETFILTER)
|
||||
|
||||
typedef void (FilterSetup) (NetFilterState *nf, Error **errp);
|
||||
typedef void (FilterCleanup) (NetFilterState *nf);
|
||||
/*
|
||||
* Return:
|
||||
* 0: finished handling the packet, we should continue
|
||||
* size: filter stolen this packet, we stop pass this packet further
|
||||
*/
|
||||
typedef ssize_t (FilterReceiveIOV)(NetFilterState *nc,
|
||||
NetClientState *sender,
|
||||
unsigned flags,
|
||||
const struct iovec *iov,
|
||||
int iovcnt,
|
||||
NetPacketSent *sent_cb);
|
||||
|
||||
typedef void (FilterStatusChanged) (NetFilterState *nf, Error **errp);
|
||||
|
||||
typedef void (FilterHandleEvent) (NetFilterState *nf, int event, Error **errp);
|
||||
|
||||
struct NetFilterClass {
|
||||
ObjectClass parent_class;
|
||||
|
||||
/* optional */
|
||||
FilterSetup *setup;
|
||||
FilterCleanup *cleanup;
|
||||
FilterStatusChanged *status_changed;
|
||||
FilterHandleEvent *handle_event;
|
||||
/* mandatory */
|
||||
FilterReceiveIOV *receive_iov;
|
||||
};
|
||||
|
||||
|
||||
struct NetFilterState {
|
||||
/* private */
|
||||
Object parent;
|
||||
|
||||
/* protected */
|
||||
char *netdev_id;
|
||||
NetClientState *netdev;
|
||||
NetFilterDirection direction;
|
||||
bool on;
|
||||
char *position;
|
||||
bool insert_before_flag;
|
||||
QTAILQ_ENTRY(NetFilterState) next;
|
||||
};
|
||||
|
||||
ssize_t qemu_netfilter_receive(NetFilterState *nf,
|
||||
NetFilterDirection direction,
|
||||
NetClientState *sender,
|
||||
unsigned flags,
|
||||
const struct iovec *iov,
|
||||
int iovcnt,
|
||||
NetPacketSent *sent_cb);
|
||||
|
||||
/* pass the packet to the next filter */
|
||||
ssize_t qemu_netfilter_pass_to_next(NetClientState *sender,
|
||||
unsigned flags,
|
||||
const struct iovec *iov,
|
||||
int iovcnt,
|
||||
void *opaque);
|
||||
|
||||
void colo_notify_filters_event(int event, Error **errp);
|
||||
|
||||
#endif /* QEMU_NET_FILTER_H */
|
||||
@@ -0,0 +1,380 @@
|
||||
#ifndef QEMU_NET_H
|
||||
#define QEMU_NET_H
|
||||
|
||||
#include "qemu/queue.h"
|
||||
#include "qapi/qapi-types-net.h"
|
||||
#include "net/queue.h"
|
||||
#include "hw/core/qdev-properties-system.h"
|
||||
|
||||
#define MAC_FMT "%02X:%02X:%02X:%02X:%02X:%02X"
|
||||
#define MAC_ARG(x) ((uint8_t *)(x))[0], ((uint8_t *)(x))[1], \
|
||||
((uint8_t *)(x))[2], ((uint8_t *)(x))[3], \
|
||||
((uint8_t *)(x))[4], ((uint8_t *)(x))[5]
|
||||
|
||||
#define MAX_QUEUE_NUM 1024
|
||||
|
||||
/* Maximum GSO packet size (64k) plus plenty of room for
|
||||
* the ethernet and virtio_net headers
|
||||
*/
|
||||
#define NET_BUFSIZE (4096 + 65536)
|
||||
|
||||
struct MACAddr {
|
||||
uint8_t a[6];
|
||||
};
|
||||
|
||||
/* qdev nic properties */
|
||||
|
||||
typedef struct NICPeers {
|
||||
NetClientState *ncs[MAX_QUEUE_NUM];
|
||||
int32_t queues;
|
||||
} NICPeers;
|
||||
|
||||
typedef struct NICConf {
|
||||
MACAddr macaddr;
|
||||
NICPeers peers;
|
||||
int32_t bootindex;
|
||||
} NICConf;
|
||||
|
||||
typedef struct NetOffloads {
|
||||
bool csum;
|
||||
bool tso4;
|
||||
bool tso6;
|
||||
bool ecn;
|
||||
bool ufo;
|
||||
bool uso4;
|
||||
bool uso6;
|
||||
bool tnl;
|
||||
bool tnl_csum;
|
||||
} NetOffloads;
|
||||
|
||||
#define DEFINE_NIC_PROPERTIES(_state, _conf) \
|
||||
DEFINE_PROP_MACADDR("mac", _state, _conf.macaddr), \
|
||||
DEFINE_PROP_NETDEV("netdev", _state, _conf.peers)
|
||||
|
||||
|
||||
/* Net clients */
|
||||
|
||||
typedef void (NetPoll)(NetClientState *, bool enable);
|
||||
typedef bool (NetCanReceive)(NetClientState *);
|
||||
typedef int (NetStart)(NetClientState *);
|
||||
typedef int (NetLoad)(NetClientState *);
|
||||
typedef void (NetStop)(NetClientState *);
|
||||
typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t);
|
||||
typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int);
|
||||
typedef void (NetCleanup) (NetClientState *);
|
||||
typedef void (LinkStatusChanged)(NetClientState *);
|
||||
typedef void (NetClientDestructor)(NetClientState *);
|
||||
typedef RxFilterInfo *(QueryRxFilter)(NetClientState *);
|
||||
typedef bool (HasUfo)(NetClientState *);
|
||||
typedef bool (HasUso)(NetClientState *);
|
||||
typedef bool (HasTunnel)(NetClientState *);
|
||||
typedef bool (HasVnetHdr)(NetClientState *);
|
||||
typedef bool (HasVnetHdrLen)(NetClientState *, int);
|
||||
typedef void (SetOffload)(NetClientState *, const NetOffloads *);
|
||||
typedef int (GetVnetHdrLen)(NetClientState *);
|
||||
typedef void (SetVnetHdrLen)(NetClientState *, int);
|
||||
typedef bool (GetVnetHashSupportedTypes)(NetClientState *, uint32_t *);
|
||||
typedef int (SetVnetLE)(NetClientState *, bool);
|
||||
typedef int (SetVnetBE)(NetClientState *, bool);
|
||||
typedef struct SocketReadState SocketReadState;
|
||||
typedef void (SocketReadStateFinalize)(SocketReadState *rs);
|
||||
typedef void (NetAnnounce)(NetClientState *);
|
||||
typedef bool (SetSteeringEBPF)(NetClientState *, int);
|
||||
typedef bool (NetCheckPeerType)(NetClientState *, ObjectClass *, Error **);
|
||||
typedef struct vhost_net *(GetVHostNet)(NetClientState *nc);
|
||||
|
||||
typedef struct NetClientInfo {
|
||||
NetClientDriver type;
|
||||
size_t size;
|
||||
NetReceive *receive;
|
||||
NetReceiveIOV *receive_iov;
|
||||
NetCanReceive *can_receive;
|
||||
NetStart *start;
|
||||
NetLoad *load;
|
||||
NetStop *stop;
|
||||
NetCleanup *cleanup;
|
||||
LinkStatusChanged *link_status_changed;
|
||||
QueryRxFilter *query_rx_filter;
|
||||
NetPoll *poll;
|
||||
HasUfo *has_ufo;
|
||||
HasUso *has_uso;
|
||||
HasTunnel *has_tunnel;
|
||||
HasVnetHdr *has_vnet_hdr;
|
||||
HasVnetHdrLen *has_vnet_hdr_len;
|
||||
SetOffload *set_offload;
|
||||
SetVnetHdrLen *set_vnet_hdr_len;
|
||||
SetVnetLE *set_vnet_le;
|
||||
SetVnetBE *set_vnet_be;
|
||||
GetVnetHashSupportedTypes *get_vnet_hash_supported_types;
|
||||
NetAnnounce *announce;
|
||||
SetSteeringEBPF *set_steering_ebpf;
|
||||
NetCheckPeerType *check_peer_type;
|
||||
GetVHostNet *get_vhost_net;
|
||||
} NetClientInfo;
|
||||
|
||||
struct NetClientState {
|
||||
NetClientInfo *info;
|
||||
int link_down;
|
||||
QTAILQ_ENTRY(NetClientState) next;
|
||||
NetClientState *peer;
|
||||
NetQueue *incoming_queue;
|
||||
char *model;
|
||||
char *name;
|
||||
char info_str[256];
|
||||
unsigned receive_disabled : 1;
|
||||
NetClientDestructor *destructor;
|
||||
unsigned int queue_index;
|
||||
unsigned rxfilter_notify_enabled:1;
|
||||
int vring_enable;
|
||||
int vnet_hdr_len;
|
||||
bool is_netdev;
|
||||
bool do_not_pad; /* do not pad to the minimum ethernet frame length */
|
||||
bool is_datapath;
|
||||
QTAILQ_HEAD(, NetFilterState) filters;
|
||||
};
|
||||
|
||||
typedef QTAILQ_HEAD(NetClientStateList, NetClientState) NetClientStateList;
|
||||
|
||||
typedef struct NICState {
|
||||
NetClientState *ncs;
|
||||
NICConf *conf;
|
||||
MemReentrancyGuard *reentrancy_guard;
|
||||
void *opaque;
|
||||
bool peer_deleted;
|
||||
} NICState;
|
||||
|
||||
struct SocketReadState {
|
||||
/* 0 = getting length, 1 = getting vnet header length, 2 = getting data */
|
||||
int state;
|
||||
/* This flag decide whether to read the vnet_hdr_len field */
|
||||
bool vnet_hdr;
|
||||
uint32_t index;
|
||||
uint32_t packet_len;
|
||||
uint32_t vnet_hdr_len;
|
||||
uint8_t buf[NET_BUFSIZE];
|
||||
SocketReadStateFinalize *finalize;
|
||||
};
|
||||
|
||||
int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size);
|
||||
char *qemu_mac_strdup_printf(const uint8_t *macaddr);
|
||||
NetClientState *qemu_find_netdev(const char *id);
|
||||
int qemu_find_net_clients_except(const char *id, NetClientState **ncs,
|
||||
NetClientDriver type, int max);
|
||||
NetClientState *qemu_new_net_client(NetClientInfo *info,
|
||||
NetClientState *peer,
|
||||
const char *model,
|
||||
const char *name);
|
||||
NetClientState *qemu_new_net_control_client(NetClientInfo *info,
|
||||
NetClientState *peer,
|
||||
const char *model,
|
||||
const char *name);
|
||||
NICState *qemu_new_nic(NetClientInfo *info,
|
||||
NICConf *conf,
|
||||
const char *model,
|
||||
const char *name,
|
||||
MemReentrancyGuard *reentrancy_guard,
|
||||
void *opaque);
|
||||
void qemu_del_nic(NICState *nic);
|
||||
NetClientState *qemu_get_subqueue(NICState *nic, int queue_index);
|
||||
NetClientState *qemu_get_queue(NICState *nic);
|
||||
NICState *qemu_get_nic(NetClientState *nc);
|
||||
void *qemu_get_nic_opaque(NetClientState *nc);
|
||||
void qemu_del_net_client(NetClientState *nc);
|
||||
typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque);
|
||||
void qemu_foreach_nic(qemu_nic_foreach func, void *opaque);
|
||||
int qemu_can_receive_packet(NetClientState *nc);
|
||||
int qemu_can_send_packet(NetClientState *nc);
|
||||
ssize_t qemu_sendv_packet(NetClientState *nc, const struct iovec *iov,
|
||||
int iovcnt);
|
||||
ssize_t qemu_sendv_packet_async(NetClientState *nc, const struct iovec *iov,
|
||||
int iovcnt, NetPacketSent *sent_cb);
|
||||
ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size);
|
||||
ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size);
|
||||
ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size);
|
||||
ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf,
|
||||
int size, NetPacketSent *sent_cb);
|
||||
void qemu_purge_queued_packets(NetClientState *nc);
|
||||
void qemu_flush_queued_packets(NetClientState *nc);
|
||||
void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge);
|
||||
void qemu_set_info_str(NetClientState *nc,
|
||||
const char *fmt, ...) G_GNUC_PRINTF(2, 3);
|
||||
void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]);
|
||||
bool qemu_has_ufo(NetClientState *nc);
|
||||
bool qemu_has_uso(NetClientState *nc);
|
||||
bool qemu_has_tunnel(NetClientState *nc);
|
||||
bool qemu_has_vnet_hdr(NetClientState *nc);
|
||||
bool qemu_has_vnet_hdr_len(NetClientState *nc, int len);
|
||||
void qemu_set_offload(NetClientState *nc, const NetOffloads *ol);
|
||||
int qemu_get_vnet_hdr_len(NetClientState *nc);
|
||||
void qemu_set_vnet_hdr_len(NetClientState *nc, int len);
|
||||
bool qemu_get_vnet_hash_supported_types(NetClientState *nc, uint32_t *types);
|
||||
int qemu_set_vnet_le(NetClientState *nc, bool is_le);
|
||||
int qemu_set_vnet_be(NetClientState *nc, bool is_be);
|
||||
void qemu_macaddr_default_if_unset(MACAddr *macaddr);
|
||||
/**
|
||||
* qemu_find_nic_info: Obtain NIC configuration information
|
||||
* @typename: Name of device object type
|
||||
* @match_default: Match NIC configurations with no model specified
|
||||
* @alias: Additional model string to match (for user convenience and
|
||||
* backward compatibility).
|
||||
*
|
||||
* Search for a NIC configuration matching the NIC model constraints.
|
||||
*/
|
||||
NICInfo *qemu_find_nic_info(const char *typename, bool match_default,
|
||||
const char *alias);
|
||||
/**
|
||||
* qemu_configure_nic_device: Apply NIC configuration to a given device
|
||||
* @dev: Network device to be configured
|
||||
* @match_default: Match NIC configurations with no model specified
|
||||
* @alias: Additional model string to match
|
||||
*
|
||||
* Search for a NIC configuration for the provided device, using the
|
||||
* additionally specified matching constraints. If found, apply the
|
||||
* configuration using qdev_set_nic_properties() and return %true.
|
||||
*
|
||||
* This is used by platform code which creates the device anyway,
|
||||
* regardless of whether there is a configuration for it. This tends
|
||||
* to be platforms which ignore `--nodefaults` and create net devices
|
||||
* anyway, for example because the Ethernet device on that board is
|
||||
* always physically present.
|
||||
*/
|
||||
bool qemu_configure_nic_device(DeviceState *dev, bool match_default,
|
||||
const char *alias);
|
||||
|
||||
/**
|
||||
* qemu_create_nic_device: Create a NIC device if a configuration exists for it
|
||||
* @typename: Object typename of network device
|
||||
* @match_default: Match NIC configurations with no model specified
|
||||
* @alias: Additional model string to match
|
||||
*
|
||||
* Search for a NIC configuration for the provided device type. If found,
|
||||
* create an object of the corresponding type and return it.
|
||||
*/
|
||||
DeviceState *qemu_create_nic_device(const char *typename, bool match_default,
|
||||
const char *alias);
|
||||
|
||||
/*
|
||||
* qemu_create_nic_bus_devices: Create configured NIC devices for a given bus
|
||||
* @bus: Bus on which to create devices
|
||||
* @parent_type: Object type for devices to be created (e.g. TYPE_PCI_DEVICE)
|
||||
* @default_model: Object type name for default NIC model (or %NULL)
|
||||
* @alias: Additional model string to replace, for user convenience
|
||||
* @alias_target: Actual object type name to be used in place of @alias
|
||||
*
|
||||
* Instantiate dynamic NICs on a given bus, typically a PCI bus. This scans
|
||||
* for available NIC configurations which either specify a model which is
|
||||
* a child type of @parent_type, or which do not specify a model when
|
||||
* @default_model is non-NULL. Each device is instantiated on the given @bus.
|
||||
*
|
||||
* A single substitution is supported, e.g. "xen" → "xen-net-device" for the
|
||||
* Xen bus, or "virtio" → "virtio-net-pci" for PCI. This allows the user to
|
||||
* specify a more understandable "model=" parameter on the command line, not
|
||||
* only the real object typename.
|
||||
*/
|
||||
void qemu_create_nic_bus_devices(BusState *bus, const char *parent_type,
|
||||
const char *default_model,
|
||||
const char *alias, const char *alias_target);
|
||||
void print_net_client(Monitor *mon, NetClientState *nc);
|
||||
void net_socket_rs_init(SocketReadState *rs,
|
||||
SocketReadStateFinalize *finalize,
|
||||
bool vnet_hdr);
|
||||
NetClientState *qemu_get_peer(NetClientState *nc, int queue_index);
|
||||
|
||||
/**
|
||||
* qemu_get_nic_models:
|
||||
* @device_type: Defines which devices should be taken into consideration
|
||||
* (e.g. TYPE_DEVICE for all devices, or TYPE_PCI_DEVICE for PCI)
|
||||
*
|
||||
* Get an array of pointers to names of NIC devices that are available in
|
||||
* the QEMU binary. The array is terminated with a NULL pointer entry.
|
||||
* The caller is responsible for freeing the memory when it is not required
|
||||
* anymore, e.g. with g_ptr_array_free(..., true).
|
||||
*
|
||||
* Returns: Pointer to the array that contains the pointers to the names.
|
||||
*/
|
||||
GPtrArray *qemu_get_nic_models(const char *device_type);
|
||||
|
||||
/* NIC info */
|
||||
|
||||
#define MAX_NICS 8
|
||||
|
||||
struct NICInfo {
|
||||
MACAddr macaddr;
|
||||
char *model;
|
||||
char *name;
|
||||
char *devaddr;
|
||||
NetClientState *netdev;
|
||||
int used; /* is this slot in nd_table[] being used? */
|
||||
int instantiated; /* does this NICInfo correspond to an instantiated NIC? */
|
||||
int nvectors;
|
||||
};
|
||||
|
||||
/* from net.c */
|
||||
extern NetClientStateList net_clients;
|
||||
bool netdev_is_modern(const char *optstr);
|
||||
void netdev_parse_modern(const char *optstr);
|
||||
void net_client_parse(QemuOptsList *opts_list, const char *optstr);
|
||||
void show_netdevs(void);
|
||||
void net_init_clients(void);
|
||||
void net_check_clients(void);
|
||||
void net_client_set_link(NetClientState **ncs, int queues, bool up);
|
||||
void net_cleanup(void);
|
||||
void hmp_host_net_add(Monitor *mon, const QDict *qdict);
|
||||
void hmp_host_net_remove(Monitor *mon, const QDict *qdict);
|
||||
void netdev_add(QemuOpts *opts, Error **errp);
|
||||
|
||||
int net_hub_id_for_client(NetClientState *nc, int *id);
|
||||
|
||||
#define DEFAULT_NETWORK_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifup"
|
||||
#define DEFAULT_NETWORK_DOWN_SCRIPT CONFIG_SYSCONFDIR "/qemu-ifdown"
|
||||
#define DEFAULT_BRIDGE_HELPER CONFIG_QEMU_HELPERDIR "/qemu-bridge-helper"
|
||||
#define DEFAULT_BRIDGE_INTERFACE "br0"
|
||||
|
||||
void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd);
|
||||
|
||||
#define POLYNOMIAL_BE 0x04c11db6
|
||||
#define POLYNOMIAL_LE 0xedb88320
|
||||
uint32_t net_crc32(const uint8_t *p, int len);
|
||||
uint32_t net_crc32_le(const uint8_t *p, int len);
|
||||
|
||||
#define vmstate_offset_macaddr(_state, _field) \
|
||||
vmstate_offset_array(_state, _field.a, uint8_t, \
|
||||
sizeof(typeof_field(_state, _field)))
|
||||
|
||||
#define VMSTATE_MACADDR(_field, _state) { \
|
||||
.name = (stringify(_field)), \
|
||||
.size = sizeof(MACAddr), \
|
||||
.info = &vmstate_info_buffer, \
|
||||
.flags = VMS_BUFFER, \
|
||||
.offset = vmstate_offset_macaddr(_state, _field), \
|
||||
}
|
||||
|
||||
/**
|
||||
* net_peer_needs_padding: Should we pad as we send out packets?
|
||||
* @nc: NetClientState
|
||||
*
|
||||
* Return true if the peer of this NetClientState (i.e. the
|
||||
* destination that qemu_send_packet() etc send to) requires us to pad
|
||||
* out packets that are shorter than the minimum ethernet frame
|
||||
* length.
|
||||
*/
|
||||
static inline bool net_peer_needs_padding(NetClientState *nc)
|
||||
{
|
||||
return nc->peer && !nc->peer->do_not_pad;
|
||||
}
|
||||
|
||||
/**
|
||||
* net_client_needs_padding: Should we pad as we queue packets to ourselves?
|
||||
* @nc: NetClientState
|
||||
*
|
||||
* Return true if this NetClientState requires us to pad out packets
|
||||
* that are shorter than the minimum ethernet frame length. This is
|
||||
* the check to make in qemu_receive_packet() when we are queuing a
|
||||
* packet back into ourselves (i.e. loopback).
|
||||
*/
|
||||
static inline bool net_client_needs_padding(NetClientState *nc)
|
||||
{
|
||||
return !nc->do_not_pad;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2009 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_NET_QUEUE_H
|
||||
#define QEMU_NET_QUEUE_H
|
||||
|
||||
|
||||
typedef struct NetPacket NetPacket;
|
||||
typedef struct NetQueue NetQueue;
|
||||
|
||||
typedef void (NetPacketSent) (NetClientState *sender, ssize_t ret);
|
||||
|
||||
#define QEMU_NET_PACKET_FLAG_NONE 0
|
||||
#define QEMU_NET_PACKET_FLAG_RAW (1<<0)
|
||||
|
||||
/* Returns:
|
||||
* >0 - success
|
||||
* 0 - queue packet for future redelivery
|
||||
* <0 - failure (discard packet)
|
||||
*/
|
||||
typedef ssize_t (NetQueueDeliverFunc)(NetClientState *sender,
|
||||
unsigned flags,
|
||||
const struct iovec *iov,
|
||||
int iovcnt,
|
||||
void *opaque);
|
||||
|
||||
NetQueue *qemu_new_net_queue(NetQueueDeliverFunc *deliver, void *opaque);
|
||||
|
||||
void qemu_net_queue_append_iov(NetQueue *queue,
|
||||
NetClientState *sender,
|
||||
unsigned flags,
|
||||
const struct iovec *iov,
|
||||
int iovcnt,
|
||||
NetPacketSent *sent_cb);
|
||||
|
||||
void qemu_del_net_queue(NetQueue *queue);
|
||||
|
||||
ssize_t qemu_net_queue_receive(NetQueue *queue,
|
||||
const uint8_t *data,
|
||||
size_t size);
|
||||
|
||||
ssize_t qemu_net_queue_send(NetQueue *queue,
|
||||
NetClientState *sender,
|
||||
unsigned flags,
|
||||
const uint8_t *data,
|
||||
size_t size,
|
||||
NetPacketSent *sent_cb);
|
||||
|
||||
ssize_t qemu_net_queue_send_iov(NetQueue *queue,
|
||||
NetClientState *sender,
|
||||
unsigned flags,
|
||||
const struct iovec *iov,
|
||||
int iovcnt,
|
||||
NetPacketSent *sent_cb);
|
||||
|
||||
void qemu_net_queue_purge(NetQueue *queue, NetClientState *from);
|
||||
bool qemu_net_queue_flush(NetQueue *queue);
|
||||
|
||||
#endif /* QEMU_NET_QUEUE_H */
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* QEMU System Emulator
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef QEMU_NET_SLIRP_H
|
||||
#define QEMU_NET_SLIRP_H
|
||||
|
||||
|
||||
#ifdef CONFIG_SLIRP
|
||||
|
||||
void hmp_hostfwd_add(Monitor *mon, const QDict *qdict);
|
||||
void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict);
|
||||
|
||||
void hmp_info_usernet(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* QEMU_NET_SLIRP_H */
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* QEMU System Emulator
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2009 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_NET_TAP_H
|
||||
#define QEMU_NET_TAP_H
|
||||
|
||||
#include "standard-headers/linux/virtio_net.h"
|
||||
|
||||
int tap_enable(NetClientState *nc);
|
||||
int tap_disable(NetClientState *nc);
|
||||
|
||||
int tap_get_fd(NetClientState *nc);
|
||||
|
||||
#endif /* QEMU_NET_TAP_H */
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* vhost-vdpa.h
|
||||
*
|
||||
* Copyright(c) 2017-2018 Intel Corporation.
|
||||
* Copyright(c) 2020 Red Hat, Inc.
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VHOST_VDPA_H
|
||||
#define VHOST_VDPA_H
|
||||
|
||||
#define TYPE_VHOST_VDPA "vhost-vdpa"
|
||||
|
||||
#endif /* VHOST_VDPA_H */
|
||||
@@ -0,0 +1,91 @@
|
||||
#ifndef VHOST_NET_H
|
||||
#define VHOST_NET_H
|
||||
|
||||
#include "net/net.h"
|
||||
#include "hw/virtio/virtio-features.h"
|
||||
#include "hw/virtio/vhost-backend.h"
|
||||
|
||||
struct vhost_net;
|
||||
typedef struct vhost_net VHostNetState;
|
||||
|
||||
typedef uint64_t (GetAckedFeatures)(NetClientState *nc);
|
||||
typedef void (SaveAcketFeatures)(NetClientState *nc);
|
||||
|
||||
typedef struct VhostNetOptions {
|
||||
VhostBackendType backend_type;
|
||||
NetClientState *net_backend;
|
||||
uint32_t busyloop_timeout;
|
||||
unsigned int nvqs;
|
||||
const int *feature_bits;
|
||||
int max_tx_queue_size;
|
||||
bool is_vhost_user;
|
||||
GetAckedFeatures *get_acked_features;
|
||||
SaveAcketFeatures *save_acked_features;
|
||||
void *opaque;
|
||||
} VhostNetOptions;
|
||||
|
||||
uint64_t vhost_net_get_max_queues(VHostNetState *net);
|
||||
struct vhost_net *vhost_net_init(VhostNetOptions *options);
|
||||
|
||||
int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
|
||||
int data_queue_pairs, int cvq);
|
||||
void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
|
||||
int data_queue_pairs, int cvq);
|
||||
|
||||
void vhost_net_cleanup(VHostNetState *net);
|
||||
|
||||
void vhost_net_get_features_ex(VHostNetState *net, uint64_t *features);
|
||||
static inline uint64_t vhost_net_get_features(VHostNetState *net,
|
||||
uint64_t features)
|
||||
{
|
||||
uint64_t features_array[VIRTIO_FEATURES_NU64S];
|
||||
|
||||
virtio_features_from_u64(features_array, features);
|
||||
vhost_net_get_features_ex(net, features_array);
|
||||
return features_array[0];
|
||||
}
|
||||
|
||||
void vhost_net_ack_features_ex(VHostNetState *net, const uint64_t *features);
|
||||
static inline void vhost_net_ack_features(VHostNetState *net,
|
||||
uint64_t features)
|
||||
{
|
||||
uint64_t features_array[VIRTIO_FEATURES_NU64S];
|
||||
|
||||
virtio_features_from_u64(features_array, features);
|
||||
vhost_net_ack_features_ex(net, features_array);
|
||||
}
|
||||
|
||||
int vhost_net_get_config(struct vhost_net *net, uint8_t *config,
|
||||
uint32_t config_len);
|
||||
|
||||
int vhost_net_set_config(struct vhost_net *net, const uint8_t *data,
|
||||
uint32_t offset, uint32_t size, uint32_t flags);
|
||||
bool vhost_net_virtqueue_pending(VHostNetState *net, int n);
|
||||
void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
|
||||
int idx, bool mask);
|
||||
bool vhost_net_config_pending(VHostNetState *net);
|
||||
void vhost_net_config_mask(VHostNetState *net, VirtIODevice *dev, bool mask);
|
||||
int vhost_net_notify_migration_done(VHostNetState *net, char* mac_addr);
|
||||
VHostNetState *get_vhost_net(NetClientState *nc);
|
||||
|
||||
int vhost_net_set_vring_enable(NetClientState *nc, int enable);
|
||||
|
||||
void vhost_net_get_acked_features_ex(VHostNetState *net, uint64_t *features);
|
||||
static inline uint64_t vhost_net_get_acked_features(VHostNetState *net)
|
||||
{
|
||||
uint64_t features[VIRTIO_FEATURES_NU64S];
|
||||
|
||||
vhost_net_get_acked_features_ex(net, features);
|
||||
assert(!virtio_features_use_ex(features));
|
||||
return features[0];
|
||||
}
|
||||
|
||||
int vhost_net_set_mtu(struct vhost_net *net, uint16_t mtu);
|
||||
|
||||
void vhost_net_virtqueue_reset(VirtIODevice *vdev, NetClientState *nc,
|
||||
int vq_index);
|
||||
int vhost_net_virtqueue_restart(VirtIODevice *vdev, NetClientState *nc,
|
||||
int vq_index);
|
||||
|
||||
void vhost_net_save_acked_features(NetClientState *nc);
|
||||
#endif
|
||||
Reference in new issue
Block a user