From 0dfe5a40a0011c00d9c9ee227afa51adcbe63075 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Sat, 29 Jul 2023 07:54:31 -1000 Subject: [PATCH] ETHER: Load VDE support dynamically --- sim_ether.c | 227 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 137 insertions(+), 90 deletions(-) diff --git a/sim_ether.c b/sim_ether.c index 8fe13475..5e0d7853 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -994,29 +994,6 @@ t_stat sim_ether_test (DEVICE *dptr, const char *cptr) {return SCPE_OK;} #else /* endif unimplemented */ -const char *eth_capabilities(void) - { -#if defined (USE_READER_THREAD) - return "Threaded " -#else - return "Polled " -#endif - "Ethernet Packet transports" -#if defined (HAVE_PCAP_NETWORK) - ":PCAP" -#endif -#if defined (HAVE_TAP_NETWORK) - ":TAP" -#endif -#if defined (HAVE_VDE_NETWORK) - ":VDE" -#endif -#if defined (HAVE_SLIRP_NETWORK) - ":NAT" -#endif - ":UDP"; - } - #if (defined (xBSD) || defined (__APPLE__)) && (defined (HAVE_TAP_NETWORK) || defined (HAVE_PCAP_NETWORK)) #include #include @@ -1126,6 +1103,77 @@ for (i=0; i +#include +#include +#elif defined(HAVE_BSDTUNTAP) +#include +#include +#include +#else /* We don't know how to do this on the current platform */ +#undef HAVE_TAP_NETWORK +#endif +#endif /* HAVE_TAP_NETWORK */ + +#ifdef HAVE_VDE_NETWORK +#ifdef __cplusplus +extern "C" { +#endif +#include +/* support for dynamic loading */ +static void load_vde (void); +static VDECONN *(*p_vde_open_real)(char *vde_url,char *descr,int interface_version, struct vde_open_args *open_args) = NULL; +static ssize_t (*p_vde_recv)(VDECONN *conn,void *buf,size_t len,int flags) = NULL; +static ssize_t (*p_vde_send)(VDECONN *conn,const void *buf,size_t len,int flags) = NULL; +static int (*p_vde_datafd)(VDECONN *conn) = NULL; +static int (*p_vde_close)(VDECONN *conn) = NULL; +static t_bool eth_vde_network_available = FALSE; +#ifdef __cplusplus +} +#endif +#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 +#endif + +const char *eth_capabilities(void) + { + static char capabilities[CBUFSIZE] = ""; + + if (capabilities[0] != '\0') + return capabilities; +#if defined (USE_READER_THREAD) + strlcat (capabilities, "Threaded ", sizeof (capabilities)); +#else + strlcat (capabilities, "Polled ", sizeof (capabilities)); +#endif + strlcat (capabilities, "Ethernet Packet transports", sizeof (capabilities)); +#if defined (HAVE_PCAP_NETWORK) + strlcat (capabilities, ":PCAP", sizeof (capabilities)); +#endif +#if defined (HAVE_TAP_NETWORK) + strlcat (capabilities, ":TAP", sizeof (capabilities)); +#endif +#if defined (HAVE_VDE_NETWORK) + load_vde(); + if (eth_vde_network_available) + strlcat (capabilities, ":VDE", sizeof (capabilities)); +#endif +#if defined (HAVE_SLIRP_NETWORK) + strlcat (capabilities, ":NAT", sizeof (capabilities)); +#endif + strlcat (capabilities, ":UDP", sizeof (capabilities)); + return capabilities; + } + int eth_devices(int max, ETH_LIST* list, ETH_BOOL framers) { int used = 0; @@ -1188,7 +1236,7 @@ if (used < max) { } #endif #ifdef HAVE_VDE_NETWORK -if (used < max) { +if (eth_vde_network_available && (used < max)) { sprintf(list[used].name, "%s", "vde:device{:switch-port-number}"); sprintf(list[used].desc, "%s", "Integrated VDE support"); list[used].eth_api = ETH_API_VDE; @@ -1215,39 +1263,6 @@ if (used < max) { return used; } -#ifdef HAVE_TAP_NETWORK -#if defined(__linux) || defined(__linux__) -#include -#include -#include -#elif defined(HAVE_BSDTUNTAP) -#include -#include -#include -#else /* We don't know how to do this on the current platform */ -#undef HAVE_TAP_NETWORK -#endif -#endif /* HAVE_TAP_NETWORK */ - -#ifdef HAVE_VDE_NETWORK -#ifdef __cplusplus -extern "C" { -#endif -#include -#ifdef __cplusplus -} -#endif -#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 -#endif - #if defined(USE_SHARED) && (defined(_WIN32) || defined(SIM_HAVE_DLOPEN)) /* Dynamic DLL loading technique and modified source comes from Etherial/WireShark capture_pcap.c */ @@ -1317,7 +1332,7 @@ static void load_function(const char* function, _func* func_ptr) { } } -/* load wpcap.dll as required */ +/* load wpcap.dll or libpcap as required */ int load_pcap(void) { switch(lib_loaded) { case 0: /* not loaded */ @@ -1544,6 +1559,31 @@ int pcap_setnonblock(pcap_t* a, int nonblock, char *errbuf) { return 0; } } + +#if defined(HAVE_VDE_NETWORK) +/* Dynamic VDE loading */ +static void load_vde (void) +{ + void *handle; + + handle = dlopen("libvdeplug." __STR(SIM_DLOPEN_EXTENSION), RTLD_NOW|RTLD_GLOBAL); + if (handle == NULL) + handle = dlopen("libvdeplug." __STR(SIM_DLOPEN_EXTENSION) ".2", RTLD_NOW|RTLD_GLOBAL); + if (handle != NULL) { +#define _load_function(function) *((_func **)&p_##function) = (_func *)((size_t)dlsym(handle, __STR(function))) + _load_function(vde_open_real); + _load_function(vde_datafd); + _load_function(vde_recv); + _load_function(vde_send); + _load_function(vde_close); +#undef _load_function + } + eth_vde_network_available = (p_vde_open_real != NULL); +} + +#endif + + #endif /* defined(USE_SHARED) && (defined(_WIN32) || defined(SIM_HAVE_DLOPEN)) */ /* Some platforms have always had pcap_sendpacket */ @@ -2046,7 +2086,7 @@ while (dev->handle) { u_char buf[ETH_MAX_JUMBO_FRAME]; memset(&header, 0, sizeof(header)); - len = vde_recv((VDECONN *)dev->handle, buf, sizeof(buf), 0); + len = p_vde_recv((VDECONN *)dev->handle, buf, sizeof(buf), 0); if (len > 0) { status = 1; header.caplen = header.len = len; @@ -2336,34 +2376,38 @@ if (0 == strncmp("tap:", savname, 4)) { else { /* !tap: */ if (0 == strncmp("vde:", savname, 4)) { #if defined(HAVE_VDE_NETWORK) - char vdeswitch_s[CBUFSIZE]; /* VDE switch name */ - char vdeport_s[CBUFSIZE]; /* VDE switch port (optional), numeric */ + if (eth_vde_network_available) { + char vdeswitch_s[CBUFSIZE]; /* VDE switch name */ + char vdeport_s[CBUFSIZE]; /* VDE switch port (optional), numeric */ - struct vde_open_args voa; - const char *devname = savname + 4; + struct vde_open_args voa; + const char *devname = savname + 4; - memset(&voa, 0, sizeof(voa)); - if (!strcmp(savname, "vde:vdedevice")) - return sim_messagef (SCPE_OPENERR, "Eth: Must specify actual vde device name (i.e. vde:/tmp/switch)\n"); - while (isspace(*devname)) - ++devname; - devname = get_glyph_nc (devname, vdeswitch_s, ':'); /* Extract switch name */ - devname = get_glyph_nc (devname, vdeport_s, 0); /* Extract optional port number */ + memset(&voa, 0, sizeof(voa)); + if (!strcmp(savname, "vde:vdedevice")) + return sim_messagef (SCPE_OPENERR, "Eth: Must specify actual vde device name (i.e. vde:/tmp/switch)\n"); + while (isspace(*devname)) + ++devname; + devname = get_glyph_nc (devname, vdeswitch_s, ':'); /* Extract switch name */ + devname = get_glyph_nc (devname, vdeport_s, 0); /* Extract optional port number */ - if (vdeport_s[0]) { /* port provided? */ - t_stat r; + if (vdeport_s[0]) { /* port provided? */ + t_stat r; - voa.port = (int)get_uint (vdeport_s, 10, 255, &r); - if (r != SCPE_OK) - return sim_messagef (SCPE_OPENERR, "Eth: Invalid vde port number: %s in %s\n", vdeport_s, savname); - } - - if (!(*handle = (void*) vde_open((char *)vdeswitch_s, (char *)"simh", &voa))) - strlcpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE); - else { - *eth_api = ETH_API_VDE; - *fd_handle = (SOCKET)vde_datafd((VDECONN*)(*handle)); + voa.port = (int)get_uint (vdeport_s, 10, 255, &r); + if (r != SCPE_OK) + return sim_messagef (SCPE_OPENERR, "Eth: Invalid vde port number: %s in %s\n", vdeport_s, savname); + } + + if (!(*handle = (void*) p_vde_open_real((char *)vdeswitch_s, (char *)"simh", LIBVDEPLUG_INTERFACE_VERSION, &voa))) + strlcpy(errbuf, strerror(errno), PCAP_ERRBUF_SIZE); + else { + *eth_api = ETH_API_VDE; + *fd_handle = (SOCKET)p_vde_datafd((VDECONN*)(*handle)); + } } + else + strlcpy(errbuf, "No support for vde: network devices", PCAP_ERRBUF_SIZE); #else strlcpy(errbuf, "No support for vde: network devices", PCAP_ERRBUF_SIZE); #endif /* defined(HAVE_VDE_NETWORK) */ @@ -2632,7 +2676,7 @@ switch (eth_api) { #endif #ifdef HAVE_VDE_NETWORK case ETH_API_VDE: - vde_close((VDECONN*)pcap); + p_vde_close((VDECONN*)pcap); break; #endif #ifdef HAVE_SLIRP_NETWORK @@ -2697,7 +2741,7 @@ return SCPE_OK; const char *eth_version (void) { -static char version[300]; +static char version[300] = ""; if (version[0] != '\0') return version; @@ -2712,9 +2756,11 @@ if (version[0] != '\0') strlcat (version, "TAP", sizeof (version)); #endif #if defined(HAVE_VDE_NETWORK) -if (version[0] != '\0') - strlcat (version, ", ", sizeof (version)); -strlcat (version, "VDE", sizeof (version)); +if (eth_vde_network_available) { + if (version[0] != '\0') + strlcat (version, ", ", sizeof (version)); + strlcat (version, "VDE", sizeof (version)); + } #endif if (version[0] != '\0') strlcat (version, ", ", sizeof (version)); @@ -2749,7 +2795,8 @@ fprintf (st, " eth0 en0 (No description av fprintf (st, " eth1 tap:tapN (Integrated Tun/Tap support)\n"); #endif #if defined(HAVE_VDE_NETWORK) -fprintf (st, " eth2 vde:device{:switch-port-number} (Integrated VDE support)\n"); +if (eth_vde_network_available) + fprintf (st, " eth2 vde:device{:switch-port-number} (Integrated VDE support)\n"); #endif #if defined(HAVE_SLIRP_NETWORK) fprintf (st, " eth3 nat:{optional-nat-parameters} (Integrated NAT (SLiRP) support)\n"); @@ -3082,7 +3129,7 @@ if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) { #endif #ifdef HAVE_VDE_NETWORK case ETH_API_VDE: - status = vde_send((VDECONN*)dev->handle, (void *)packet->msg, packet->len, 0); + status = p_vde_send((VDECONN*)dev->handle, (void *)packet->msg, packet->len, 0); if ((status == (int)packet->len) || (status == 0)) status = 0; else @@ -3905,7 +3952,7 @@ do { u_char buf[ETH_MAX_JUMBO_FRAME]; memset(&header, 0, sizeof(header)); - len = vde_recv((VDECONN*)dev->handle, buf, sizeof(buf), 0); + len = p_vde_recv((VDECONN*)dev->handle, buf, sizeof(buf), 0); if (len > 0) { status = 1; header.caplen = header.len = len;