diff --git a/docs/src/man/man9/hm2_eth.9.adoc b/docs/src/man/man9/hm2_eth.9.adoc index 0e6e3b43dcf..c158c93f3db 100644 --- a/docs/src/man/man9/hm2_eth.9.adoc +++ b/docs/src/man/man9/hm2_eth.9.adoc @@ -159,12 +159,7 @@ 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 -.... + Deprecated, this function has no effect. == NOTES diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth.c b/src/hal/drivers/mesa-hostmot2/hm2_eth.c index 5dbf3cfae9a..4ffd8bdbcc5 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth.c @@ -591,7 +591,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() { +static bool use_firewall() { if(fw_state != FW_UNRESOLVED) return fw_state == FW_READY; @@ -638,7 +638,7 @@ 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() { +static void clear_firewall() { if(!use_firewall()) return; switch(fw_backend) { case FW_IPTABLES: @@ -706,7 +706,7 @@ char* fetch_ifname(int sockfd, char *buf, size_t n) { return NULL; } -int 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]; @@ -751,7 +751,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. @@ -819,7 +819,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; @@ -830,7 +829,6 @@ static int init_board(hm2_eth_t *board, const char *board_ip, const char *board_ 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; @@ -843,15 +841,28 @@ 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; -/// ethernet io functions mapping + 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"); + } -static inline int init_board_realtime(hm2_eth_t *board){ - return board->init_board_realtime(board); + // 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 + static inline int close_board(hm2_eth_t *board){ return board->close_board(board); } @@ -1059,9 +1070,8 @@ static int hm2_eth_receive_queued_reads(hm2_lowlevel_io_t *this) { } static int hm2_eth_reset(hm2_lowlevel_io_t *this) { - LL_PRINT("in hm2_eth_reset\n"); - hm2_eth_t *board = this->private; + LL_PRINT("%s: INFO: reset\n", board->ip); // Make the watchdog timer bite in 1ns from now lbp16_cmd_addr_data32 bite_packet; @@ -1656,10 +1666,27 @@ static int hm2_eth_items(hm2_eth_t *board) { void init_board_realtime_all(void *arg, long period){ (void)arg; (void)period; + LL_PRINT("DEPRECATED: \"initf hm2_eth.realtime-init\" is not needed and will be removed\n"); +} + +static void cleanup(void){ int i; - for(i = 0; i < boards_count; i++) { - init_board_realtime(&boards[i]); - } + comm_active = 0; + //Reset all boards + 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; + } else { + LL_PRINT("%s: WARNING: interface name for board unknown, skipping per interface firewall\n", + boards[i].ip); + } } hal_export_functf(init_board_realtime_all, 0, 0, 0, comp_id, "%s.realtime-init", HM2_LLIO_NAME); @@ -1719,28 +1751,12 @@ int rtapi_app_main(void) { return 0; error: - for(i = 0; iis_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)); @@ -67,26 +71,32 @@ int hm2_evl_init_board(hm2_eth_t *board, const char *board_ip) { ret = connect(board->sockfd, (struct sockaddr *) &board->server_addr, sizeof(struct sockaddr_in)); if (ret < 0) { + ret = -errno; LL_PRINT("ERROR: can't connect: %s\n", strerror(errno)); - return -errno; + hm2_evl_close_board(board); + return ret; } strncpy(board->ip, board_ip, sizeof(board->ip)-1); char *ifptr = fetch_ifname(board->sockfd, board->ifname, sizeof(board->ifname)); if(!ifptr) { - LL_PRINT("failed to retrieve interface name for board\n"); - return 0; + //Interface name is mandatory for EVL + LL_PRINT("ERROR: failed to retrieve interface name for board\n"); + hm2_evl_close_board(board); + return -1; } if (setsockopt(board->sockfd, SOL_SOCKET, SO_BINDTODEVICE, board->ifname, strlen(board->ifname))) { LL_PRINT("ERROR: can't SO_BINDTODEVICE socket: %s\n", strerror(errno)); } - 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"); + //oob_enable_port needs: sockfd / server_addr / ip / ifname + //However, it must be called before the first ethernet + //communication in fetch_hwaddr. + ret = oob_enable_port(board); + if (ret < 0) { + hm2_evl_close_board(board); + return ret; } struct timeval timeout; @@ -94,16 +104,20 @@ int hm2_evl_init_board(hm2_eth_t *board, const char *board_ip) { timeout.tv_usec = RECV_TIMEOUT_US; ret = setsockopt(board->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); if (ret < 0) { + ret = -errno; LL_PRINT("ERROR: can't set receive timeout socket option: %s\n", strerror(errno)); - return -errno; + hm2_evl_close_board(board); + return ret; } timeout.tv_sec = 0; timeout.tv_usec = SEND_TIMEOUT_US; ret = setsockopt(board->sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)); if (ret < 0) { + ret = -errno; LL_PRINT("ERROR: can't set send timeout socket option: %s\n", strerror(errno)); - return -errno; + hm2_evl_close_board(board); + return ret; } memset(&board->req, 0, sizeof(board->req)); @@ -118,35 +132,16 @@ int hm2_evl_init_board(hm2_eth_t *board, const char *board_ip) { ret = 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)); + hm2_evl_close_board(board); return ret; } - // 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; - board->write_packet_ptr = board->write_packet; board->read_packet_ptr = board->read_packet; return 0; } -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); -} - static int oob_enable_port(hm2_eth_t *board) { //long long t1, t2; int devfd, ret; @@ -175,7 +170,7 @@ static int oob_enable_port(hm2_eth_t *board) { ret = evl_net_solicit(board->sockfd, (struct sockaddr*)&board->server_addr, EVL_NEIGH_PERMANENT); if (ret) { - LL_PRINT("solicit did not respond\n"); + LL_PRINT("ERROR: solicit did not respond\n"); return -1; } @@ -184,8 +179,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; } @@ -214,18 +207,17 @@ 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); - - clear_firewall(); + //If ifname is not set, the board was never initialized fully + //No need to disable oob + if (strnlen(board->ifname, sizeof(board->ifname)) > 0) { + oob_disable_port(board); + } ret = close(board->sockfd); if (ret == -1) @@ -245,98 +237,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_evl.h b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.h index 6136c99b6d8..9337a434890 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.h +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_evl.h @@ -26,7 +26,6 @@ #include "hm2_eth.h" int hm2_evl_init_board(hm2_eth_t *board, const char *board_ip); -int hm2_evl_init_board_realtime(hm2_eth_t *board); int hm2_evl_close_board(hm2_eth_t *board); int hm2_evl_eth_socket_send(hm2_eth_t *board, const void *buffer, int len); int hm2_evl_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_posix.c b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c index 43ae1358ec2..6e8b0d30d3c 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.c @@ -55,22 +55,17 @@ int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip) { ret = connect(board->sockfd, (struct sockaddr *) &board->server_addr, sizeof(struct sockaddr_in)); if (ret < 0) { + ret = -errno; LL_PRINT("ERROR: can't connect: %s\n", strerror(errno)); - return -errno; + hm2_posix_close_board(board); + return ret; } strncpy(board->ip, board_ip, sizeof(board->ip)-1); char *ifptr = 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()) { - 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"); + //Interface name is only needed for firewall, we can continue + LL_PRINT("WARNING: failed to retrieve interface name for board\n"); } struct timeval timeout; @@ -78,16 +73,20 @@ int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip) { timeout.tv_usec = RECV_TIMEOUT_US; ret = setsockopt(board->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); if (ret < 0) { + ret = -errno; LL_PRINT("ERROR: can't set receive timeout socket option: %s\n", strerror(errno)); - return -errno; + hm2_posix_close_board(board); + return ret; } timeout.tv_sec = 0; timeout.tv_usec = SEND_TIMEOUT_US; ret = setsockopt(board->sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)); if (ret < 0) { + ret = -errno; LL_PRINT("ERROR: can't set send timeout socket option: %s\n", strerror(errno)); - return -errno; + hm2_posix_close_board(board); + return ret; } memset(&board->req, 0, sizeof(board->req)); @@ -102,6 +101,8 @@ int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip) { ret = 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)); + board->req.arp_flags &= ~ATF_PERM; + hm2_posix_close_board(board); return ret; } @@ -118,28 +119,14 @@ 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 = install_firewall_board(board->sockfd); - if(ret < 0) return ret; - board->write_packet_ptr = board->write_packet; board->read_packet_ptr = board->read_packet; 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); - - clear_firewall(); if(board->req.arp_flags & ATF_PERM) { ret = ioctl(board->sockfd, SIOCDARP, &board->req); diff --git a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.h b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.h index 87aca6e074c..82f8aaf5916 100644 --- a/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.h +++ b/src/hal/drivers/mesa-hostmot2/hm2_eth_net_posix.h @@ -23,7 +23,6 @@ #include "hm2_eth.h" int hm2_posix_init_board(hm2_eth_t *board, const char *board_ip); -int hm2_posix_init_board_realtime(hm2_eth_t *board); int hm2_posix_close_board(hm2_eth_t *board); int hm2_posix_eth_socket_send(hm2_eth_t *board, const void *buffer, int len); int hm2_posix_eth_socket_recv(hm2_eth_t *board, void *buffer, int len, int recv_timeout_ns); 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;