mirror of
https://github.com/open-simh/simh.git
synced 2026-01-25 19:57:36 +00:00
all VAX, PDP11: Add initial NAT based ethernet connectivity via SLiRP.
This should work on all byte addressable host systems using GCC/clang to build. The QEMU slirp code has been pried out of QEMU and stubs have been created to solve where the current slirp is entangled with the QEMU code. Ths slirp/simh directory contains all the necessary include and glue files to make this useful. Everything in the slirp directory is unmodified QEMU code.
This commit is contained in:
258
sim_ether.c
258
sim_ether.c
@@ -150,6 +150,9 @@
|
||||
specified at open time. This functionality is only
|
||||
available on *nix platforms since the vde api isn't
|
||||
available on Windows.
|
||||
HAVE_SLIRP_NETWORK- Specifies that support for SLiRP networking should be
|
||||
included. This can be leveraged to provide User Mode
|
||||
IP NAT connectivity for simulators.
|
||||
|
||||
NEED_PCAP_SENDPACKET
|
||||
- Specifies that you are using an older version of libpcap
|
||||
@@ -884,7 +887,7 @@ void eth_show_dev (FILE* st, ETH_DEV* dev)
|
||||
|
||||
const char *eth_capabilities(void)
|
||||
{
|
||||
return "Ethernet Packet transport"
|
||||
return "Ethernet Packet transports"
|
||||
#if defined (HAVE_PCAP_NETWORK)
|
||||
":PCAP"
|
||||
#endif
|
||||
@@ -893,6 +896,9 @@ const char *eth_capabilities(void)
|
||||
#endif
|
||||
#if defined (HAVE_VDE_NETWORK)
|
||||
":VDE"
|
||||
#endif
|
||||
#if defined (HAVE_SLIRP_NETWORK)
|
||||
":NAT"
|
||||
#endif
|
||||
":UDP";
|
||||
}
|
||||
@@ -938,6 +944,10 @@ typedef void * pcap_t; /* Pseudo Type to avoid compiler errors */
|
||||
#include <libvdeplug.h>
|
||||
#endif /* HAVE_VDE_NETWORK */
|
||||
|
||||
#ifdef HAVE_SLIRP_NETWORK
|
||||
#include "sim_slirp.h"
|
||||
#endif /* HAVE_SLIRP_NETWORK */
|
||||
|
||||
/* Allows windows to look up user-defined adapter names */
|
||||
#if defined(_WIN32)
|
||||
#include <winreg.h>
|
||||
@@ -1495,6 +1505,17 @@ _eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine);
|
||||
static void
|
||||
_eth_error(ETH_DEV* dev, const char* where);
|
||||
|
||||
#if defined(HAVE_SLIRP_NETWORK)
|
||||
static void _slirp_callback (void *opaque, const unsigned char *buf, int len)
|
||||
{
|
||||
struct pcap_pkthdr header;
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.caplen = header.len = len;
|
||||
_eth_callback((u_char *)opaque, &header, buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (USE_READER_THREAD)
|
||||
#include <pthread.h>
|
||||
|
||||
@@ -1524,6 +1545,7 @@ switch (dev->eth_api) {
|
||||
case ETH_API_TAP:
|
||||
case ETH_API_VDE:
|
||||
case ETH_API_UDP:
|
||||
case ETH_API_NAT:
|
||||
do_select = 1;
|
||||
select_fd = dev->fd_handle;
|
||||
break;
|
||||
@@ -1532,8 +1554,8 @@ switch (dev->eth_api) {
|
||||
sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n");
|
||||
|
||||
/* Boost Priority for this I/O thread vs the CPU instruction execution
|
||||
thread which in general won't be readily yielding the processor when
|
||||
this thread needs to run */
|
||||
thread which, in general, won't be readily yielding the processor
|
||||
when this thread needs to run */
|
||||
pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority);
|
||||
++sched_priority.sched_priority;
|
||||
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
|
||||
@@ -1544,22 +1566,31 @@ while (dev->handle) {
|
||||
if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250))
|
||||
sel_ret = 1;
|
||||
}
|
||||
if (dev->eth_api == ETH_API_UDP)
|
||||
if ((dev->eth_api == ETH_API_UDP) || (dev->eth_api == ETH_API_NAT))
|
||||
#endif /* _WIN32 */
|
||||
if (1) {
|
||||
fd_set setl;
|
||||
struct timeval timeout;
|
||||
|
||||
if (do_select) {
|
||||
FD_ZERO(&setl);
|
||||
FD_SET(select_fd, &setl);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 250*1000;
|
||||
sel_ret = select(1+select_fd, &setl, NULL, NULL, &timeout);
|
||||
#ifdef HAVE_SLIRP_NETWORK
|
||||
if (dev->eth_api == ETH_API_NAT) {
|
||||
sel_ret = sim_slirp_select ((SLIRP*)dev->handle, 250);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fd_set setl;
|
||||
struct timeval timeout;
|
||||
|
||||
FD_ZERO(&setl);
|
||||
FD_SET(select_fd, &setl);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 250*1000;
|
||||
sel_ret = select(1+select_fd, &setl, NULL, NULL, &timeout);
|
||||
}
|
||||
}
|
||||
else
|
||||
sel_ret = 1;
|
||||
if (sel_ret < 0 && errno != EINTR) break;
|
||||
if (sel_ret < 0 && errno != EINTR)
|
||||
break;
|
||||
}
|
||||
if (sel_ret > 0) {
|
||||
if (!dev->handle)
|
||||
@@ -1617,6 +1648,11 @@ while (dev->handle) {
|
||||
}
|
||||
break;
|
||||
#endif /* HAVE_VDE_NETWORK */
|
||||
#ifdef HAVE_SLIRP_NETWORK
|
||||
case ETH_API_NAT:
|
||||
sim_slirp_dispatch ((SLIRP*)dev->handle);
|
||||
break;
|
||||
#endif /* HAVE_SLIRP_NETWORK */
|
||||
case ETH_API_UDP:
|
||||
if (1) {
|
||||
struct pcap_pkthdr header;
|
||||
@@ -1769,7 +1805,7 @@ dev->throttle_mask = (1 << dev->throttle_burst) - 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static t_stat _eth_open_port(char *savname, int *eth_api, void **handle, SOCKET *fd_handle, char errbuf[PCAP_ERRBUF_SIZE], char *bpf_filter)
|
||||
static t_stat _eth_open_port(char *savname, int *eth_api, void **handle, SOCKET *fd_handle, char errbuf[PCAP_ERRBUF_SIZE], char *bpf_filter, void *opaque)
|
||||
{
|
||||
int bufsz = (BUFSIZ < ETH_MAX_PACKET) ? ETH_MAX_PACKET : BUFSIZ;
|
||||
|
||||
@@ -1789,7 +1825,7 @@ if (0 == strncmp("tap:", savname, 4)) {
|
||||
#if defined(HAVE_TAP_NETWORK)
|
||||
if (!strcmp(savname, "tap:tapN")) {
|
||||
sim_printf ("Eth: Must specify actual tap device name (i.e. tap:tap0)\r\n");
|
||||
return SCPE_OPENERR;
|
||||
return SCPE_OPENERR | SCPE_NOMESSAGE;
|
||||
}
|
||||
#endif
|
||||
#if (defined(__linux) || defined(__linux__)) && defined(HAVE_TAP_NETWORK)
|
||||
@@ -1865,7 +1901,7 @@ if (0 == strncmp("tap:", savname, 4)) {
|
||||
*handle = (void *)1; /* Flag used to indicated open */
|
||||
}
|
||||
}
|
||||
else
|
||||
else { /* !tap: */
|
||||
if (0 == strncmp("vde:", savname, 4)) {
|
||||
#if defined(HAVE_VDE_NETWORK)
|
||||
struct vde_open_args voa;
|
||||
@@ -1873,7 +1909,7 @@ else
|
||||
memset(&voa, 0, sizeof(voa));
|
||||
if (!strcmp(savname, "vde:vdedevice")) {
|
||||
sim_printf ("Eth: Must specify actual vde device name (i.e. vde:/tmp/switch)\r\n");
|
||||
return SCPE_OPENERR;
|
||||
return SCPE_OPENERR | SCPE_NOMESSAGE;
|
||||
}
|
||||
if (!(*handle = (void*) vde_open(savname+4, "simh", &voa)))
|
||||
strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
|
||||
@@ -1885,76 +1921,91 @@ else
|
||||
strncpy(errbuf, "No support for vde: network devices", PCAP_ERRBUF_SIZE-1);
|
||||
#endif /* defined(HAVE_VDE_NETWORK) */
|
||||
}
|
||||
else {
|
||||
if (0 == strncmp("udp:", savname, 4)) {
|
||||
char localport[CBUFSIZE], host[CBUFSIZE], port[CBUFSIZE];
|
||||
char hostport[2*CBUFSIZE];
|
||||
|
||||
if (!strcmp(savname, "udp:sourceport:remotehost:remoteport")) {
|
||||
sim_printf ("Eth: Must specify actual udp host and ports(i.e. udp:1224:somehost.com:2234)\r\n");
|
||||
return SCPE_OPENERR;
|
||||
else { /* !vde: */
|
||||
if (0 == strncmp("nat:", savname, 4)) {
|
||||
#if defined(HAVE_SLIRP_NETWORK)
|
||||
if (!(*handle = (void*) sim_slirp_open(savname+4, opaque, &_slirp_callback)))
|
||||
strncpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE-1);
|
||||
else {
|
||||
*eth_api = ETH_API_NAT;
|
||||
*fd_handle = 0;
|
||||
}
|
||||
|
||||
if (SCPE_OK != sim_parse_addr_ex (savname+4, host, sizeof(host), "localhost", port, sizeof(port), localport, sizeof(localport), NULL))
|
||||
return SCPE_OPENERR;
|
||||
|
||||
if (localport[0] == '\0')
|
||||
strcpy (localport, port);
|
||||
sprintf (hostport, "%s:%s", host, port);
|
||||
if ((SCPE_OK == sim_parse_addr (hostport, NULL, 0, NULL, NULL, 0, NULL, "localhost")) &&
|
||||
(0 == strcmp (localport, port))) {
|
||||
sim_printf ("Eth: Must specify different udp localhost ports\r\n");
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
*fd_handle = sim_connect_sock_ex (localport, hostport, NULL, NULL, SIM_SOCK_OPT_DATAGRAM);
|
||||
if (INVALID_SOCKET == *fd_handle)
|
||||
return SCPE_OPENERR;
|
||||
*eth_api = ETH_API_UDP;
|
||||
*handle = (void *)1; /* Flag used to indicated open */
|
||||
#else
|
||||
strncpy(errbuf, "No support for nat: network devices", PCAP_ERRBUF_SIZE-1);
|
||||
#endif /* defined(HAVE_SLIRP_NETWORK) */
|
||||
}
|
||||
else {
|
||||
else { /* not nat: */
|
||||
if (0 == strncmp("udp:", savname, 4)) {
|
||||
char localport[CBUFSIZE], host[CBUFSIZE], port[CBUFSIZE];
|
||||
char hostport[2*CBUFSIZE];
|
||||
|
||||
if (!strcmp(savname, "udp:sourceport:remotehost:remoteport")) {
|
||||
sim_printf ("Eth: Must specify actual udp host and ports(i.e. udp:1224:somehost.com:2234)\r\n");
|
||||
return SCPE_OPENERR | SCPE_NOMESSAGE;
|
||||
}
|
||||
|
||||
if (SCPE_OK != sim_parse_addr_ex (savname+4, host, sizeof(host), "localhost", port, sizeof(port), localport, sizeof(localport), NULL))
|
||||
return SCPE_OPENERR;
|
||||
|
||||
if (localport[0] == '\0')
|
||||
strcpy (localport, port);
|
||||
sprintf (hostport, "%s:%s", host, port);
|
||||
if ((SCPE_OK == sim_parse_addr (hostport, NULL, 0, NULL, NULL, 0, NULL, "localhost")) &&
|
||||
(0 == strcmp (localport, port))) {
|
||||
sim_printf ("Eth: Must specify different udp localhost ports\r\n");
|
||||
return SCPE_OPENERR | SCPE_NOMESSAGE;
|
||||
}
|
||||
*fd_handle = sim_connect_sock_ex (localport, hostport, NULL, NULL, SIM_SOCK_OPT_DATAGRAM);
|
||||
if (INVALID_SOCKET == *fd_handle)
|
||||
return SCPE_OPENERR;
|
||||
*eth_api = ETH_API_UDP;
|
||||
*handle = (void *)1; /* Flag used to indicated open */
|
||||
}
|
||||
else { /* not udp:, so attempt to open the parameter as if it were an explicit device name */
|
||||
#if defined(HAVE_PCAP_NETWORK)
|
||||
*handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
|
||||
if (!*handle) { /* can't open device */
|
||||
sim_printf ("Eth: pcap_open_live error - %s\r\n", errbuf);
|
||||
return SCPE_OPENERR;
|
||||
}
|
||||
*eth_api = ETH_API_PCAP;
|
||||
*handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
|
||||
if (!*handle) { /* can't open device */
|
||||
sim_printf ("Eth: pcap_open_live error - %s\r\n", errbuf);
|
||||
return SCPE_OPENERR | SCPE_NOMESSAGE;
|
||||
}
|
||||
*eth_api = ETH_API_PCAP;
|
||||
#if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__)
|
||||
/* Tell the kernel that the header is fully-formed when it gets it.
|
||||
This is required in order to fake the src address. */
|
||||
if (1) {
|
||||
int one = 1;
|
||||
ioctl(pcap_fileno(*handle), BIOCSHDRCMPLT, &one);
|
||||
}
|
||||
/* Tell the kernel that the header is fully-formed when it gets it.
|
||||
This is required in order to fake the src address. */
|
||||
if (1) {
|
||||
int one = 1;
|
||||
ioctl(pcap_fileno(*handle), BIOCSHDRCMPLT, &one);
|
||||
}
|
||||
#endif /* xBSD */
|
||||
#if defined(_WIN32)
|
||||
pcap_setmintocopy ((pcap_t*)(*handle), 0);
|
||||
pcap_setmintocopy ((pcap_t*)(*handle), 0);
|
||||
#endif
|
||||
#if !defined (USE_READER_THREAD)
|
||||
#ifdef USE_SETNONBLOCK
|
||||
/* set ethernet device non-blocking so pcap_dispatch() doesn't hang */
|
||||
if (pcap_setnonblock (*handle, 1, errbuf) == -1) {
|
||||
sim_printf ("Eth: Failed to set non-blocking: %s\r\n", errbuf);
|
||||
}
|
||||
/* set ethernet device non-blocking so pcap_dispatch() doesn't hang */
|
||||
if (pcap_setnonblock (*handle, 1, errbuf) == -1) {
|
||||
sim_printf ("Eth: Failed to set non-blocking: %s\r\n", errbuf);
|
||||
}
|
||||
#endif
|
||||
#if defined (__APPLE__)
|
||||
if (1) {
|
||||
/* Deliver packets immediately, needed for OS X 10.6.2 and later
|
||||
* (Snow-Leopard).
|
||||
* See this thread on libpcap and Mac Os X 10.6 Snow Leopard on
|
||||
* the tcpdump mailinglist: http://seclists.org/tcpdump/2010/q1/110
|
||||
*/
|
||||
int v = 1;
|
||||
ioctl(pcap_fileno(*handle), BIOCIMMEDIATE, &v);
|
||||
}
|
||||
if (1) {
|
||||
/* Deliver packets immediately, needed for OS X 10.6.2 and later
|
||||
* (Snow-Leopard).
|
||||
* See this thread on libpcap and Mac Os X 10.6 Snow Leopard on
|
||||
* the tcpdump mailinglist: http://seclists.org/tcpdump/2010/q1/110
|
||||
*/
|
||||
int v = 1;
|
||||
ioctl(pcap_fileno(*handle), BIOCIMMEDIATE, &v);
|
||||
}
|
||||
#endif /* defined (__APPLE__) */
|
||||
#endif /* !defined (USE_READER_THREAD) */
|
||||
#else
|
||||
strncpy (errbuf, "Unknown or unsupported network device", PCAP_ERRBUF_SIZE-1);
|
||||
strncpy (errbuf, "Unknown or unsupported network device", PCAP_ERRBUF_SIZE-1);
|
||||
#endif /* defined(HAVE_PCAP_NETWORK) */
|
||||
}
|
||||
}
|
||||
} /* not udp:, so attempt to open the parameter as if it were an explicit device name */
|
||||
} /* !nat: */
|
||||
} /* !vde: */
|
||||
} /* !tap: */
|
||||
if (errbuf[0])
|
||||
return SCPE_OPENERR;
|
||||
|
||||
@@ -2030,11 +2081,11 @@ else {
|
||||
}
|
||||
}
|
||||
|
||||
r = _eth_open_port(savname, &dev->eth_api, &dev->handle, &dev->fd_handle, errbuf, NULL);
|
||||
r = _eth_open_port(savname, &dev->eth_api, &dev->handle, &dev->fd_handle, errbuf, NULL, (void *)dev);
|
||||
|
||||
if (errbuf[0]) {
|
||||
sim_printf ("Eth: open error - %s\r\n", errbuf);
|
||||
return SCPE_OPENERR;
|
||||
return SCPE_OPENERR | SCPE_NOMESSAGE;
|
||||
}
|
||||
if (r != SCPE_OK)
|
||||
return r;
|
||||
@@ -2099,15 +2150,15 @@ switch (eth_api) {
|
||||
case ETH_API_VDE:
|
||||
vde_close((VDECONN*)pcap);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_SLIRP_NETWORK
|
||||
case ETH_API_NAT:
|
||||
sim_slirp_close((SLIRP*)pcap);
|
||||
break;
|
||||
#endif
|
||||
case ETH_API_UDP:
|
||||
sim_close_sock(pcap_fd);
|
||||
break;
|
||||
#ifdef USE_SLIRP_NETWORK
|
||||
case ETH_API_NAT:
|
||||
vde_close((VDECONN*)pcap);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
@@ -2166,11 +2217,23 @@ fprintf (st, "%s attach help\n\n", dptr->name);
|
||||
fprintf (st, " sim> SHOW ETHERNET\n");
|
||||
fprintf (st, " libpcap version 1.0.0\n");
|
||||
fprintf (st, " ETH devices:\n");
|
||||
fprintf (st, " eth0 en0 (No description available)\n");
|
||||
fprintf (st, " eth1 tap:tapN (Integrated Tun/Tap support)\n");
|
||||
fprintf (st, " eth0 en0 (No description available)\n");
|
||||
#if defined(HAVE_TAP_NETWORK)
|
||||
fprintf (st, " eth1 tap:tapN (Integrated Tun/Tap support)\n");
|
||||
#endif
|
||||
#if defined(HAVE_SLIRP_NETWORK)
|
||||
fprintf (st, " eth2 vde:device (Integrated VDE support)\n");
|
||||
#endif
|
||||
#if defined(HAVE_SLIRP_NETWORK)
|
||||
fprintf (st, " eth3 nat:{optional-nat-parameters} (Integrated NAT (SLiRP) support)\n");
|
||||
#endif
|
||||
fprintf (st, " eth4 udp:sourceport:remotehost:remoteport (Integrated UDP bridge support)\n");
|
||||
fprintf (st, " sim> ATTACH %s eth0\n\n", dptr->name);
|
||||
fprintf (st, "or equivalently:\n\n");
|
||||
fprintf (st, " sim> ATTACH %s en0\n\n", dptr->name);
|
||||
#if defined(HAVE_SLIRP_NETWORK)
|
||||
sim_slirp_attach_help (st, dptr, uptr, flag, cptr);
|
||||
#endif
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -2399,7 +2462,7 @@ if (dev->error_needs_reset) {
|
||||
_eth_close_port(dev->eth_api, (pcap_t *)dev->handle, dev->fd_handle);
|
||||
sim_os_sleep (ETH_ERROR_REOPEN_PAUSE);
|
||||
|
||||
r = _eth_open_port(dev->name, &dev->eth_api, &dev->handle, &dev->fd_handle, errbuf, dev->bpf_filter);
|
||||
r = _eth_open_port(dev->name, &dev->eth_api, &dev->handle, &dev->fd_handle, errbuf, dev->bpf_filter, (void *)dev);
|
||||
dev->error_needs_reset = FALSE;
|
||||
if (r == SCPE_OK)
|
||||
sim_printf ("%s ReOpened: %s \n", msg, dev->name);
|
||||
@@ -2473,6 +2536,15 @@ if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) {
|
||||
else
|
||||
status = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_SLIRP_NETWORK
|
||||
case ETH_API_NAT:
|
||||
status = sim_slirp_send((SLIRP*)dev->handle, (char *)packet->msg, (size_t)packet->len, 0);
|
||||
if ((status == (int)packet->len) || (status == 0))
|
||||
status = 0;
|
||||
else
|
||||
status = 1;
|
||||
break;
|
||||
#endif
|
||||
case ETH_API_UDP:
|
||||
status = (((int32)packet->len == sim_write_sock (dev->fd_handle, (char *)packet->msg, (int32)packet->len)) ? 0 : -1);
|
||||
@@ -3086,6 +3158,7 @@ switch (dev->eth_api) {
|
||||
case ETH_API_TAP:
|
||||
case ETH_API_VDE:
|
||||
case ETH_API_UDP:
|
||||
case ETH_API_NAT:
|
||||
bpf_used = 0;
|
||||
to_me = 0;
|
||||
eth_packet_trace (dev, data, header->len, "received");
|
||||
@@ -3130,7 +3203,7 @@ if ((LOOPBACK_SELF_FRAME(dev->physical_addr, data)) ||
|
||||
#ifdef USE_READER_THREAD
|
||||
pthread_mutex_unlock (&dev->self_lock);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (bpf_used ? to_me : (to_me && !from_me)) {
|
||||
if (header->len > ETH_MIN_JUMBO_FRAME) {
|
||||
@@ -3623,6 +3696,13 @@ if (used < max) {
|
||||
++used;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_SLIRP_NETWORK
|
||||
if (used < max) {
|
||||
sprintf(list[used].name, "%s", "nat:{optional-nat-parameters}");
|
||||
sprintf(list[used].desc, "%s", "Integrated NAT (SLiRP) support");
|
||||
++used;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (used < max) {
|
||||
sprintf(list[used].name, "%s", "udp:sourceport:remotehost:remoteport");
|
||||
@@ -3630,14 +3710,6 @@ if (used < max) {
|
||||
++used;
|
||||
}
|
||||
|
||||
#ifdef USE_SLIRP_NETWORK
|
||||
if (used < max) {
|
||||
sprintf(list[used].name, "%s", "nat:device");
|
||||
sprintf(list[used].desc, "%s", "Integrated User Mode NAT support");
|
||||
++used;
|
||||
}
|
||||
#endif
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
@@ -3731,5 +3803,9 @@ fprintf(st, " Peak Write Queue Size: %d\n", dev->write_queue_peak);
|
||||
#endif
|
||||
if (dev->bpf_filter)
|
||||
fprintf(st, " BPF Filter: %s\n", dev->bpf_filter);
|
||||
#if defined(HAVE_SLIRP_NETWORK)
|
||||
if (dev->eth_api == ETH_API_NAT)
|
||||
sim_slirp_show ((SLIRP *)dev->handle, st);
|
||||
#endif
|
||||
}
|
||||
#endif /* USE_NETWORK */
|
||||
|
||||
Reference in New Issue
Block a user