From b783deab36d1f8993b6883c63371f2b278ef18fc Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Wed, 2 Sep 2026 13:51:04 +0200 Subject: [PATCH 1/7] hm2_eth: Use library for EVL support A library is needed to avoid having to link hm2_eth to libevl and being able to create a package not depending on libevl. --- src/Makefile | 11 ++-- src/hal/drivers/Submakefile | 11 ++++ src/hal/drivers/mesa-hostmot2/hm2_eth.c | 61 ++++++++++++++++--- .../drivers/mesa-hostmot2/hm2_eth_net_evl.c | 1 + .../drivers/mesa-hostmot2/hm2_eth_net_posix.c | 3 + 5 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/Makefile b/src/Makefile index 2c56a18ed3a..ef7ba15b609 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1080,11 +1080,8 @@ hm2_pci-objs := \ $(MATHSTUB) hm2_eth-objs := \ hal/drivers/mesa-hostmot2/hm2_eth.o \ - hal/drivers/mesa-hostmot2/hm2_eth_net_posix.o -ifeq ($(CONFIG_USPACE_XENOMAI_EVL),y) -hm2_eth-objs += hal/drivers/mesa-hostmot2/hm2_eth_net_evl.o -endif -hm2_eth-objs += $(MATHSTUB) + hal/drivers/mesa-hostmot2/hm2_eth_net_posix.o \ + $(MATHSTUB) hm2_spi-objs := \ hal/drivers/mesa-hostmot2/hm2_spi.o \ hal/drivers/mesa-hostmot2/llio_info.o \ @@ -1329,7 +1326,7 @@ modules: $(patsubst %.o,../rtlib/%.so,$(obj-m)) $(Q)objdump -w -j .rtapi_export -t objects/$*.tmp \ | awk 'BEGIN{print "{ global :"} /rtapi_exported_/{printf("%s;\n", substr($$6,16))} END{print "local : * ; };"}' \ > objects/$*.ver - $(Q)$(CC) -shared -Bsymbolic -Wl,--version-script,objects/$*.ver -o $@ $^ -lm $(XENOMAI_EVL_LDFLAGS) $(LDFLAGS) + $(Q)$(CC) -shared -Bsymbolic -Wl,--version-script,objects/$*.ver -o $@ $^ -lm $(LDFLAGS) $(Q)chmod -x $@ RTFLAGS += -fno-strict-aliasing -fwrapv @@ -1340,7 +1337,7 @@ $(sort $(filter-out objects/rtemc/tp/cruckig/%,$(RTOBJS))) : objects/rt%.o : %.c @rm -f $@ @mkdir -p $(dir $@) $(Q)$(CC) -c $(OPT) $(DEBUG) $(EXTRA_DEBUG) -DRTAPI \ - $(EXTRA_CFLAGS) $(XENOMAI_EVL_CFLAGS) \ + $(EXTRA_CFLAGS) \ -MP -MD -MF "${@:.o=.d}" -MT "$@" \ $< -o $@ diff --git a/src/hal/drivers/Submakefile b/src/hal/drivers/Submakefile index b4ff16113ef..aab6f9dd3ac 100644 --- a/src/hal/drivers/Submakefile +++ b/src/hal/drivers/Submakefile @@ -39,3 +39,14 @@ modules: \ hal/drivers/pluto_step_rbf.h endif + +ifeq ($(CONFIG_USPACE_XENOMAI_EVL),y) +NET_EVL_SRCS := hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c +USERSRCS += $(NET_EVL_SRCS) +$(call TOOBJSDEPS, $(NET_EVL_SRCS)): EXTRAFLAGS += -fPIC $(XENOMAI_EVL_CFLAGS) +../lib/liblinuxcnc-hm2_eth_net_evl.so.0: $(call TOOBJS, $(NET_EVL_SRCS)) + $(ECHO) Linking $(notdir $@) + $(Q)$(CXX) -shared $(LDFLAGS) -o $@ $^ $(XENOMAI_EVL_LDFLAGS) -Wl,-soname,$(notdir $@) +TARGETS += ../lib/liblinuxcnc-hm2_eth_net_evl.so.0 +TARGETS += ../lib/liblinuxcnc-hm2_eth_net_evl.so +endif diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth.c b/src/hal/drivers/mesa-hostmot2/hm2_eth.c index 5dbf3cfae9a..bee0a7e09ba 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -44,15 +45,19 @@ #include -#include "config.h" //For USPACE_XENOMAI_EVL +#include "config.h" //For USPACE_XENOMAI_EVL defines #include "hostmot2-lowlevel.h" #include "hostmot2.h" #include "hm2_eth.h" #include "hm2_eth_net_posix.h" -#ifdef USPACE_XENOMAI_EVL -#include "hm2_eth_net_evl.h" -#endif + +EXPORT_SYMBOL(use_firewall); +EXPORT_SYMBOL(install_firewall_board); +EXPORT_SYMBOL(install_firewall_perinterface); +EXPORT_SYMBOL(clear_firewall); +EXPORT_SYMBOL(fetch_ifname); +EXPORT_SYMBOL(fetch_hwaddr); #define RECV_TIMEOUT_NON_RT_NS (200 * 1000 * 1000) //200ms for initialisation / non-realtime part @@ -815,6 +820,21 @@ int fetch_hwaddr(hm2_eth_t *board, unsigned char buf[6]) { return 0; } +#ifdef USPACE_XENOMAI_EVL +static void *eth_net_evl_lib = NULL; +static bool load_eth_net_evl(void) { + if (eth_net_evl_lib != NULL) { + return true; // Already checked + } + eth_net_evl_lib = dlopen("liblinuxcnc-hm2_eth_net_evl.so", RTLD_LOCAL | RTLD_NOW); + if (!eth_net_evl_lib) { + LL_PRINT("ERROR: EVL support loading library failed: %s\n", dlerror()); + return false; + } + return true; +} +#endif + static int init_board(hm2_eth_t *board, const char *board_ip, const char *board_rtnet){ //Default (NULL) is posix if (board_rtnet == NULL || strcmp(board_rtnet, "posix") == 0) { @@ -829,11 +849,34 @@ static int init_board(hm2_eth_t *board, const char *board_ip, const char *board_ LL_PRINT("ERROR: board_rtnet = %s not available, LinuxCNC not running with Xenomai4 EVL realtime\n", board_rtnet) return -1; } - board->init_board = &hm2_evl_init_board; - board->init_board_realtime = &hm2_evl_init_board_realtime; - board->close_board = &hm2_evl_close_board; - board->eth_socket_send = &hm2_evl_eth_socket_send; - board->eth_socket_recv = &hm2_evl_eth_socket_recv; + if (!load_eth_net_evl()) { + return -1; + } + board->init_board = dlsym(eth_net_evl_lib, "hm2_evl_init_board"); + if (board->init_board == NULL) { + LL_PRINT("ERROR: EVL support dlsym hm2_evl_init_board failed: %s\n", dlerror()); + return -1; + } + board->init_board_realtime = dlsym(eth_net_evl_lib, "hm2_evl_init_board_realtime"); + if (board->init_board_realtime == NULL) { + LL_PRINT("ERROR: EVL support dlsym init_board_realtime failed: %s\n", dlerror()); + return -1; + } + board->close_board = dlsym(eth_net_evl_lib, "hm2_evl_close_board"); + if (board->close_board == NULL) { + LL_PRINT("ERROR: EVL support dlsym hm2_evl_init_close_boardboard failed: %s\n", dlerror()); + return -1; + } + board->eth_socket_send = dlsym(eth_net_evl_lib, "hm2_evl_eth_socket_send"); + if (board->eth_socket_send == NULL) { + LL_PRINT("ERROR: EVL support dlsym eth_socket_send failed: %s\n", dlerror()); + return -1; + } + board->eth_socket_recv = dlsym(eth_net_evl_lib, "hm2_evl_eth_socket_recv"); + if (board->eth_socket_recv == NULL) { + LL_PRINT("ERROR: EVL support dlsym eth_socket_recv failed: %s\n", dlerror()); + return -1; + } #else LL_PRINT("ERROR: board_rtnet = %s not available, LinuxCNC was built without Xenomai EVL support\n", board_rtnet); return -1; diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c index 38958f7e659..e90b84e1c6f 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c @@ -340,3 +340,4 @@ int hm2_evl_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int recv_ti } return ret; } + diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c index 43ae1358ec2..0397536e058 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c @@ -35,6 +35,9 @@ #define SEND_TIMEOUT_US 10 #define RECV_TIMEOUT_US 10 +EXPORT_SYMBOL(hm2_posix_eth_socket_send); +EXPORT_SYMBOL(hm2_posix_eth_socket_recv); + /// ethernet io functions int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip) { From 80b7f8d77f2a5af9c26139329dad7af742a778df Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Wed, 2 Sep 2026 13:56:00 +0200 Subject: [PATCH 2/7] hm2_eth: Rename exported functions ...so they are less likely to conflict and remove not externaly used install_firewall_perinterface from header. --- src/hal/drivers/mesa-hostmot2/hm2_eth.c | 33 +++++++++---------- src/hal/drivers/mesa-hostmot2/hm2_eth.h | 11 +++---- .../drivers/mesa-hostmot2/hm2_eth_net_evl.c | 10 +++--- .../drivers/mesa-hostmot2/hm2_eth_net_posix.c | 10 +++--- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth.c b/src/hal/drivers/mesa-hostmot2/hm2_eth.c index bee0a7e09ba..43543766188 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth.c @@ -52,12 +52,11 @@ #include "hm2_eth.h" #include "hm2_eth_net_posix.h" -EXPORT_SYMBOL(use_firewall); -EXPORT_SYMBOL(install_firewall_board); -EXPORT_SYMBOL(install_firewall_perinterface); -EXPORT_SYMBOL(clear_firewall); -EXPORT_SYMBOL(fetch_ifname); -EXPORT_SYMBOL(fetch_hwaddr); +EXPORT_SYMBOL(hm2_eth_use_firewall); +EXPORT_SYMBOL(hm2_eth_install_firewall_board); +EXPORT_SYMBOL(hm2_eth_clear_firewall); +EXPORT_SYMBOL(hm2_eth_fetch_ifname); +EXPORT_SYMBOL(hm2_eth_fetch_hwaddr); #define RECV_TIMEOUT_NON_RT_NS (200 * 1000 * 1000) //200ms for initialisation / non-realtime part @@ -596,7 +595,7 @@ static fw_state_t fw_state = FW_UNRESOLVED; // Resolve and bring up the firewall backend on first call, caching the // result. Returns true when a backend is ready, false when isolation // is unavailable or disabled. -bool use_firewall() { +bool hm2_eth_use_firewall() { if(fw_state != FW_UNRESOLVED) return fw_state == FW_READY; @@ -643,8 +642,8 @@ bool use_firewall() { // Drop all rules from our chain/table but keep the chain in place, so a // fresh set can be installed on (re-)init. -void clear_firewall() { - if(!use_firewall()) return; +void hm2_eth_clear_firewall() { + if(!hm2_eth_use_firewall()) return; switch(fw_backend) { case FW_IPTABLES: IPT(1, "-F", CHAIN); @@ -660,7 +659,7 @@ void clear_firewall() { // Remove everything we installed: chain, OUTPUT jump, and (nft) table. static void cleanup_firewall() { - if(!use_firewall()) return; + if(!hm2_eth_use_firewall()) return; switch(fw_backend) { case FW_IPTABLES: IPT(1, "-F", CHAIN); @@ -684,7 +683,7 @@ static char* inet_ntoa_buf(struct in_addr in, char *buf, size_t n) { return buf; } -char* fetch_ifname(int sockfd, char *buf, size_t n) { +char* hm2_eth_fetch_ifname(int sockfd, char *buf, size_t n) { struct sockaddr_in srcaddr; struct ifaddrs *ifa, *it; @@ -711,12 +710,12 @@ char* fetch_ifname(int sockfd, char *buf, size_t n) { return NULL; } -int install_firewall_board(int sockfd) { +int hm2_eth_install_firewall_board(int sockfd) { struct sockaddr_in srcaddr, dstaddr; char srchost[16], dsthost[16]; // enough for 255.255.255.255\0 char dport_s[8], sport_s[8]; - if(!use_firewall()) return 0; + if(!hm2_eth_use_firewall()) return 0; socklen_t addrlen = sizeof(srcaddr); int res = getsockname(sockfd, &srcaddr, &addrlen); @@ -756,7 +755,7 @@ int install_firewall_board(int sockfd) { return 0; } -int install_firewall_perinterface(const char *ifbuf) { +static int install_firewall_perinterface(const char *ifbuf) { // Without these rules, 'ping' spews a lot of "Packet filtered" // messages. With them, ping prints 'ping: sendmsg: Operation not // permitted' once per second. @@ -767,7 +766,7 @@ int install_firewall_perinterface(const char *ifbuf) { // grant it to rtapi_app. Users who want full IPv6 quiescence (no // router solicitations etc.) can additionally set // 'net.ipv6.conf..disable_ipv6=1' in /etc/sysctl.conf. - if(!use_firewall()) return 0; + if(!hm2_eth_use_firewall()) return 0; switch(fw_backend) { case FW_IPTABLES: @@ -800,7 +799,7 @@ int install_firewall_perinterface(const char *ifbuf) { return 0; } -int fetch_hwaddr(hm2_eth_t *board, unsigned char buf[6]) { +int hm2_eth_fetch_hwaddr(hm2_eth_t *board, unsigned char buf[6]) { lbp16_cmd_addr packet; unsigned char response[6]; LBP16_INIT_PACKET4(packet, 0x4983, 0x0002); @@ -1718,7 +1717,7 @@ int rtapi_app_main(void) { return ret; comp_id = ret; - clear_firewall(); + hm2_eth_clear_firewall(); for(i = 0, ret = 0; ret == 0 && iip, board_ip, sizeof(board->ip)-1); - char *ifptr = fetch_ifname(board->sockfd, board->ifname, sizeof(board->ifname)); + char *ifptr = hm2_eth_fetch_ifname(board->sockfd, board->ifname, sizeof(board->ifname)); if(!ifptr) { LL_PRINT("failed to retrieve interface name for board\n"); return 0; @@ -82,7 +82,7 @@ int hm2_evl_init_board(hm2_eth_t *board, const char *board_ip) { LL_PRINT("ERROR: can't SO_BINDTODEVICE socket: %s\n", strerror(errno)); } - if (!use_firewall()) { + if (!hm2_eth_use_firewall()) { LL_PRINT(\ "WARNING: Unable to restrict other access to the hm2-eth device.\n" "This means that other software using the same network interface can violate\n" @@ -115,7 +115,7 @@ int hm2_evl_init_board(hm2_eth_t *board, const char *board_ip) { board->req.arp_ha.sa_family = AF_LOCAL; board->req.arp_flags = ATF_PERM | ATF_COM; - ret = fetch_hwaddr( board, (void*)&board->req.arp_ha.sa_data ); + ret = hm2_eth_fetch_hwaddr( board, (void*)&board->req.arp_ha.sa_data ); if (ret < 0) { LL_PRINT("ERROR: Could not retrieve hardware address (MAC) of %s: %s\n", board_ip, strerror(-ret)); return ret; @@ -124,7 +124,7 @@ int hm2_evl_init_board(hm2_eth_t *board, const char *board_ip) { // install_firewall_board() is a no-op when no firewall backend is // available (rootless install without CAP_NET_ADMIN, or // firewall=none), so it is safe to call unconditionally. - ret = install_firewall_board(board->sockfd); + ret = hm2_eth_install_firewall_board(board->sockfd); if (ret < 0) return ret; board->write_packet_ptr = board->write_packet; @@ -225,7 +225,7 @@ int hm2_evl_close_board(hm2_eth_t *board) { board->llio.reset(&board->llio); - clear_firewall(); + hm2_eth_clear_firewall(); ret = close(board->sockfd); if (ret == -1) diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c index 0397536e058..5b20c121531 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c @@ -63,13 +63,13 @@ int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip) { } strncpy(board->ip, board_ip, sizeof(board->ip)-1); - char *ifptr = fetch_ifname(board->sockfd, board->ifname, sizeof(board->ifname)); + char *ifptr = hm2_eth_fetch_ifname(board->sockfd, board->ifname, sizeof(board->ifname)); if(!ifptr) { LL_PRINT("failed to retrieve interface name for board\n"); return 0; } - if(!use_firewall()) { + if(!hm2_eth_use_firewall()) { LL_PRINT(\ "WARNING: Unable to restrict other access to the hm2-eth device.\n" "This means that other software using the same network interface can violate\n" @@ -102,7 +102,7 @@ int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip) { board->req.arp_ha.sa_family = AF_LOCAL; board->req.arp_flags = ATF_PERM | ATF_COM; - ret = fetch_hwaddr( board, (void*)&board->req.arp_ha.sa_data ); + ret = hm2_eth_fetch_hwaddr( board, (void*)&board->req.arp_ha.sa_data ); if(ret < 0) { LL_PRINT("ERROR: Could not retrieve hardware address (MAC) of %s: %s\n", board_ip, strerror(-ret)); return ret; @@ -124,7 +124,7 @@ int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip) { // install_firewall_board() is a no-op when no firewall backend is // available (rootless install without CAP_NET_ADMIN, or // firewall=none), so it is safe to call unconditionally. - ret = install_firewall_board(board->sockfd); + ret = hm2_eth_install_firewall_board(board->sockfd); if(ret < 0) return ret; board->write_packet_ptr = board->write_packet; @@ -142,7 +142,7 @@ int hm2_posix_close_board(hm2_eth_t *board) { int ret; board->llio.reset(&board->llio); - clear_firewall(); + hm2_eth_clear_firewall(); if(board->req.arp_flags & ATF_PERM) { ret = ioctl(board->sockfd, SIOCDARP, &board->req); From e9e27afe4db8163b4c00b7e4f1e5a67f4c1a60ad Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Wed, 2 Sep 2026 14:04:27 +0200 Subject: [PATCH 3/7] hm2_eth: Add Xenomai3 support --- src/Makefile.inc.in | 1 + src/configure.ac | 4 + src/hal/drivers/Submakefile | 11 ++ src/hal/drivers/mesa-hostmot2/hm2_eth.c | 71 ++++++++- .../mesa-hostmot2/hm2_eth_net_xenomai.c | 143 ++++++++++++++++++ .../mesa-hostmot2/hm2_eth_net_xenomai.h | 34 +++++ 6 files changed, 257 insertions(+), 7 deletions(-) create mode 100644 src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c create mode 100644 src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.h diff --git a/src/Makefile.inc.in b/src/Makefile.inc.in index c0ab1ceb631..c051cbb084f 100644 --- a/src/Makefile.inc.in +++ b/src/Makefile.inc.in @@ -235,6 +235,7 @@ RTAI_LXRT_LDFLAGS=@RTAI_LXRT_LDFLAGS@ CONFIG_USPACE_XENOMAI=@CONFIG_USPACE_XENOMAI@ XENOMAI_CFLAGS=@XENOMAI_CFLAGS@ XENOMAI_LDFLAGS=@XENOMAI_LDFLAGS@ +XENOMAI_LDFLAGS_NOINIT=@XENOMAI_LDFLAGS_NOINIT@ CONFIG_USPACE_XENOMAI_EVL=@CONFIG_USPACE_XENOMAI_EVL@ XENOMAI_EVL_CFLAGS=@XENOMAI_EVL_CFLAGS@ diff --git a/src/configure.ac b/src/configure.ac index 88d7959cd96..bb50b7c3550 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -242,17 +242,21 @@ if test "$RTS" = uspace || test -z "$RTS" -a "$RTAI_CONFIG" = "none" ; then CONFIG_USPACE_XENOMAI=n XENOMAI_CFLAGS= XENOMAI_LDFLAGS= + XENOMAI_LDFLAGS_NOINIT= else USPACE_XENOMAI=+xenomai CONFIG_USPACE_XENOMAI=y XENOMAI_CFLAGS=`$XENOMAI_CONFIG --skin posix --cflags` XENOMAI_LDFLAGS=`$XENOMAI_CONFIG --skin posix --ldflags` + #Libs need --no-auto-init, otherwhise, each module initialises xenomai at load + XENOMAI_LDFLAGS_NOINIT=`$XENOMAI_CONFIG --skin posix --ldflags --no-auto-init` AC_DEFINE([USPACE_XENOMAI], [], [Define if uspace realtime should optionally support Xenomai]) fi AC_SUBST([CONFIG_USPACE_XENOMAI]) AC_SUBST([XENOMAI_CFLAGS]) AC_SUBST([XENOMAI_LDFLAGS]) + AC_SUBST([XENOMAI_LDFLAGS_NOINIT]) if test "$HAS_EVL" = "n" ; then USPACE_XENOMAI_EVL= diff --git a/src/hal/drivers/Submakefile b/src/hal/drivers/Submakefile index aab6f9dd3ac..516c9f33843 100644 --- a/src/hal/drivers/Submakefile +++ b/src/hal/drivers/Submakefile @@ -50,3 +50,14 @@ $(call TOOBJSDEPS, $(NET_EVL_SRCS)): EXTRAFLAGS += -fPIC $(XENOMAI_EVL_CFLAGS) TARGETS += ../lib/liblinuxcnc-hm2_eth_net_evl.so.0 TARGETS += ../lib/liblinuxcnc-hm2_eth_net_evl.so endif + +ifeq ($(CONFIG_USPACE_XENOMAI),y) +NET_XENOMAI_SRCS := hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c +USERSRCS += $(NET_XENOMAI_SRCS) +$(call TOOBJSDEPS, $(NET_XENOMAI_SRCS)): EXTRAFLAGS += -fPIC $(XENOMAI_CFLAGS) +../lib/liblinuxcnc-hm2_eth_net_xenomai.so.0: $(call TOOBJS, $(NET_XENOMAI_SRCS)) + $(ECHO) Linking $(notdir $@) + $(Q)$(CXX) -shared $(LDFLAGS) -o $@ $^ $(XENOMAI_LDFLAGS_NOINIT) -Wl,-soname,$(notdir $@) +TARGETS += ../lib/liblinuxcnc-hm2_eth_net_xenomai.so.0 +TARGETS += ../lib/liblinuxcnc-hm2_eth_net_xenomai.so +endif diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth.c b/src/hal/drivers/mesa-hostmot2/hm2_eth.c index 43543766188..8ec9f6ab81d 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth.c @@ -45,7 +45,7 @@ #include -#include "config.h" //For USPACE_XENOMAI_EVL defines +#include "config.h" //For USPACE_XENOMAI_EVL / USPACE_XENOMAI defines #include "hostmot2-lowlevel.h" #include "hostmot2.h" @@ -834,6 +834,21 @@ static bool load_eth_net_evl(void) { } #endif +#ifdef USPACE_XENOMAI_EVL +static void *eth_net_xenomai_lib = NULL; +static bool load_eth_net_xenomai(void) { + if (eth_net_xenomai_lib != NULL) { + return true; // Already checked + } + eth_net_xenomai_lib = dlopen("liblinuxcnc-hm2_eth_net_xenomai.so", RTLD_LOCAL | RTLD_NOW); + if (!eth_net_xenomai_lib) { + LL_PRINT("ERROR: XENOMAI support loading library failed: %s\n", dlerror()); + return false; + } + return true; +} +#endif + static int init_board(hm2_eth_t *board, const char *board_ip, const char *board_rtnet){ //Default (NULL) is posix if (board_rtnet == NULL || strcmp(board_rtnet, "posix") == 0) { @@ -842,6 +857,44 @@ static int init_board(hm2_eth_t *board, const char *board_ip, const char *board_ board->close_board = &hm2_posix_close_board; board->eth_socket_send = &hm2_posix_eth_socket_send; board->eth_socket_recv = &hm2_posix_eth_socket_recv; + } else if (strcmp(board_rtnet, "xenomai") == 0) { +#ifdef USPACE_XENOMAI + if (hal_get_realtime_type() != REALTIME_TYPE_XENOMAI) { + LL_PRINT("ERROR: board_rtnet = %s not available, LinuxCNC not running with Xenomai realtime\n", board_rtnet) + return -1; + } + if (!load_eth_net_xenomai()) { + return -1; + } + board->init_board = dlsym(eth_net_xenomai_lib, "hm2_xenomai_init_board"); + if (board->init_board == NULL) { + LL_PRINT("ERROR: XENOMAI support dlsym hm2_xenomai_init_board failed: %s\n", dlerror()); + return -1; + } + board->init_board_realtime = dlsym(eth_net_xenomai_lib, "hm2_xenomai_init_board_realtime"); + if (board->init_board_realtime == NULL) { + LL_PRINT("ERROR: XENOMAI support dlsym init_board_realtime failed: %s\n", dlerror()); + return -1; + } + board->close_board = dlsym(eth_net_xenomai_lib, "hm2_xenomai_close_board"); + if (board->close_board == NULL) { + LL_PRINT("ERROR: XENOMAI support dlsym hm2_xenomai_init_close_boardboard failed: %s\n", dlerror()); + return -1; + } + board->eth_socket_send = dlsym(eth_net_xenomai_lib, "hm2_xenomai_eth_socket_send"); + if (board->eth_socket_send == NULL) { + LL_PRINT("ERROR: XENOMAI support dlsym eth_socket_send failed: %s\n", dlerror()); + return -1; + } + board->eth_socket_recv = dlsym(eth_net_xenomai_lib, "hm2_xenomai_eth_socket_recv"); + if (board->eth_socket_recv == NULL) { + LL_PRINT("ERROR: XENOMAI support dlsym eth_socket_recv failed: %s\n", dlerror()); + return -1; + } +#else + LL_PRINT("ERROR: board_rtnet = %s not available, LinuxCNC was built without Xenomai support\n", board_rtnet); + return -1; +#endif } else if (strcmp(board_rtnet, "evl") == 0) { #ifdef USPACE_XENOMAI_EVL if (hal_get_realtime_type() != REALTIME_TYPE_XENOMAI_EVL) { @@ -1746,12 +1799,16 @@ int rtapi_app_main(void) { for(i = 0; i 0){ + int *added = kvlist_lookup(&ifnames, boards[i].ifname); + if(!added) + goto error; + if(*added) continue; + install_firewall_perinterface(boards[i].ifname); + *added = 1; + } } hal_export_functf(init_board_realtime_all, 0, 0, 0, comp_id, "%s.realtime-init", HM2_LLIO_NAME); diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c new file mode 100644 index 00000000000..89d925ac092 --- /dev/null +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c @@ -0,0 +1,143 @@ +/* This is a component of LinuxCNC + * Copyright 2013,2014 Michael Geszkiewicz , + * Jeff Epler + * + * Xenomai Port: + * Copyright 2026 Hannes Diethelm + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "hostmot2-lowlevel.h" +#include "hm2_eth_net_xenomai.h" + +#define SEND_TIMEOUT_US 10 +#define RECV_TIMEOUT_US 10 + +/// ethernet io functions + +int hm2_xenomai_init_board(hm2_eth_t *board, const char *board_ip) { + int ret; + LL_PRINT("%s: INFO: init board (XENOMAI)\n", board_ip); + board->sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + if (board->sockfd < 0) { + LL_PRINT("ERROR: can't open socket: %s\n", strerror(errno)); + return -errno; + } + + //Check if socket is rtnet: F_GETFD will + //fail due to this is only supported on normal + //sockets. Nicer alternatives are welcome but + //it looks to be the only option. + //See: kernel/cobalt/rtdm/fd.c + if( fcntl(board->sockfd, F_GETFD) >= 0 ){ + LL_PRINT("ERROR: Socket is not realtime\n" + " Read hm2_eth man page how to enable realtime\n" + " ethernet for Xenomai\n"); + return -1; + } + + board->server_addr.sin_family = AF_INET; + board->server_addr.sin_port = htons(LBP16_UDP_PORT); + board->server_addr.sin_addr.s_addr = inet_addr(board_ip); + + board->local_addr.sin_family = AF_INET; + board->local_addr.sin_addr.s_addr = INADDR_ANY; + + ret = connect(board->sockfd, (struct sockaddr *) &board->server_addr, sizeof(struct sockaddr_in)); + if (ret < 0) { + LL_PRINT("ERROR: can't connect: %s\n", strerror(errno)); + return -errno; + } + + strncpy(board->ip, board_ip, sizeof(board->ip)-1); + + memset(&board->req, 0, sizeof(board->req)); + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *) &board->req.arp_pa; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = inet_addr(board_ip); + + board->req.arp_ha.sa_family = AF_LOCAL; + board->req.arp_flags = ATF_PERM | ATF_COM; + ret = hm2_eth_fetch_hwaddr( board, (void*)&board->req.arp_ha.sa_data ); + if(ret < 0) { + LL_PRINT("ERROR: Could not retrieve hardware address (MAC) of %s: %s\n", board_ip, strerror(-ret)); + return ret; + } + + board->write_packet_ptr = board->write_packet; + board->read_packet_ptr = board->read_packet; + + return 0; +} + +int hm2_xenomai_init_board_realtime(hm2_eth_t *board){ + (void)board; + return 0; //Nothing todo +} + +int hm2_xenomai_close_board(hm2_eth_t *board) { + int ret; + board->llio.reset(&board->llio); + + ret = close(board->sockfd); + if (ret == -1) + LL_PRINT("ERROR: can't close socket: %s\n", strerror(errno)); + + return ret < 0 ? -errno : 0; +} + +int hm2_xenomai_eth_socket_send(hm2_eth_t *board, const void *buffer, int len) { + return send(board->sockfd, buffer, len, 0); +} + +int hm2_xenomai_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns) { + fd_set rfds; + struct timeval tv; + int ret; + + //ppoll is not suported by xenomai, use select + FD_ZERO(&rfds); + FD_SET(board->sockfd, &rfds); + tv.tv_sec = 0; + tv.tv_usec = recv_timeout_ns; + ret = select(board->sockfd+1, &rfds, NULL, NULL, &tv); + + if (ret < 0) { + LL_PRINT("ERROR: select() failed: %m\n"); + } else if(ret) { + ret = recv(board->sockfd, buffer, len, 0); + } else { + errno = EAGAIN; + ret = -1; + } + + return ret; +} diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.h b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.h new file mode 100644 index 00000000000..4fdd51ac17d --- /dev/null +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.h @@ -0,0 +1,34 @@ +/* This is a component of LinuxCNC + * Copyright 2013,2014 Michael Geszkiewicz , + * Jeff Epler + * + * Xenomai Port: + * Copyright 2026 Hannes Diethelm + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __INCLUDE_HM2_ETH_NET_XENOMAI_H +#define __INCLUDE_HM2_ETH_NET_XENOMAI_H + +#include "hm2_eth.h" + +int hm2_xenomai_init_board(hm2_eth_t *board, const char *board_ip); +int hm2_xenomai_init_board_realtime(hm2_eth_t *board); +int hm2_xenomai_close_board(hm2_eth_t *board); +int hm2_xenomai_eth_socket_send(hm2_eth_t *board, const void *buffer, int len); +int hm2_xenomai_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns); + +#endif From c2782e708fceebcda9615a772e485ba366162502 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Wed, 2 Sep 2026 15:40:13 +0200 Subject: [PATCH 4/7] hm2_eth: Reorder code so there is no need to export firewall functions --- src/hal/drivers/mesa-hostmot2/hm2_eth.c | 41 +++++++++++++------ src/hal/drivers/mesa-hostmot2/hm2_eth.h | 7 +--- .../drivers/mesa-hostmot2/hm2_eth_net_evl.c | 16 +------- .../drivers/mesa-hostmot2/hm2_eth_net_posix.c | 16 +------- .../mesa-hostmot2/hm2_eth_net_xenomai.c | 3 +- 5 files changed, 35 insertions(+), 48 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth.c b/src/hal/drivers/mesa-hostmot2/hm2_eth.c index 8ec9f6ab81d..e406f4aa82c 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth.c @@ -52,9 +52,6 @@ #include "hm2_eth.h" #include "hm2_eth_net_posix.h" -EXPORT_SYMBOL(hm2_eth_use_firewall); -EXPORT_SYMBOL(hm2_eth_install_firewall_board); -EXPORT_SYMBOL(hm2_eth_clear_firewall); EXPORT_SYMBOL(hm2_eth_fetch_ifname); EXPORT_SYMBOL(hm2_eth_fetch_hwaddr); @@ -595,7 +592,7 @@ static fw_state_t fw_state = FW_UNRESOLVED; // Resolve and bring up the firewall backend on first call, caching the // result. Returns true when a backend is ready, false when isolation // is unavailable or disabled. -bool hm2_eth_use_firewall() { +static bool use_firewall() { if(fw_state != FW_UNRESOLVED) return fw_state == FW_READY; @@ -642,8 +639,8 @@ bool hm2_eth_use_firewall() { // Drop all rules from our chain/table but keep the chain in place, so a // fresh set can be installed on (re-)init. -void hm2_eth_clear_firewall() { - if(!hm2_eth_use_firewall()) return; +static void clear_firewall() { + if(!use_firewall()) return; switch(fw_backend) { case FW_IPTABLES: IPT(1, "-F", CHAIN); @@ -659,7 +656,7 @@ void hm2_eth_clear_firewall() { // Remove everything we installed: chain, OUTPUT jump, and (nft) table. static void cleanup_firewall() { - if(!hm2_eth_use_firewall()) return; + if(!use_firewall()) return; switch(fw_backend) { case FW_IPTABLES: IPT(1, "-F", CHAIN); @@ -710,12 +707,12 @@ char* hm2_eth_fetch_ifname(int sockfd, char *buf, size_t n) { return NULL; } -int hm2_eth_install_firewall_board(int sockfd) { +static int install_firewall_board(int sockfd) { struct sockaddr_in srcaddr, dstaddr; char srchost[16], dsthost[16]; // enough for 255.255.255.255\0 char dport_s[8], sport_s[8]; - if(!hm2_eth_use_firewall()) return 0; + if(!use_firewall()) return 0; socklen_t addrlen = sizeof(srcaddr); int res = getsockname(sockfd, &srcaddr, &addrlen); @@ -766,7 +763,7 @@ static int install_firewall_perinterface(const char *ifbuf) { // grant it to rtapi_app. Users who want full IPv6 quiescence (no // router solicitations etc.) can additionally set // 'net.ipv6.conf..disable_ipv6=1' in /etc/sysctl.conf. - if(!hm2_eth_use_firewall()) return 0; + if(!use_firewall()) return 0; switch(fw_backend) { case FW_IPTABLES: @@ -938,7 +935,25 @@ static int init_board(hm2_eth_t *board, const char *board_ip, const char *board_ return -1; } - return board->init_board(board, board_ip); + int ret; + ret = board->init_board(board, board_ip); + if (ret < 0) return ret; + + if(board->needs_firewall){ + if(!use_firewall()) { + LL_PRINT(\ + "WARNING: Unable to restrict other access to the hm2-eth device.\n" + "This means that other software using the same network interface can violate\n" + "realtime guarantees. See hm2_eth(9) for more information.\n"); + } + // install_firewall_board() is a no-op when no firewall backend is + // available (rootless install without CAP_NET_ADMIN, or + // firewall=none), so it is safe to call unconditionally. + ret = install_firewall_board(board->sockfd); + if(ret < 0) return ret; + } + + return 0; } /// ethernet io functions mapping @@ -1770,7 +1785,7 @@ int rtapi_app_main(void) { return ret; comp_id = ret; - hm2_eth_clear_firewall(); + clear_firewall(); for(i = 0, ret = 0; ret == 0 && isockfd); - if (ret < 0) return ret; - board->write_packet_ptr = board->write_packet; board->read_packet_ptr = board->read_packet; + board->needs_firewall = true; return 0; } @@ -225,8 +213,6 @@ int hm2_evl_close_board(hm2_eth_t *board) { board->llio.reset(&board->llio); - hm2_eth_clear_firewall(); - ret = close(board->sockfd); if (ret == -1) LL_PRINT("ERROR: can't close socket: %s\n", strerror(errno)); diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c index 5b20c121531..825785390ed 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c @@ -69,13 +69,6 @@ int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip) { return 0; } - if(!hm2_eth_use_firewall()) { - LL_PRINT(\ -"WARNING: Unable to restrict other access to the hm2-eth device.\n" -"This means that other software using the same network interface can violate\n" -"realtime guarantees. See hm2_eth(9) for more information.\n"); - } - struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = RECV_TIMEOUT_US; @@ -121,14 +114,9 @@ int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip) { board->req.arp_flags &= ~ATF_PERM; } - // install_firewall_board() is a no-op when no firewall backend is - // available (rootless install without CAP_NET_ADMIN, or - // firewall=none), so it is safe to call unconditionally. - ret = hm2_eth_install_firewall_board(board->sockfd); - if(ret < 0) return ret; - board->write_packet_ptr = board->write_packet; board->read_packet_ptr = board->read_packet; + board->needs_firewall = true; return 0; } @@ -142,8 +130,6 @@ int hm2_posix_close_board(hm2_eth_t *board) { int ret; board->llio.reset(&board->llio); - hm2_eth_clear_firewall(); - if(board->req.arp_flags & ATF_PERM) { ret = ioctl(board->sockfd, SIOCDARP, &board->req); if(ret < 0) perror("ioctl SIOCDARP"); diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c index 89d925ac092..6b7b0afa2de 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c @@ -94,7 +94,8 @@ int hm2_xenomai_init_board(hm2_eth_t *board, const char *board_ip) { board->write_packet_ptr = board->write_packet; board->read_packet_ptr = board->read_packet; - + board->needs_firewall = false; + return 0; } From 8c80cf1baf6b2a9a6cb0edcac931567846b1f988 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Wed, 2 Sep 2026 21:37:30 +0200 Subject: [PATCH 5/7] Temp Commit: Add up/down scripts for testing --- rtnet_down.sh | 6 ++++++ rtnet_up.sh | 15 +++++++++++++++ 2 files changed, 21 insertions(+) create mode 100755 rtnet_down.sh create mode 100755 rtnet_up.sh diff --git a/rtnet_down.sh b/rtnet_down.sh new file mode 100755 index 00000000000..3888bcd29d1 --- /dev/null +++ b/rtnet_down.sh @@ -0,0 +1,6 @@ +#! /bin/sh +rtifconfig rteth0 down + +rmmod rt_igb +modprobe igb +ifup enp2s0f0 diff --git a/rtnet_up.sh b/rtnet_up.sh new file mode 100755 index 00000000000..68f140aef44 --- /dev/null +++ b/rtnet_up.sh @@ -0,0 +1,15 @@ +#! /bin/sh +ifdown enp2s0f0 + +modprobe rt_loopback +modprobe rtudp +modprobe rtipv4 +rmmod igb +rmmod rt_igb +modprobe rt_igb +rtifconfig rteth0 up 192.168.1.120 netmask 255.255.255.254 +sleep 1 +rtroute solicit 192.168.1.121 dev rteth0 +sleep 1 +rtping 192.168.1.121 + From 5c54eb6eec0f6418d5ccd297a757ee10eb865a61 Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Wed, 2 Sep 2026 21:37:39 +0200 Subject: [PATCH 6/7] hm2_eth: EVL: Simplify initialisation By attaching rtapi_app also to the EVL core, no posix initialisation is needed and all can me set up in rtapi_app_main(). --- src/hal/drivers/mesa-hostmot2/hm2_eth.h | 1 - .../drivers/mesa-hostmot2/hm2_eth_net_evl.c | 169 +++++++----------- .../drivers/mesa-hostmot2/hm2_eth_net_posix.c | 3 - src/rtapi/uspace_xenomai_evl.cc | 12 +- 4 files changed, 79 insertions(+), 106 deletions(-) diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth.h b/src/hal/drivers/mesa-hostmot2/hm2_eth.h index 245e1e32e67..fd96cd035b5 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth.h +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth.h @@ -55,7 +55,6 @@ struct hm2_eth_t { int (*eth_socket_recv)(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns); bool needs_firewall; //Not all rt implementations need firewall - bool is_evl_oob_active; //For evl implementation: oob network active rtapi_u8 read_packet[1400]; rtapi_u8 *read_packet_ptr; diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c index 7b0abbaefe8..70b52892040 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c @@ -38,7 +38,6 @@ #include "hostmot2-lowlevel.h" #include "hm2_eth_net_evl.h" -#include "hm2_eth_net_posix.h" #define SEND_TIMEOUT_US 10 #define RECV_TIMEOUT_US 10 @@ -51,7 +50,12 @@ static int oob_disable_port(hm2_eth_t *board); int hm2_evl_init_board(hm2_eth_t *board, const char *board_ip) { int ret; LL_PRINT("%s: INFO: init board (Xenomai EVL)\n", board_ip); - board->is_evl_oob_active = false; + + if (evl_get_self() < 0) { + LL_PRINT("ERROR: hm2_eth evl mode: Process not attached to EVL core\n"); + return -1; + } + board->sockfd = socket(PF_INET, SOCK_DGRAM | SOCK_OOB, IPPROTO_IP); if (board->sockfd < 0) { LL_PRINT("ERROR: can't open socket: %s\n", strerror(errno)); @@ -82,6 +86,14 @@ int hm2_evl_init_board(hm2_eth_t *board, const char *board_ip) { LL_PRINT("ERROR: can't SO_BINDTODEVICE socket: %s\n", strerror(errno)); } + //oob_enable_port needs: sockfd / server_addr / ip / ifname + //However, it must be called before the first ethernet + //communication in hm2_eth_fetch_hwaddr. + ret = oob_enable_port(board); + if (ret < 0) { + return ret; + } + struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = RECV_TIMEOUT_US; @@ -122,17 +134,8 @@ int hm2_evl_init_board(hm2_eth_t *board, const char *board_ip) { } int hm2_evl_init_board_realtime(hm2_eth_t *board) { - static bool error_shown = false; - if (board->is_evl_oob_active ) { - if (!error_shown) { - LL_PRINT("ERROR: realtime-init called while realtime is allready initialized\n" - " You might be you using \"addf hm2_eth.realtime-init servo-thread\"\n" - " instead of \"initf hm2_eth.realtime-init servo-thread\"\n"); - error_shown = true; - } - return 0; //No failure in this case - } - return oob_enable_port(board); + (void)board; + return 0; //Nothing todo } static int oob_enable_port(hm2_eth_t *board) { @@ -172,8 +175,6 @@ static int oob_enable_port(hm2_eth_t *board) { /*t2 = rtapi_get_time(); LL_PRINT("Enable dur = %lli\n", t2-t1);*/ - board->is_evl_oob_active=true; - return 0; } @@ -202,17 +203,18 @@ static int oob_disable_port(hm2_eth_t *board) { setfsuid(previous); - board->is_evl_oob_active=false; - return 0; } int hm2_evl_close_board(hm2_eth_t *board) { int ret; - oob_disable_port(board); board->llio.reset(&board->llio); + //oob_disable_port must be called after the last + //ethernet communication + oob_disable_port(board); + ret = close(board->sockfd); if (ret == -1) LL_PRINT("ERROR: can't close socket: %s\n", strerror(errno)); @@ -231,99 +233,64 @@ static void print_addr(char* desc, struct sockaddr_in *addr){ } */ -static int check_evl(hm2_eth_t *board) { - static bool error_shown = false; - if (!board->is_evl_oob_active && evl_get_self() >= 0) { - if (!error_shown) { - LL_PRINT("ERROR: hm2_eth evl mode: OOB not active in realtime thread\n" - " Please add: \"initf hm2_eth.realtime-init servo-thread\"\n" - " to your hal file\n"); - error_shown = true; - } - return -1; - } else { - return 0; - } -} - int hm2_evl_eth_socket_send(hm2_eth_t *board, const void *buffer, int len) { ssize_t ret = 0; - ret = check_evl(board); - if (ret < 0) { - return ret; + struct iovec iov; + struct oob_msghdr msghdr; + struct timespec ts_timeout; + + evl_read_clock(EVL_CLOCK_MONOTONIC, &ts_timeout); + ts_timeout.tv_nsec += 1000*SEND_TIMEOUT_US; + while (ts_timeout.tv_nsec >= 1e9) { + ts_timeout.tv_nsec -= 1e9; + ts_timeout.tv_sec ++; } - if (board->is_evl_oob_active) { - struct iovec iov; - struct oob_msghdr msghdr; - struct timespec ts_timeout; - - evl_read_clock(EVL_CLOCK_MONOTONIC, &ts_timeout); - ts_timeout.tv_nsec += 1000*SEND_TIMEOUT_US; - while (ts_timeout.tv_nsec >= 1e9) { - ts_timeout.tv_nsec -= 1e9; - ts_timeout.tv_sec ++; - } - - /* OUTPUT */ - iov.iov_base = (void *)buffer; - iov.iov_len = len; - msghdr.msg_iov = &iov; - msghdr.msg_iovlen = 1; - msghdr.msg_control = NULL; - msghdr.msg_controllen = 0; - msghdr.msg_name = &board->server_addr; - msghdr.msg_namelen = sizeof(board->server_addr); - /*msghdr.msg_name = NULL; - msghdr.msg_namelen = 0;*/ - msghdr.msg_flags = 0; - ret = oob_sendmsg(board->sockfd, &msghdr, &ts_timeout, 0); - if (ret == -1) { - LL_PRINT("ERROR: oob_sendmsg %m %i %li\n", errno, ret); - } - } else { - //While initialisation, use posix mode due - //to we are not in an evl thread - ret = hm2_posix_eth_socket_send(board, buffer, len); + + /* OUTPUT */ + iov.iov_base = (void *)buffer; + iov.iov_len = len; + msghdr.msg_iov = &iov; + msghdr.msg_iovlen = 1; + msghdr.msg_control = NULL; + msghdr.msg_controllen = 0; + msghdr.msg_name = &board->server_addr; + msghdr.msg_namelen = sizeof(board->server_addr); + /*msghdr.msg_name = NULL; + msghdr.msg_namelen = 0;*/ + msghdr.msg_flags = 0; + ret = oob_sendmsg(board->sockfd, &msghdr, &ts_timeout, 0); + if (ret == -1) { + LL_PRINT("ERROR: oob_sendmsg %m %i %li\n", errno, ret); } return ret; } int hm2_evl_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns) { ssize_t ret = 0; - ret = check_evl(board); - if (ret < 0) { - return ret; - } - if (board->is_evl_oob_active) { - struct oob_msghdr msghdr; - struct iovec iov; - struct timespec ts_timeout; - - evl_read_clock(EVL_CLOCK_MONOTONIC, &ts_timeout); - ts_timeout.tv_nsec += recv_timeout_ns; - while (ts_timeout.tv_nsec >= 1e9) { - ts_timeout.tv_nsec -= 1e9; - ts_timeout.tv_sec ++; - } - - /* INPUT */ - iov.iov_base = buffer; - iov.iov_len = len; - msghdr.msg_iov = &iov; - msghdr.msg_iovlen = 1; - msghdr.msg_control = NULL; - msghdr.msg_controllen = 0; - msghdr.msg_name = &board->local_addr; - msghdr.msg_namelen = sizeof(board->local_addr); - /*msghdr.msg_name = NULL; - msghdr.msg_namelen = 0;*/ - msghdr.msg_flags = 0; - ret = oob_recvmsg(board->sockfd, &msghdr, &ts_timeout, 0); - } else { - //While initialisation, use posix mode due - //to we are not in an evl thread - ret = hm2_posix_eth_socket_recv(board, buffer, len, recv_timeout_ns); + struct oob_msghdr msghdr; + struct iovec iov; + struct timespec ts_timeout; + + evl_read_clock(EVL_CLOCK_MONOTONIC, &ts_timeout); + ts_timeout.tv_nsec += recv_timeout_ns; + while (ts_timeout.tv_nsec >= 1e9) { + ts_timeout.tv_nsec -= 1e9; + ts_timeout.tv_sec ++; } + + /* INPUT */ + iov.iov_base = buffer; + iov.iov_len = len; + msghdr.msg_iov = &iov; + msghdr.msg_iovlen = 1; + msghdr.msg_control = NULL; + msghdr.msg_controllen = 0; + msghdr.msg_name = &board->local_addr; + msghdr.msg_namelen = sizeof(board->local_addr); + /*msghdr.msg_name = NULL; + msghdr.msg_namelen = 0;*/ + msghdr.msg_flags = 0; + ret = oob_recvmsg(board->sockfd, &msghdr, &ts_timeout, 0); return ret; } diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c index 825785390ed..3a196ca0e96 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c @@ -35,9 +35,6 @@ #define SEND_TIMEOUT_US 10 #define RECV_TIMEOUT_US 10 -EXPORT_SYMBOL(hm2_posix_eth_socket_send); -EXPORT_SYMBOL(hm2_posix_eth_socket_recv); - /// ethernet io functions int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip) { diff --git a/src/rtapi/uspace_xenomai_evl.cc b/src/rtapi/uspace_xenomai_evl.cc index 84f997900fa..d50b17d97b9 100644 --- a/src/rtapi/uspace_xenomai_evl.cc +++ b/src/rtapi/uspace_xenomai_evl.cc @@ -49,6 +49,16 @@ struct EvlTask : RtapiTask { struct EvlApp : RtapiApp { EvlApp() : RtapiApp(SCHED_FIFO) { pthread_once(&key_once, init_key); + WithRoot r; + /* Attach to the EVL core for rtapi_app, so modules can use EVL core + * functions also in rtapi_app_main. This has no influence on realtime + * due to rtapi_app will run with SCHED_WEAK. + */ + int tfd = evl_attach_self("linuxcnc-rtapi_app:%d", gettid()); + if (tfd < 0) { + rtapi_print("evl_attach_self() failed ret %i errno %i\n", tfd, errno); + throw std::invalid_argument("evl_attach_self() failed"); + } } RtapiTask *do_task_new() { @@ -120,7 +130,7 @@ struct EvlApp : RtapiApp { { WithRoot r; /* Attach to the core. */ - int tfd = evl_attach_self("linuxcnc-thread:%d", gettid()); + int tfd = evl_attach_self("linuxcnc-realtime:%d", gettid()); if (tfd < 0) { rtapi_print("evl_attach_self() failed ret %i errno %i\n", tfd, errno); return nullptr; From e023330aa94fce9c2bb9e408c03e8da57f45244e Mon Sep 17 00:00:00 2001 From: Hannes Diethelm Date: Wed, 2 Sep 2026 21:37:46 +0200 Subject: [PATCH 7/7] hm2_eth: Deprecate realtime-init This is not needed any more. --- docs/src/man/man9/hm2_eth.9.adoc | 10 ---------- src/hal/drivers/mesa-hostmot2/hm2_eth.c | 20 +------------------ src/hal/drivers/mesa-hostmot2/hm2_eth.h | 1 - .../drivers/mesa-hostmot2/hm2_eth_net_evl.c | 5 ----- .../drivers/mesa-hostmot2/hm2_eth_net_posix.c | 5 ----- .../mesa-hostmot2/hm2_eth_net_xenomai.c | 5 ----- 6 files changed, 1 insertion(+), 45 deletions(-) diff --git a/docs/src/man/man9/hm2_eth.9.adoc b/docs/src/man/man9/hm2_eth.9.adoc index 0e6e3b43dcf..8197a7508ab 100644 --- a/docs/src/man/man9/hm2_eth.9.adoc +++ b/docs/src/man/man9/hm2_eth.9.adoc @@ -156,16 +156,6 @@ hm2_____.____.packet-read-timeout (s32, rw):: Setting this value too low can cause spurious read errors. Setting it too high can cause realtime delay errors. -== FUNCTIONS - -hm2_eth.realtime-init:: - Realtime initialization function. This function initializes the realtime - ethernet for *evl*. With *posix*, this function is not needed. - It needs to be called once at startup using: -.... -initf hm2_eth.realtime-init servo-thread -.... - == NOTES hm2_eth installs firewall rules to control the network interface while diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth.c b/src/hal/drivers/mesa-hostmot2/hm2_eth.c index e406f4aa82c..07875811b8e 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth.c @@ -850,7 +850,6 @@ static int init_board(hm2_eth_t *board, const char *board_ip, const char *board_ //Default (NULL) is posix if (board_rtnet == NULL || strcmp(board_rtnet, "posix") == 0) { board->init_board = &hm2_posix_init_board; - board->init_board_realtime = &hm2_posix_init_board_realtime; board->close_board = &hm2_posix_close_board; board->eth_socket_send = &hm2_posix_eth_socket_send; board->eth_socket_recv = &hm2_posix_eth_socket_recv; @@ -868,11 +867,6 @@ static int init_board(hm2_eth_t *board, const char *board_ip, const char *board_ LL_PRINT("ERROR: XENOMAI support dlsym hm2_xenomai_init_board failed: %s\n", dlerror()); return -1; } - board->init_board_realtime = dlsym(eth_net_xenomai_lib, "hm2_xenomai_init_board_realtime"); - if (board->init_board_realtime == NULL) { - LL_PRINT("ERROR: XENOMAI support dlsym init_board_realtime failed: %s\n", dlerror()); - return -1; - } board->close_board = dlsym(eth_net_xenomai_lib, "hm2_xenomai_close_board"); if (board->close_board == NULL) { LL_PRINT("ERROR: XENOMAI support dlsym hm2_xenomai_init_close_boardboard failed: %s\n", dlerror()); @@ -906,11 +900,6 @@ static int init_board(hm2_eth_t *board, const char *board_ip, const char *board_ LL_PRINT("ERROR: EVL support dlsym hm2_evl_init_board failed: %s\n", dlerror()); return -1; } - board->init_board_realtime = dlsym(eth_net_evl_lib, "hm2_evl_init_board_realtime"); - if (board->init_board_realtime == NULL) { - LL_PRINT("ERROR: EVL support dlsym init_board_realtime failed: %s\n", dlerror()); - return -1; - } board->close_board = dlsym(eth_net_evl_lib, "hm2_evl_close_board"); if (board->close_board == NULL) { LL_PRINT("ERROR: EVL support dlsym hm2_evl_init_close_boardboard failed: %s\n", dlerror()); @@ -958,10 +947,6 @@ static int init_board(hm2_eth_t *board, const char *board_ip, const char *board_ /// ethernet io functions mapping -static inline int init_board_realtime(hm2_eth_t *board){ - return board->init_board_realtime(board); -} - static inline int close_board(hm2_eth_t *board){ return board->close_board(board); } @@ -1766,10 +1751,7 @@ static int hm2_eth_items(hm2_eth_t *board) { void init_board_realtime_all(void *arg, long period){ (void)arg; (void)period; - int i; - for(i = 0; i < boards_count; i++) { - init_board_realtime(&boards[i]); - } + LL_PRINT("DEPRECATED: \"initf hm2_eth.realtime-init\" is not needed and will be removed\n"); } int rtapi_app_main(void) { diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth.h b/src/hal/drivers/mesa-hostmot2/hm2_eth.h index fd96cd035b5..871d1ed5fad 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth.h +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth.h @@ -49,7 +49,6 @@ struct hm2_eth_t { //RT network specific functions int (*init_board)(hm2_eth_t *board, const char *board_ip); - int (*init_board_realtime)(hm2_eth_t *board); int (*close_board)(hm2_eth_t *board); int (*eth_socket_send)(hm2_eth_t *board, const void *buffer, int len); int (*eth_socket_recv)(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns); diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c index 70b52892040..3cf5cbd3560 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.c @@ -133,11 +133,6 @@ int hm2_evl_init_board(hm2_eth_t *board, const char *board_ip) { return 0; } -int hm2_evl_init_board_realtime(hm2_eth_t *board) { - (void)board; - return 0; //Nothing todo -} - static int oob_enable_port(hm2_eth_t *board) { //long long t1, t2; int devfd, ret; diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c index 3a196ca0e96..40221877668 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c @@ -118,11 +118,6 @@ int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip) { return 0; } -int hm2_posix_init_board_realtime(hm2_eth_t *board){ - (void)board; - return 0; //Nothing todo -} - int hm2_posix_close_board(hm2_eth_t *board) { int ret; board->llio.reset(&board->llio); diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c index 6b7b0afa2de..b9ce8708b9b 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_xenomai.c @@ -99,11 +99,6 @@ int hm2_xenomai_init_board(hm2_eth_t *board, const char *board_ip) { return 0; } -int hm2_xenomai_init_board_realtime(hm2_eth_t *board){ - (void)board; - return 0; //Nothing todo -} - int hm2_xenomai_close_board(hm2_eth_t *board) { int ret; board->llio.reset(&board->llio);