Merge pull request #3521 from dougvj/net-add-tap-backend
networking: add Linux-specific TAP mode to network devices
This commit is contained in:
@@ -660,6 +660,8 @@ load_network(void)
|
||||
nc->net_type = NET_TYPE_SLIRP;
|
||||
else if (!strcmp(p, "vde") || !strcmp(p, "2"))
|
||||
nc->net_type = NET_TYPE_VDE;
|
||||
else if (!strcmp(p, "tap") || !strcmp(p, "3"))
|
||||
nc->net_type = NET_TYPE_TAP;
|
||||
else
|
||||
nc->net_type = NET_TYPE_NONE;
|
||||
} else
|
||||
@@ -706,11 +708,12 @@ load_network(void)
|
||||
nc->net_type = NET_TYPE_SLIRP;
|
||||
else if (!strcmp(p, "vde") || !strcmp(p, "2"))
|
||||
nc->net_type = NET_TYPE_VDE;
|
||||
else if (!strcmp(p, "tap") || !strcmp(p, "3"))
|
||||
nc->net_type = NET_TYPE_TAP;
|
||||
else
|
||||
nc->net_type = NET_TYPE_NONE;
|
||||
} else
|
||||
nc->net_type = NET_TYPE_NONE;
|
||||
|
||||
sprintf(temp, "net_%02i_host_device", c + 1);
|
||||
p = ini_section_get_string(cat, temp, NULL);
|
||||
if (p != NULL) {
|
||||
@@ -2433,7 +2436,9 @@ save_network(void)
|
||||
case NET_TYPE_VDE:
|
||||
ini_section_set_string(cat, temp, "vde");
|
||||
break;
|
||||
|
||||
case NET_TYPE_TAP:
|
||||
ini_section_set_string(cat, temp, "tap");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#define NET_TYPE_SLIRP 1 /* use the SLiRP port forwarder */
|
||||
#define NET_TYPE_PCAP 2 /* use the (Win)Pcap API */
|
||||
#define NET_TYPE_VDE 3 /* use the VDE plug API */
|
||||
#define NET_TYPE_TAP 4 /* use a linux TAP device */
|
||||
|
||||
#define NET_MAX_FRAME 1518
|
||||
/* Queue size must be a power of 2 */
|
||||
@@ -126,6 +127,7 @@ typedef struct netdrv_t {
|
||||
extern const netdrv_t net_pcap_drv;
|
||||
extern const netdrv_t net_slirp_drv;
|
||||
extern const netdrv_t net_vde_drv;
|
||||
extern const netdrv_t net_tap_drv;
|
||||
extern const netdrv_t net_null_drv;
|
||||
|
||||
struct _netcard_t {
|
||||
@@ -155,10 +157,11 @@ typedef struct {
|
||||
int has_slirp;
|
||||
int has_pcap;
|
||||
int has_vde;
|
||||
int has_tap;
|
||||
} network_devmap_t;
|
||||
|
||||
|
||||
#define HAS_NOSLIRP_NET(x) (x.has_pcap || x.has_vde)
|
||||
#define HAS_NOSLIRP_NET(x) (x.has_pcap || x.has_vde || x.has_tap)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -70,5 +70,14 @@ if (UNIX)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
if (UNIX AND NOT APPLE) # Support for TAP on Linux and BSD, supposedly.
|
||||
find_path(HAS_TAP "linux/if_tun.h" PATHS ${TAP_INCLUDE_DIR} "/usr/include /usr/local/include" "/opt/homebrew/include" )
|
||||
if(HAS_TAP)
|
||||
add_compile_definitions(HAS_TAP)
|
||||
list(APPEND net_sources net_tap.c)
|
||||
else()
|
||||
message(WARNING "TAP support not available. Are you on some BSD?")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(net OBJECT ${net_sources})
|
||||
|
||||
353
src/network/net_tap.c
Normal file
353
src/network/net_tap.c
Normal file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Linux TAP network interface for 86box.
|
||||
*
|
||||
* This file was created by looking at the VDE network backend
|
||||
* as a reference, credit to jguillaumes.
|
||||
*
|
||||
* Authors: Doug Johnson <dougvj@gmail.com>
|
||||
*
|
||||
*
|
||||
* Copyright 2023 Doug Johnson
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with
|
||||
* or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the entire
|
||||
* above notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names
|
||||
* of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
# error TAP networking is only supported on Linux
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <stdbool.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/sockios.h>
|
||||
|
||||
#define HAVE_STDARG_H
|
||||
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/plat.h>
|
||||
#include <86box/plat_dynld.h>
|
||||
#include <86box/thread.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/network.h>
|
||||
#include <86box/net_event.h>
|
||||
|
||||
typedef struct net_tap_t {
|
||||
int fd; // tap device file descriptor
|
||||
netcard_t *card;
|
||||
thread_t *poll_tid;
|
||||
net_evt_t tx_event;
|
||||
net_evt_t stop_event;
|
||||
netpkt_t pkt_rx;
|
||||
netpkt_t pkts_tx[NET_QUEUE_LEN];
|
||||
} net_tap_t;
|
||||
|
||||
#ifdef ENABLE_TAP_LOG
|
||||
int tap_do_log = ENABLE_TAP_LOG;
|
||||
|
||||
|
||||
static void tap_logv(const char *fmt, va_list ap)
|
||||
{
|
||||
if (tap_do_log) {
|
||||
pclog_ex(fmt, ap);
|
||||
}
|
||||
}
|
||||
|
||||
static void tap_log(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
if (tap_do_log) {
|
||||
va_start(ap, fmt);
|
||||
tap_logv(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#else
|
||||
# define tap_log(...) \
|
||||
do { \
|
||||
} while (0)
|
||||
# define tap_logv(...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static void net_tap_thread(void *priv) {
|
||||
enum {
|
||||
NET_EVENT_STOP = 0,
|
||||
NET_EVENT_TX,
|
||||
NET_EVENT_RX,
|
||||
NET_EVENT_TAP,
|
||||
NET_EVENT_MAX,
|
||||
};
|
||||
net_tap_t *tap = priv;
|
||||
tap_log("TAP: poll thread started.\n");
|
||||
struct pollfd pfd[NET_EVENT_MAX];
|
||||
pfd[NET_EVENT_STOP].fd = net_event_get_fd(&tap->stop_event);
|
||||
pfd[NET_EVENT_STOP].events = POLLIN | POLLPRI;
|
||||
|
||||
pfd[NET_EVENT_TX].fd = net_event_get_fd(&tap->tx_event);
|
||||
pfd[NET_EVENT_TX].events = POLLIN | POLLPRI;
|
||||
|
||||
pfd[NET_EVENT_RX].fd = tap->fd;
|
||||
pfd[NET_EVENT_RX].events = POLLIN | POLLPRI;
|
||||
|
||||
pfd[NET_EVENT_TAP].fd = tap->fd;
|
||||
pfd[NET_EVENT_TAP].events = POLLERR | POLLHUP | POLLPRI;
|
||||
fcntl(tap->fd, F_SETFL, O_NONBLOCK);
|
||||
while(1) {
|
||||
ssize_t ret = poll(pfd, NET_EVENT_MAX, -1);
|
||||
if (ret < 0) {
|
||||
tap_log("TAP: poll error: %s\n", strerror(errno));
|
||||
net_event_set(&tap->stop_event);
|
||||
break;
|
||||
}
|
||||
if (pfd[NET_EVENT_TAP].revents) {
|
||||
tap_log("TAP: tap close/error event received.\n");
|
||||
net_event_set(&tap->stop_event);
|
||||
}
|
||||
if (pfd[NET_EVENT_TX].revents & POLLIN) {
|
||||
net_event_clear(&tap->tx_event);
|
||||
int packets = network_tx_popv(tap->card, tap->pkts_tx,
|
||||
NET_QUEUE_LEN);
|
||||
for(int i = 0; i < packets; i++) {
|
||||
netpkt_t *pkt = &tap->pkts_tx[i];
|
||||
ssize_t ret = write(tap->fd, pkt->data, pkt->len);
|
||||
if (ret < 0) {
|
||||
tap_log("TAP: write error: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pfd[NET_EVENT_RX].revents & POLLIN) {
|
||||
ssize_t len = read(tap->fd, tap->pkt_rx.data, NET_MAX_FRAME);
|
||||
if (len < 0) {
|
||||
tap_log("TAP: read error: %s\n", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
tap->pkt_rx.len = len;
|
||||
network_rx_put_pkt(tap->card, &tap->pkt_rx);
|
||||
}
|
||||
if (pfd[NET_EVENT_STOP].revents & POLLIN) {
|
||||
net_event_clear(&tap->stop_event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void net_tap_close(void *priv)
|
||||
{
|
||||
if (!priv) {
|
||||
return;
|
||||
}
|
||||
net_tap_t *tap = priv;
|
||||
tap_log("TAP: closing.\n");
|
||||
net_event_set(&tap->stop_event);
|
||||
tap_log("TAP: waiting for poll thread to exit.\n");
|
||||
thread_wait(tap->poll_tid);
|
||||
tap_log("TAP: poll thread exited.\n");
|
||||
for(int i = 0; i < NET_QUEUE_LEN; i++) {
|
||||
free(tap->pkts_tx[i].data);
|
||||
}
|
||||
free(tap->pkt_rx.data);
|
||||
if (tap->fd >= 0) {
|
||||
close(tap->fd);
|
||||
}
|
||||
free(tap);
|
||||
}
|
||||
|
||||
void net_tap_error(char *errbuf, const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vsnprintf(errbuf, NET_DRV_ERRBUF_SIZE, format, ap);
|
||||
tap_log("TAP: %s", errbuf);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
// Error handling macro for the many ioctl calls we use in net_tap_alloc
|
||||
#define ioctl_or_fail(fd, request, argp) \
|
||||
do { \
|
||||
if ((err = ioctl(fd, request, argp)) < 0) { \
|
||||
tap_log("TAP: ioctl " #request " error: %s\n", strerror(errno)); \
|
||||
goto fail; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Returns -ERRNO so we can get an idea what's wrong
|
||||
int net_tap_alloc(const uint8_t *mac_addr, const char* bridge_dev)
|
||||
{
|
||||
int fd;
|
||||
struct ifreq ifr = {0};
|
||||
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
|
||||
tap_log("TAP: open error: %s\n", strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
int err;
|
||||
if ((err = ioctl(fd, TUNSETIFF, &ifr)) < 0) {
|
||||
tap_log("TAP: ioctl TUNSETIFF error: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
// Create a socket for ioctl operations
|
||||
int sock;
|
||||
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
tap_log("TAP: socket error: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
// Bring the interface up
|
||||
tap_log("TAP: Bringing interface '%s' up.\n", ifr.ifr_name);
|
||||
ifr.ifr_flags = IFF_UP;
|
||||
ioctl_or_fail(sock, SIOCSIFFLAGS, &ifr);
|
||||
// Add interface to bridge, if specified
|
||||
if (bridge_dev && bridge_dev[0] != '\0') {
|
||||
// First see if the bridge exists
|
||||
struct ifreq ifr_bridge;
|
||||
//NOTE strncpy does not null terminate if the string is too long, I use
|
||||
// snprintf or strlcpy instead
|
||||
//strncpy(ifr_bridge.ifr_name, bridge_dev, IFNAMSIZ);
|
||||
snprintf(ifr_bridge.ifr_name, IFNAMSIZ, "%s", bridge_dev);
|
||||
if ((err = ioctl(sock, SIOCGIFINDEX, &ifr_bridge)) < 0) {
|
||||
if (errno != ENODEV) {
|
||||
tap_log("TAP: ioctl SIOCGIFINDEX error: %s\n", strerror(errno));
|
||||
goto fail;
|
||||
} else {
|
||||
// Create the bridge
|
||||
ioctl_or_fail(sock, SIOCBRADDBR, &ifr_bridge);
|
||||
// Set the bridge up
|
||||
ifr_bridge.ifr_flags = IFF_UP;
|
||||
ioctl_or_fail(sock, SIOCSIFFLAGS, &ifr_bridge);
|
||||
}
|
||||
}
|
||||
// Get TAP index
|
||||
ioctl_or_fail(sock, SIOCGIFINDEX, &ifr);
|
||||
// Add the tap device to the bridge
|
||||
ifr_bridge.ifr_ifindex = ifr.ifr_ifindex;
|
||||
ioctl_or_fail(sock, SIOCBRADDIF, &ifr_bridge);
|
||||
}
|
||||
// close the socket we used for ioctl operations
|
||||
close(sock);
|
||||
tap_log("Allocated tap device %s\n", ifr.ifr_name);
|
||||
return fd;
|
||||
// cleanup point used by ioctl_or_fail macro
|
||||
fail:
|
||||
close(sock);
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
void net_tap_in_available(void *priv)
|
||||
{
|
||||
net_tap_t *tap = priv;
|
||||
net_event_set(&tap->tx_event);
|
||||
}
|
||||
|
||||
void *
|
||||
net_tap_init(
|
||||
const netcard_t *card,
|
||||
const uint8_t *mac_addr,
|
||||
void *priv,
|
||||
char *netdrv_errbuf)
|
||||
{
|
||||
const char *bridge_dev = (void *) priv;
|
||||
int tap_fd = net_tap_alloc(mac_addr, bridge_dev);
|
||||
if (tap_fd < 0) {
|
||||
if (tap_fd == -EPERM) {
|
||||
net_tap_error(
|
||||
netdrv_errbuf,
|
||||
"No permissions to allocate tap device. "
|
||||
"Try adding NET_CAP_ADMIN,NET_CAP_RAW to 86box ("
|
||||
"sudo setcap 'CAP_NET_RAW,CAP_NET_ADMIN=eip')");
|
||||
} else {
|
||||
net_tap_error(
|
||||
netdrv_errbuf,
|
||||
"Unable to allocate TAP device: %s",
|
||||
strerror(-tap_fd));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (bridge_dev && bridge_dev[0] != '\0') {
|
||||
}
|
||||
net_tap_t *tap = calloc(1, sizeof(net_tap_t));
|
||||
if (!tap) {
|
||||
goto alloc_fail;
|
||||
}
|
||||
tap->pkt_rx.data = calloc(1, NET_MAX_FRAME);
|
||||
if (!tap->pkt_rx.data) {
|
||||
goto alloc_fail;
|
||||
}
|
||||
for(int i = 0; i < NET_QUEUE_LEN; i++) {
|
||||
tap->pkts_tx[i].data = calloc(1, NET_MAX_FRAME);
|
||||
if (!tap->pkts_tx[i].data) {
|
||||
goto alloc_fail;
|
||||
}
|
||||
}
|
||||
tap->fd = tap_fd;
|
||||
tap->card = (netcard_t *) card;
|
||||
net_event_init(&tap->tx_event);
|
||||
net_event_init(&tap->stop_event);
|
||||
tap->poll_tid = thread_create(net_tap_thread, tap);
|
||||
return tap;
|
||||
alloc_fail:
|
||||
net_tap_error(netdrv_errbuf, "Failed to allocate memory");
|
||||
close(tap_fd);
|
||||
free(tap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const netdrv_t net_tap_drv = {
|
||||
&net_tap_in_available,
|
||||
&net_tap_init,
|
||||
&net_tap_close,
|
||||
NULL
|
||||
};
|
||||
@@ -496,6 +496,12 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_lin
|
||||
card->host_drv = net_vde_drv;
|
||||
card->host_drv.priv = card->host_drv.init(card, mac, net_cards_conf[net_card_current].host_dev_name, net_drv_error);
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAS_TAP
|
||||
case NET_TYPE_TAP:
|
||||
card->host_drv = net_tap_drv;
|
||||
card->host_drv.priv = card->host_drv.init(card, mac, net_cards_conf[net_card_current].host_dev_name, net_drv_error);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
card->host_drv.priv = NULL;
|
||||
|
||||
@@ -1081,6 +1081,9 @@ MediaMenu::nicUpdateMenu(int i)
|
||||
case NET_TYPE_VDE:
|
||||
netType = "VDE";
|
||||
break;
|
||||
case NET_TYPE_TAP:
|
||||
netType = "TAP";
|
||||
break;
|
||||
}
|
||||
|
||||
QString devName = DeviceConfig::DeviceName(network_card_getdevice(net_cards_conf[i].device_num), network_card_get_internal_name(net_cards_conf[i].device_num), 1);
|
||||
|
||||
@@ -45,6 +45,8 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui)
|
||||
auto *vde_socket_label = findChild<QLabel *>(QString("labelSocketVDENIC%1").arg(i + 1));
|
||||
auto *socket_line = findChild<QLineEdit *>(QString("socketVDENIC%1").arg(i + 1));
|
||||
|
||||
auto *bridge_line = findChild<QLineEdit *>(QString("bridgeTAPNIC%1").arg(i + 1));
|
||||
|
||||
auto *option_list_label = findChild<QLabel *>(QString("labelOptionList%1").arg(i + 1));
|
||||
auto *option_list_line = findChild<QWidget *>(QString("lineOptionList%1").arg(i + 1));
|
||||
|
||||
@@ -60,6 +62,9 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui)
|
||||
vde_socket_label->setVisible(false);
|
||||
socket_line->setVisible(false);
|
||||
|
||||
// TAP
|
||||
bridge_line->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_TAP);
|
||||
|
||||
// PCAP
|
||||
intf_cbox->setVisible(false);
|
||||
intf_label->setVisible(false);
|
||||
@@ -86,6 +91,9 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui)
|
||||
intf_label->setVisible(true);
|
||||
break;
|
||||
|
||||
case NET_TYPE_TAP:
|
||||
bridge_line->setVisible(true);
|
||||
|
||||
case NET_TYPE_SLIRP:
|
||||
default:
|
||||
break;
|
||||
@@ -123,6 +131,7 @@ SettingsNetwork::save()
|
||||
for (int i = 0; i < NET_CARD_MAX; ++i) {
|
||||
auto *cbox = findChild<QComboBox *>(QString("comboBoxNIC%1").arg(i + 1));
|
||||
auto *socket_line = findChild<QLineEdit *>(QString("socketVDENIC%1").arg(i + 1));
|
||||
auto *bridge_line = findChild<QLineEdit *>(QString("bridgeTAPNIC%1").arg(i + 1));
|
||||
net_cards_conf[i].device_num = cbox->currentData().toInt();
|
||||
cbox = findChild<QComboBox *>(QString("comboBoxNet%1").arg(i + 1));
|
||||
net_cards_conf[i].net_type = cbox->currentData().toInt();
|
||||
@@ -132,6 +141,8 @@ SettingsNetwork::save()
|
||||
strncpy(net_cards_conf[i].host_dev_name, network_devs[cbox->currentData().toInt()].device, sizeof(net_cards_conf[i].host_dev_name) - 1);
|
||||
else if (net_cards_conf[i].net_type == NET_TYPE_VDE)
|
||||
strncpy(net_cards_conf[i].host_dev_name, socket_line->text().toUtf8().constData(), sizeof(net_cards_conf[i].host_dev_name));
|
||||
else if (net_cards_conf[i].net_type == NET_TYPE_TAP)
|
||||
strncpy(net_cards_conf[i].host_dev_name, bridge_line->text().toUtf8().constData(), sizeof(net_cards_conf[i].host_dev_name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +209,8 @@ SettingsNetwork::onCurrentMachineChanged(int machineId)
|
||||
if (network_devmap.has_vde)
|
||||
Models::AddEntry(model, "VDE", NET_TYPE_VDE);
|
||||
|
||||
Models::AddEntry(model, "TAP", NET_TYPE_TAP);
|
||||
|
||||
model->removeRows(0, removeRows);
|
||||
cbox->setCurrentIndex(cbox->findData(net_cards_conf[i].net_type));
|
||||
|
||||
@@ -216,13 +229,18 @@ SettingsNetwork::onCurrentMachineChanged(int machineId)
|
||||
}
|
||||
model->removeRows(0, removeRows);
|
||||
cbox->setCurrentIndex(selectedRow);
|
||||
}
|
||||
}
|
||||
|
||||
if (net_cards_conf[i].net_type == NET_TYPE_VDE) {
|
||||
QString currentVdeSocket = net_cards_conf[i].host_dev_name;
|
||||
auto editline = findChild<QLineEdit *>(QString("socketVDENIC%1").arg(i+1));
|
||||
editline->setText(currentVdeSocket);
|
||||
}
|
||||
else if (net_cards_conf[i].net_type == NET_TYPE_TAP) {
|
||||
QString currentTapDevice = net_cards_conf[i].host_dev_name;
|
||||
auto editline = findChild<QLineEdit *>(QString("bridgeTAPNIC%1").arg(i+1));
|
||||
editline->setText(currentTapDevice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
|
||||
<widget class="QWidget" name="tabNet1">
|
||||
<attribute name="title">
|
||||
<string>Network Card #1</string>
|
||||
@@ -156,7 +155,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="labelBridgeTAPNIC1">
|
||||
<property name="text">
|
||||
<string>TAP Bridge Device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="bridgeTAPNIC1">
|
||||
<property name="maxLength">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<spacer name="verticalSpacerNIC1">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -171,7 +184,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
<widget class="QWidget" name="tabNet2">
|
||||
<attribute name="title">
|
||||
<string>Network Card #2</string>
|
||||
@@ -296,7 +308,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="labelBridgeTAPNIC2">
|
||||
<property name="text">
|
||||
<string>TAP Bridge Device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="bridgeTAPNIC2">
|
||||
<property name="maxLength">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<spacer name="verticalSpacerNIC2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -311,7 +337,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
<widget class="QWidget" name="tabNet3">
|
||||
<attribute name="title">
|
||||
<string>Network Card #3</string>
|
||||
@@ -436,7 +461,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="labelBridgeTAPNIC3">
|
||||
<property name="text">
|
||||
<string>TAP Bridge Device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="bridgeTAPNIC3">
|
||||
<property name="maxLength">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<spacer name="verticalSpacerNIC3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -451,7 +490,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
<widget class="QWidget" name="tabNet4">
|
||||
<attribute name="title">
|
||||
<string>Network Card #4</string>
|
||||
@@ -576,7 +614,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="labelBridgeTAPNIC4">
|
||||
<property name="text">
|
||||
<string>TAP Bridge Device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="bridgeTAPNIC4">
|
||||
<property name="maxLength">
|
||||
<number>127</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<spacer name="verticalSpacerNIC4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -591,7 +643,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
Reference in New Issue
Block a user