diff options
Diffstat (limited to 'src/ipcpd/eth')
| -rw-r--r-- | src/ipcpd/eth/CMakeLists.txt | 155 | ||||
| -rw-r--r-- | src/ipcpd/eth/dix.c | 2 | ||||
| -rw-r--r-- | src/ipcpd/eth/eth.c | 461 | ||||
| -rw-r--r-- | src/ipcpd/eth/llc.c | 2 |
4 files changed, 304 insertions, 316 deletions
diff --git a/src/ipcpd/eth/CMakeLists.txt b/src/ipcpd/eth/CMakeLists.txt index d57e1848..5a36352d 100644 --- a/src/ipcpd/eth/CMakeLists.txt +++ b/src/ipcpd/eth/CMakeLists.txt @@ -1,134 +1,21 @@ -get_filename_component(CURRENT_SOURCE_PARENT_DIR - ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) -get_filename_component(CURRENT_BINARY_PARENT_DIR - ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -include_directories(${CURRENT_SOURCE_PARENT_DIR}) -include_directories(${CURRENT_BINARY_PARENT_DIR}) - -include_directories(${CMAKE_SOURCE_DIR}/include) -include_directories(${CMAKE_BINARY_DIR}/include) - -find_path(NETMAP_C_INCLUDE_DIR - net/netmap_user.h - HINTS /usr/include /usr/local/include) - -mark_as_advanced(NETMAP_C_INCLUDE_DIR) - -# Check for raw sockets -if (CMAKE_SYSTEM_NAME STREQUAL "Linux") - set(DISABLE_RAW_SOCKETS FALSE CACHE BOOL - "Disable raw socket support for Ethernet IPCPs") - if (NOT DISABLE_RAW_SOCKETS) - message(STATUS "Raw socket support for Ethernet IPCPs enabled") - set(HAVE_RAW_SOCKETS TRUE PARENT_SCOPE) - set(HAVE_RAW_SOCKETS TRUE) - set(HAVE_ETH TRUE) - else () - message(STATUS "Raw socket support for Ethernet IPCPs disabled by user") - unset(HAVE_RAW_SOCKETS PARENT_SCOPE) - unset(HAVE_RAW_SOCKETS) - endif () -endif () - -# Check for BPF -if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux") - find_path(BPF_C_INCLUDE_DIR - net/bpf.h - HINTS /usr/include /usr/local/include) - - mark_as_advanced(BPF_C_INCLUDE_DIR) - - if (BPF_C_INCLUDE_DIR) - set(DISABLE_BPF FALSE CACHE BOOL - "Disable Berkeley Packet Filter support for Ethernet IPCPs") - if (NOT DISABLE_BPF) - message(STATUS "Berkeley Packet Filter support " - "for Ethernet IPCPs enabled") - set(HAVE_BPF TRUE PARENT_SCOPE) - set(HAVE_BPF TRUE) - set(HAVE_ETH TRUE) - else () - message(STATUS "Berkeley Packet Filter support " - "for Ethernet IPCPs disabled by user") - unset(HAVE_BPF PARENT_SCOPE) - unset(HAVE_BPF) - endif () - endif () -endif () - -# Check for netmap exclusively -if (NOT HAVE_RAW_SOCKETS AND NOT HAVE_BPF AND NETMAP_C_INCLUDE_DIR) - set(DISABLE_NETMAP FALSE CACHE BOOL - "Disable netmap support for ETH IPCPs") - if (NOT DISABLE_NETMAP) - message(STATUS "Netmap support for Ethernet IPCPs enabled") - set(HAVE_NETMAP TRUE PARENT_SCOPE) - set(HAVE_ETH TRUE) - else () - message(STATUS "Netmap support for Ethernet IPCPs disabled by user") - unset(HAVE_NETMAP PARENT_SCOPE) - endif () -endif () - -if (HAVE_ETH) - message(STATUS "Supported raw packet API found, building eth-llc and eth-dix") - - set(IPCP_ETH_RD_THR 1 CACHE STRING - "Number of reader threads in Ethernet IPCP") - set(IPCP_ETH_WR_THR 1 CACHE STRING - "Number of writer threads in Ethernet IPCP") - set(IPCP_ETH_QDISC_BYPASS false CACHE BOOL - "Bypass the Qdisc in the kernel when using raw sockets") - set(IPCP_ETH_LO_MTU 1500 CACHE STRING - "Restrict Ethernet MTU over loopback interfaces") - set(IPCP_ETH_MPL 5 CACHE STRING - "Default maximum packet lifetime for the Ethernet IPCPs, in seconds") - - set(ETH_LLC_SOURCES - # Add source files here - ${CMAKE_CURRENT_SOURCE_DIR}/llc.c - ) - - set(ETH_DIX_SOURCES - # Add source files here - ${CMAKE_CURRENT_SOURCE_DIR}/dix.c - ) - - set(IPCP_ETH_LLC_TARGET ipcpd-eth-llc CACHE INTERNAL "") - set(IPCP_ETH_DIX_TARGET ipcpd-eth-dix CACHE INTERNAL "") - - add_executable(ipcpd-eth-llc ${ETH_LLC_SOURCES} ${IPCP_SOURCES}) - add_executable(ipcpd-eth-dix ${ETH_DIX_SOURCES} ${IPCP_SOURCES}) - - if (HAVE_BPF AND NOT APPLE) - target_include_directories(ipcpd-eth-llc PUBLIC ${BPF_C_INCLUDE_DIR}) - target_include_directories(ipcpd-eth-dix PUBLIC ${BPF_C_INCLUDE_DIR}) - endif () - - if (HAVE_NETMAP AND NOT APPLE) - set_target_properties(ipcpd-eth-llc PROPERTIES - COMPILE_FLAGS "${CMAKE_C_FLAGS} -std=c99") - set_target_properties(ipcpd-eth-dix PROPERTIES - COMPILE_FLAGS "${CMAKE_C_FLAGS} -std=c99") - target_include_directories(ipcpd-eth-llc PUBLIC - ${NETMAP_C_INCLUDE_DIR}) - target_include_directories(ipcpd-eth-dix PUBLIC - ${NETMAP_C_INCLUDE_DIR}) - endif () - - target_link_libraries(ipcpd-eth-llc LINK_PUBLIC ouroboros-dev) - target_link_libraries(ipcpd-eth-dix LINK_PUBLIC ouroboros-dev) - - include(AddCompileFlags) - if (CMAKE_BUILD_TYPE MATCHES "Debug*") - add_compile_flags(ipcpd-eth-llc -DCONFIG_OUROBOROS_DEBUG) - add_compile_flags(ipcpd-eth-dix -DCONFIG_OUROBOROS_DEBUG) - endif () - - install(TARGETS ipcpd-eth-llc ipcpd-eth-dix RUNTIME DESTINATION - ${CMAKE_INSTALL_SBINDIR}) -endif () +# Ethernet IPCPs build configuration (LLC and DIX) +# HAVE_ETH detection is in cmake/dependencies.cmake + +add_executable(${IPCP_ETH_LLC_TARGET} llc.c ${IPCP_SOURCES}) +add_executable(${IPCP_ETH_DIX_TARGET} dix.c ${IPCP_SOURCES}) + +foreach(target ${IPCP_ETH_LLC_TARGET} ${IPCP_ETH_DIX_TARGET}) + target_include_directories(${target} PRIVATE ${IPCP_INCLUDE_DIRS}) + if(HAVE_BPF AND NOT APPLE) + target_include_directories(${target} PRIVATE ${BPF_C_INCLUDE_DIR}) + endif() + if(HAVE_NETMAP AND NOT APPLE) + target_compile_options(${target} PRIVATE -std=c99) + target_include_directories(${target} PRIVATE ${NETMAP_C_INCLUDE_DIR}) + endif() + target_link_libraries(${target} PRIVATE ouroboros-dev) + ouroboros_target_debug_definitions(${target}) +endforeach() + +install(TARGETS ${IPCP_ETH_LLC_TARGET} ${IPCP_ETH_DIX_TARGET} + RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}) diff --git a/src/ipcpd/eth/dix.c b/src/ipcpd/eth/dix.c index 37b9896d..cf8253bd 100644 --- a/src/ipcpd/eth/dix.c +++ b/src/ipcpd/eth/dix.c @@ -1,5 +1,5 @@ /* - * Ouroboros - Copyright (C) 2016 - 2024 + * Ouroboros - Copyright (C) 2016 - 2026 * * IPC processes over Ethernet - DIX * diff --git a/src/ipcpd/eth/eth.c b/src/ipcpd/eth/eth.c index c0e6d0ce..4be7775e 100644 --- a/src/ipcpd/eth/eth.c +++ b/src/ipcpd/eth/eth.c @@ -1,5 +1,5 @@ /* - * Ouroboros - Copyright (C) 2016 - 2024 + * Ouroboros - Copyright (C) 2016 - 2026 * * IPC processes over Ethernet * @@ -52,6 +52,7 @@ #include <ouroboros/pthread.h> #include "ipcp.h" +#include "np1.h" #include "shim-data.h" #include <signal.h> @@ -88,31 +89,31 @@ #include <sys/mman.h> #if defined(HAVE_NETMAP) -#define NETMAP_WITH_LIBS -#include <net/netmap_user.h> + #define NETMAP_WITH_LIBS + #include <net/netmap_user.h> #elif defined(HAVE_BPF) -#define BPF_DEV_MAX 256 -#define BPF_BLEN sysconf(_SC_PAGESIZE) -#include <net/bpf.h> + #define BPF_DEV_MAX 256 + #define BPF_BLEN sysconf(_SC_PAGESIZE) + #include <net/bpf.h> #endif -#ifdef __linux__ +#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_VAL(a) \ + (uint8_t)(a)[0], (uint8_t)(a)[1], (uint8_t)(a)[2], \ + (uint8_t)(a)[3], (uint8_t)(a)[4], (uint8_t)(a)[5] + + #ifndef ETH_MAX_MTU /* In if_ether.h as of Linux 4.10. */ -#define ETH_MAX_MTU 0xFFFFU + #define ETH_MAX_MTU 0xFFFFU #endif /* ETH_MAX_MTU */ #ifdef BUILD_ETH_DIX -#define ETH_MTU eth_data.mtu -#define ETH_MTU_MAX ETH_MAX_MTU + #define ETH_MTU eth_data.mtu + #define ETH_MTU_MAX ETH_MAX_MTU #else -#define ETH_MTU eth_data.mtu -#define ETH_MTU_MAX 1500 + #define ETH_MTU eth_data.mtu + #define ETH_MTU_MAX 1500 #endif /* BUILD_ETH_DIX */ -#else /* __linux__ */ -#define ETH_MTU 1500 -#define ETH_MTU_MAX ETH_MTU -#endif /* __linux__ */ -#define MAC_SIZE 6 #define ETH_TYPE_LENGTH_SIZE sizeof(uint16_t) #define ETH_HEADER_SIZE (2 * MAC_SIZE + ETH_TYPE_LENGTH_SIZE) @@ -138,15 +139,13 @@ #define NAME_QUERY_TIMEO 2000 /* ms */ #define MGMT_TIMEO 100 /* ms */ -#define MGMT_FRAME_SIZE 2048 +#define MGMT_FRAME_SIZE IPCP_ETH_MGMT_FRAME_SIZE #define FLOW_REQ 0 #define FLOW_REPLY 1 #define NAME_QUERY_REQ 2 #define NAME_QUERY_REPLY 3 -struct ipcp ipcpi; - struct mgmt_msg { #if defined(BUILD_ETH_DIX) uint16_t seid; @@ -165,13 +164,12 @@ struct mgmt_msg { uint32_t max_gap; uint32_t delay; uint32_t timeout; - uint16_t cypher_s; + int32_t response; uint8_t in_order; #if defined (BUILD_ETH_DIX) uint8_t code; uint8_t availability; #endif - int8_t response; } __attribute__((packed)); struct eth_frame { @@ -209,8 +207,9 @@ struct mgmt_frame { struct { struct shim_data * shim_data; -#ifdef __linux__ + int mtu; +#ifdef __linux__ int if_idx; #endif #if defined(HAVE_NETMAP) @@ -476,6 +475,8 @@ static int eth_ipcp_alloc(const uint8_t * dst_addr, if (buf == NULL) return -1; + memset(buf, 0, len + ETH_HEADER_TOT_SIZE + data->len); + msg = (struct mgmt_msg *) (buf + ETH_HEADER_TOT_SIZE); msg->code = FLOW_REQ; #if defined(BUILD_ETH_DIX) @@ -491,7 +492,6 @@ static int eth_ipcp_alloc(const uint8_t * dst_addr, msg->ber = hton32(qs.ber); msg->in_order = qs.in_order; msg->max_gap = hton32(qs.max_gap); - msg->cypher_s = hton16(qs.cypher_s); msg->timeout = hton32(qs.timeout); memcpy(msg + 1, hash, ipcp_dir_hash_len()); @@ -529,6 +529,8 @@ static int eth_ipcp_alloc_resp(uint8_t * dst_addr, if (buf == NULL) return -1; + memset(buf, 0, sizeof(*msg) + ETH_HEADER_TOT_SIZE + data->len); + msg = (struct mgmt_msg *) (buf + ETH_HEADER_TOT_SIZE); msg->code = FLOW_REPLY; @@ -539,7 +541,7 @@ static int eth_ipcp_alloc_resp(uint8_t * dst_addr, msg->ssap = ssap; msg->dsap = dsap; #endif - msg->response = response; + msg->response = hton32(response); if (data->len > 0) memcpy(msg + 1, data->data, data->len); @@ -667,6 +669,8 @@ static int eth_ipcp_name_query_req(const uint8_t * hash, if (buf == NULL) return -1; + memset(buf, 0, len + ETH_HEADER_TOT_SIZE); + msg = (struct mgmt_msg *) (buf + ETH_HEADER_TOT_SIZE); msg->code = NAME_QUERY_REPLY; @@ -694,11 +698,11 @@ static int eth_ipcp_name_query_req(const uint8_t * hash, static int eth_ipcp_name_query_reply(const uint8_t * hash, uint8_t * r_addr) { - uint64_t address = 0; + struct addr addr; - memcpy(&address, r_addr, MAC_SIZE); + memcpy(&addr.mac, r_addr, MAC_SIZE); - shim_data_dir_add_entry(eth_data.shim_data, hash, address); + shim_data_dir_add_entry(eth_data.shim_data, hash, addr); shim_data_dir_query_respond(eth_data.shim_data, hash); @@ -729,7 +733,6 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf, qs.ber = ntoh32(msg->ber); qs.in_order = msg->in_order; qs.max_gap = ntoh32(msg->max_gap); - qs.cypher_s = ntoh16(msg->cypher_s); qs.timeout = ntoh32(msg->timeout); data.data = (uint8_t *) buf + msg_len; @@ -762,7 +765,7 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf, msg->ssap, msg->dsap, #endif - msg->response, + ntoh32(msg->response), &data); break; case NAME_QUERY_REQ: @@ -837,7 +840,7 @@ static void * eth_ipcp_packet_reader(void * o) #if defined(HAVE_NETMAP) struct nm_pkthdr hdr; #else - struct shm_du_buff * sdb; + struct ssm_pk_buff * spb; fd_set fds; int frame_len; #endif @@ -869,21 +872,21 @@ static void * eth_ipcp_packet_reader(void * o) if (select(eth_data.bpf + 1, &fds, NULL, NULL, NULL)) continue; assert(FD_ISSET(eth_data.bpf, &fds)); - if (ipcp_sdb_reserve(&sdb, BPF_LEN)) + if (ipcp_spb_reserve(&spb, BPF_LEN)) continue; - buf = shm_du_buff_head(sdb); + buf = ssm_pk_buff_head(spb); frame_len = read(eth_data.bpf, buf, BPF_BLEN); #elif defined(HAVE_RAW_SOCKETS) FD_SET(eth_data.s_fd, &fds); if (select(eth_data.s_fd + 1, &fds, NULL, NULL, NULL) < 0) continue; assert(FD_ISSET(eth_data.s_fd, &fds)); - if (ipcp_sdb_reserve(&sdb, ETH_MTU)) + if (ipcp_spb_reserve(&spb, ETH_MTU)) continue; - buf = shm_du_buff_head_alloc(sdb, ETH_HEADER_TOT_SIZE); + buf = ssm_pk_buff_head_alloc(spb, ETH_HEADER_TOT_SIZE); if (buf == NULL) { log_dbg("Failed to allocate header."); - ipcp_sdb_release(sdb); + ipcp_spb_release(spb); continue; } frame_len = recv(eth_data.s_fd, buf, @@ -891,7 +894,7 @@ static void * eth_ipcp_packet_reader(void * o) #endif if (frame_len <= 0) { log_dbg("Failed to receive frame."); - ipcp_sdb_release(sdb); + ipcp_spb_release(spb); continue; } #endif @@ -933,7 +936,13 @@ static void * eth_ipcp_packet_reader(void * o) if (ssap == MGMT_SAP && dsap == MGMT_SAP) { #endif - ipcp_sdb_release(sdb); /* No need for the N+1 buffer. */ + ipcp_spb_release(spb); /* No need for the N+1 buffer. */ + + if (length > MGMT_FRAME_SIZE) { + log_warn("Management frame size %u exceeds %u.", + length, MGMT_FRAME_SIZE); + goto fail_frame; + } frame = malloc(sizeof(*frame)); if (frame == NULL) { @@ -973,22 +982,22 @@ static void * eth_ipcp_packet_reader(void * o) pthread_rwlock_unlock(ð_data.flows_lock); #ifndef HAVE_NETMAP - shm_du_buff_head_release(sdb, ETH_HEADER_TOT_SIZE); - shm_du_buff_truncate(sdb, length); + ssm_pk_buff_head_release(spb, ETH_HEADER_TOT_SIZE); + ssm_pk_buff_truncate(spb, length); #else - if (ipcp_sdb_reserve(&sdb, length)) + if (ipcp_spb_reserve(&spb, length)) continue; - buf = shm_du_buff_head(sdb); + buf = ssm_pk_buff_head(spb); memcpy(buf, &e_frame->payload, length); #endif - if (np1_flow_write(fd, sdb) < 0) - ipcp_sdb_release(sdb); + if (np1_flow_write(fd, spb, NP1_GET_POOL(fd)) < 0) + ipcp_spb_release(spb); continue; fail_frame: #ifndef HAVE_NETMAP - ipcp_sdb_release(sdb); + ipcp_spb_release(spb); #endif } } @@ -1004,7 +1013,7 @@ static void cleanup_writer(void * o) static void * eth_ipcp_packet_writer(void * o) { int fd; - struct shm_du_buff * sdb; + struct ssm_pk_buff * spb; size_t len; #if defined(BUILD_ETH_DIX) uint16_t deid; @@ -1032,17 +1041,17 @@ static void * eth_ipcp_packet_writer(void * o) if (fqueue_type(fq) != FLOW_PKT) continue; - if (np1_flow_read(fd, &sdb)) { + if (np1_flow_read(fd, &spb, NP1_GET_POOL(fd))) { log_dbg("Bad read from fd %d.", fd); continue; } - len = shm_du_buff_len(sdb); + len = ssm_pk_buff_len(spb); - if (shm_du_buff_head_alloc(sdb, ETH_HEADER_TOT_SIZE) + if (ssm_pk_buff_head_alloc(spb, ETH_HEADER_TOT_SIZE) == NULL) { log_dbg("Failed to allocate header."); - ipcp_sdb_release(sdb); + ipcp_spb_release(spb); continue; } @@ -1065,10 +1074,10 @@ static void * eth_ipcp_packet_writer(void * o) #elif defined(BUILD_ETH_LLC) dsap, ssap, #endif - shm_du_buff_head(sdb), + ssm_pk_buff_head(spb), len)) log_dbg("Failed to send frame."); - ipcp_sdb_release(sdb); + ipcp_spb_release(spb); } } @@ -1217,140 +1226,138 @@ static int open_bpf_device(void) } #endif -static int eth_ipcp_bootstrap(const struct ipcp_config * conf) -{ - int idx; - struct ifreq ifr; -#if defined(HAVE_NETMAP) - char ifn[IFNAMSIZ]; -#elif defined(HAVE_BPF) - int enable = 1; - int disable = 0; - int blen; -#endif /* HAVE_NETMAP */ - #if defined(__FreeBSD__) || defined(__APPLE__) +static int ifr_hwaddr_from_ifaddrs(struct ifreq * ifr) +{ struct ifaddrs * ifaddr; struct ifaddrs * ifa; -#elif defined(__linux__) - int skfd; -#endif -#ifndef SHM_RDRB_MULTI_BLOCK - size_t maxsz; -#endif -#if defined(HAVE_RAW_SOCKETS) - #if defined(IPCP_ETH_QDISC_BYPASS) - int qdisc_bypass = 1; - #endif /* ENABLE_QDISC_BYPASS */ - int flags; -#endif - assert(conf); - assert(conf->type == THIS_TYPE); - - ipcpi.dir_hash_algo = (enum hash_algo) conf->layer_info.dir_hash_algo; - strcpy(ipcpi.layer_name, conf->layer_info.name); - - if (strlen(conf->eth.dev) >= IFNAMSIZ) { - log_err("Invalid device name: %s.", conf->eth.dev); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, conf->eth.dev); - -#ifdef BUILD_ETH_DIX - if (conf->eth.ethertype < 0x0600 || conf->eth.ethertype == 0xFFFF) { - log_err("Invalid Ethertype: %d.", conf->eth.ethertype); - return -1; - } - eth_data.ethertype = htons(conf->eth.ethertype); -#endif + int idx; -#if defined(__FreeBSD__) || defined(__APPLE__) if (getifaddrs(&ifaddr) < 0) { log_err("Could not get interfaces."); - return -1; + goto fail_ifaddrs; } for (ifa = ifaddr, idx = 0; ifa != NULL; ifa = ifa->ifa_next, ++idx) { - if (strcmp(ifa->ifa_name, conf->eth.dev)) - continue; - log_dbg("Interface %s found.", conf->eth.dev); - - #if defined(HAVE_NETMAP) || defined(HAVE_BPF) - memcpy(eth_data.hw_addr, - LLADDR((struct sockaddr_dl *) (ifa)->ifa_addr), - MAC_SIZE); - #elif defined (HAVE_RAW_SOCKETS) - memcpy(&ifr.ifr_addr, ifa->ifa_addr, sizeof(*ifa->ifa_addr)); - #endif - break; + if (strcmp(ifa->ifa_name, ifr->ifr_name) == 0) + break; } - freeifaddrs(ifaddr); - if (ifa == NULL) { log_err("Interface not found."); - return -1; + goto fail_ifa; } + memcpy(&ifr->ifr_addr, ifa->ifa_addr, sizeof(*ifa->ifa_addr)); + + log_dbg("Interface %s hwaddr " MAC_FMT ".", ifr->ifr_name, + MAC_VAL(ifr->ifr_addr.sa_data)); + + freeifaddrs(ifaddr); + + return 0; + fail_ifa: + freeifaddrs(ifaddr); + fail_ifaddrs: + return -1; + +} #elif defined(__linux__) +static int ifr_hwaddr_from_socket(struct ifreq * ifr) +{ + int skfd; + skfd = socket(AF_UNIX, SOCK_STREAM, 0); if (skfd < 0) { log_err("Failed to open socket."); - return -1; + goto fail_socket; } - if (ioctl(skfd, SIOCGIFMTU, &ifr)) { - log_err("Failed to get MTU."); - close(skfd); - return -1; + if (ioctl(skfd, SIOCGIFHWADDR, ifr)) { + log_err("Failed to get hwaddr."); + goto fail_ifr; } - log_dbg("Device MTU is %d.", ifr.ifr_mtu); + log_dbg("Interface %s hwaddr " MAC_FMT ".", ifr->ifr_name, + MAC_VAL(ifr->ifr_hwaddr.sa_data)); - eth_data.mtu = MIN((int) ETH_MTU_MAX, ifr.ifr_mtu); - if (memcmp(conf->eth.dev, "lo", 2) == 0 && - eth_data.mtu > IPCP_ETH_LO_MTU) { - log_dbg("Using loopback interface. MTU restricted to %d.", - IPCP_ETH_LO_MTU); - eth_data.mtu = IPCP_ETH_LO_MTU; - } + close(skfd); -#ifndef SHM_RDRB_MULTI_BLOCK - maxsz = SHM_RDRB_BLOCK_SIZE - 5 * sizeof(size_t) - - (DU_BUFF_HEADSPACE + DU_BUFF_TAILSPACE); - if ((size_t) eth_data.mtu > maxsz ) { - log_dbg("Layer MTU truncated to shm block size."); - eth_data.mtu = maxsz; - } + return 0; + + fail_ifr: + close(skfd); + fail_socket: + return -1; +} #endif - log_dbg("Layer MTU is %d.", eth_data.mtu); - if (ioctl(skfd, SIOCGIFHWADDR, &ifr)) { - log_err("Failed to get hwaddr."); - close(skfd); - return -1; +static int eth_ifr_hwaddr(struct ifreq * ifr) +{ +#if defined(__FreeBSD__) || defined(__APPLE__) + return ifr_hwaddr_from_ifaddrs(ifr); +#elif defined(__linux__) + return ifr_hwaddr_from_socket(ifr); +#else + return -1; +#endif +} + +static int eth_ifr_mtu(struct ifreq * ifr) +{ + int skfd; + + skfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (skfd < 0) { + log_err("Failed to open socket."); + goto fail_socket; } + if (ioctl(skfd, SIOCGIFMTU, ifr) < 0) { + log_err("Failed to get MTU."); + goto fail_mtu; + } close(skfd); - idx = if_nametoindex(conf->eth.dev); - if (idx == 0) { - log_err("Failed to retrieve interface index."); + return 0; + + fail_mtu: + close(skfd); + fail_socket: + return -1; +} + +static int eth_set_mtu(struct ifreq * ifr) +{ + if (eth_ifr_mtu(ifr) < 0) { + log_err("Failed to get interface MTU."); return -1; } - eth_data.if_idx = idx; -#endif /* __FreeBSD__ */ + log_dbg("Device MTU is %d.", ifr->ifr_mtu); + + eth_data.mtu = MIN((int) ETH_MTU_MAX, ifr->ifr_mtu); + if (memcmp(ifr->ifr_name, "lo", 2) == 0 && + eth_data.mtu > IPCP_ETH_LO_MTU) { + log_dbg("Using loopback interface. MTU restricted to %d.", + IPCP_ETH_LO_MTU); + eth_data.mtu = IPCP_ETH_LO_MTU; + } + + log_dbg("Layer MTU is %d.", eth_data.mtu); + + return 0; +} #if defined(HAVE_NETMAP) +static int eth_init_nmd(struct ifreq * ifr) +{ strcpy(ifn, "netmap:"); - strcat(ifn, conf->eth.dev); + strcat(ifn, ifr->ifr_name); eth_data.nmd = nm_open(ifn, NULL, 0, NULL); if (eth_data.nmd == NULL) { log_err("Failed to open netmap device."); - return -1; + goto fail_nmd; } memset(ð_data.poll_in, 0, sizeof(eth_data.poll_in)); @@ -1362,11 +1369,22 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) eth_data.poll_out.events = POLLOUT; log_info("Using netmap device."); -#elif defined(HAVE_BPF) /* !HAVE_NETMAP */ + + return 0; + fail_nmd: + return -1; +} +#elif defined (HAVE_BPF) +static int eth_init_bpf(struct ifreq * ifr) +{ + int enable = 1; + int disable = 0; + int blen; + eth_data.bpf = open_bpf_device(); if (eth_data.bpf < 0) { log_err("Failed to open bpf device."); - return -1; + goto fail_bpf; } ioctl(eth_data.bpf, BIOCGBLEN, &blen); @@ -1376,7 +1394,7 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) goto fail_device; } - if (ioctl(eth_data.bpf, BIOCSETIF, &ifr) < 0) { + if (ioctl(eth_data.bpf, BIOCSETIF, ifr) < 0) { log_err("Failed to set interface."); goto fail_device; } @@ -1397,22 +1415,39 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) } log_info("Using Berkeley Packet Filter."); + + return 0; + + fail_device: + close(eth_data.bpf); + fail_bpf: + return -1; +} #elif defined(HAVE_RAW_SOCKETS) +static int eth_init_raw_socket(struct ifreq * ifr) +{ + int idx; + int flags; +#if defined(IPCP_ETH_QDISC_BYPASS) + int qdisc_bypass = 1; +#endif /* ENABLE_QDISC_BYPASS */ + + idx = if_nametoindex(ifr->ifr_name); + if (idx == 0) { + log_err("Failed to retrieve interface index."); + return -1; + } memset(&(eth_data.device), 0, sizeof(eth_data.device)); eth_data.device.sll_ifindex = idx; eth_data.device.sll_family = AF_PACKET; - memcpy(eth_data.device.sll_addr, ifr.ifr_hwaddr.sa_data, MAC_SIZE); + memcpy(eth_data.device.sll_addr, ifr->ifr_hwaddr.sa_data, MAC_SIZE); eth_data.device.sll_halen = MAC_SIZE; eth_data.device.sll_protocol = htons(ETH_P_ALL); - - #if defined (BUILD_ETH_DIX) +#if defined (BUILD_ETH_DIX) eth_data.s_fd = socket(AF_PACKET, SOCK_RAW, eth_data.ethertype); - #elif defined (BUILD_ETH_LLC) +#elif defined (BUILD_ETH_LLC) eth_data.s_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_802_2)); - #endif - - log_info("Using raw socket device."); - +#endif if (eth_data.s_fd < 0) { log_err("Failed to create socket."); goto fail_socket; @@ -1429,28 +1464,93 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) goto fail_device; } - #if defined(IPCP_ETH_QDISC_BYPASS) +#if defined(IPCP_ETH_QDISC_BYPASS) if (setsockopt(eth_data.s_fd, SOL_PACKET, PACKET_QDISC_BYPASS, &qdisc_bypass, sizeof(qdisc_bypass))) { log_info("Qdisc bypass not supported."); } - #endif +#endif if (bind(eth_data.s_fd, (struct sockaddr *) ð_data.device, sizeof(eth_data.device)) < 0) { log_err("Failed to bind socket to interface."); goto fail_device; } +#ifdef __linux__ + eth_data.if_idx = idx; +#endif + log_info("Using raw socket device."); + + return 0; + fail_device: + close(eth_data.s_fd); + fail_socket: + return -1; +} +#endif + +static int eth_ipcp_bootstrap(struct ipcp_config * conf) +{ + struct ifreq ifr; + int i; +#if defined(HAVE_NETMAP) + char ifn[IFNAMSIZ]; +#endif /* HAVE_NETMAP */ + + assert(conf); + assert(conf->type == THIS_TYPE); + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, conf->eth.dev); + + if (strlen(conf->eth.dev) >= IFNAMSIZ) { + log_err("Invalid device name: %s.", conf->eth.dev); + return -1; + } +#ifdef BUILD_ETH_DIX + if (conf->eth.ethertype < 0x0600 || conf->eth.ethertype == 0xFFFF) { + log_err("Invalid Ethertype: %d.", conf->eth.ethertype); + return -1; + } + eth_data.ethertype = htons(conf->eth.ethertype); +#endif + if (eth_set_mtu(&ifr) < 0) { + log_err("Failed to set MTU."); + return -1; + } + + if (eth_ifr_hwaddr(&ifr) < 0) { + log_err("Failed to get hardware addr."); + return -1; + } +#if defined(HAVE_NETMAP) || defined(HAVE_BPF) + memcpy(eth_data.hw_addr, LLADDR((struct sockaddr_dl *) &ifr.ifr_addr), + MAC_SIZE); +#endif +#if defined(HAVE_NETMAP) + if (eth_init_nmd(&ifr) < 0) { + log_err("Failed to initialize netmap device."); + return -1; + } +#elif defined(HAVE_BPF) /* !HAVE_NETMAP */ + if (eth_init_bpf(&ifr) < 0) { + log_err("Failed to initialize BPF device."); + return -1; + } +#elif defined(HAVE_RAW_SOCKETS) + if (eth_init_raw_socket(&ifr) < 0) { + log_err("Failed to initialize raw socket device."); + return -1; + } #endif /* HAVE_NETMAP */ #if defined(__linux__) if (pthread_create(ð_data.if_monitor, NULL, eth_ipcp_if_monitor, NULL)) { log_err("Failed to create monitor thread: %s.", strerror(errno)); - goto fail_device; + goto fail_monitor; } #endif - if (pthread_create(ð_data.mgmt_handler, NULL, eth_ipcp_mgmt_handler, NULL)) { log_err("Failed to create mgmt handler thread: %s.", @@ -1458,8 +1558,8 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) goto fail_mgmt_handler; } - for (idx = 0; idx < IPCP_ETH_RD_THR; ++idx) { - if (pthread_create(ð_data.packet_reader[idx], NULL, + for (i = 0; i < IPCP_ETH_RD_THR; i++) { + if (pthread_create(ð_data.packet_reader[i], NULL, eth_ipcp_packet_reader, NULL)) { log_err("Failed to create packet reader thread: %s", strerror(errno)); @@ -1467,8 +1567,8 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) } } - for (idx = 0; idx < IPCP_ETH_WR_THR; ++idx) { - if (pthread_create(ð_data.packet_writer[idx], NULL, + for (i = 0; i < IPCP_ETH_WR_THR; i++) { + if (pthread_create(ð_data.packet_writer[i], NULL, eth_ipcp_packet_writer, NULL)) { log_err("Failed to create packet writer thread: %s", strerror(errno)); @@ -1486,15 +1586,15 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) return 0; fail_packet_writer: - while (idx > 0) { - pthread_cancel(eth_data.packet_writer[--idx]); - pthread_join(eth_data.packet_writer[idx], NULL); + while (i-- > 0) { + pthread_cancel(eth_data.packet_writer[i]); + pthread_join(eth_data.packet_writer[i], NULL); } - idx = IPCP_ETH_RD_THR; + i = IPCP_ETH_RD_THR; fail_packet_reader: - while (idx > 0) { - pthread_cancel(eth_data.packet_reader[--idx]); - pthread_join(eth_data.packet_reader[idx], NULL); + while (i-- > 0) { + pthread_cancel(eth_data.packet_reader[i]); + pthread_join(eth_data.packet_reader[i], NULL); } pthread_cancel(eth_data.mgmt_handler); pthread_join(eth_data.mgmt_handler, NULL); @@ -1503,8 +1603,8 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) pthread_cancel(eth_data.if_monitor); pthread_join(eth_data.if_monitor, NULL); #endif -#if defined(__linux__) || !defined(HAVE_NETMAP) - fail_device: +#if defined(__linux__) + fail_monitor: #endif #if defined(HAVE_NETMAP) nm_close(eth_data.nmd); @@ -1512,7 +1612,6 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) close(eth_data.bpf); #elif defined(HAVE_RAW_SOCKETS) close(eth_data.s_fd); - fail_socket: #endif return -1; } @@ -1554,6 +1653,8 @@ static int eth_ipcp_query(const uint8_t * hash) if (buf == NULL) return -1; + memset(buf, 0, len + ETH_HEADER_TOT_SIZE); + msg = (struct mgmt_msg *) (buf + ETH_HEADER_TOT_SIZE); msg->code = NAME_QUERY_REQ; @@ -1599,7 +1700,7 @@ static int eth_ipcp_flow_alloc(int fd, uint8_t ssap = 0; #endif uint8_t r_addr[MAC_SIZE]; - uint64_t addr = 0; + struct addr addr; assert(hash); @@ -1608,10 +1709,12 @@ static int eth_ipcp_flow_alloc(int fd, HASH_VAL32(hash)); return -1; } + addr = shim_data_dir_get_addr(eth_data.shim_data, hash); + memcpy(r_addr, &addr.mac, MAC_SIZE); - pthread_rwlock_wrlock(ð_data.flows_lock); #ifdef BUILD_ETH_LLC + pthread_rwlock_wrlock(ð_data.flows_lock); ssap = bmp_allocate(eth_data.saps); if (!bmp_is_id_valid(eth_data.saps, ssap)) { pthread_rwlock_unlock(ð_data.flows_lock); @@ -1621,10 +1724,8 @@ static int eth_ipcp_flow_alloc(int fd, eth_data.fd_to_ef[fd].sap = ssap; eth_data.ef_to_fd[ssap] = fd; -#endif pthread_rwlock_unlock(ð_data.flows_lock); - - memcpy(r_addr, &addr, MAC_SIZE); +#endif if (eth_ipcp_alloc(r_addr, #if defined(BUILD_ETH_DIX) diff --git a/src/ipcpd/eth/llc.c b/src/ipcpd/eth/llc.c index c900dcab..a772e86e 100644 --- a/src/ipcpd/eth/llc.c +++ b/src/ipcpd/eth/llc.c @@ -1,5 +1,5 @@ /* - * Ouroboros - Copyright (C) 2016 - 2024 + * Ouroboros - Copyright (C) 2016 - 2026 * * IPC processes over Ethernet - LLC * |
