diff options
Diffstat (limited to 'src/ipcpd/eth')
-rw-r--r-- | src/ipcpd/eth/CMakeLists.txt | 12 | ||||
-rw-r--r-- | src/ipcpd/eth/eth.c | 394 |
2 files changed, 251 insertions, 155 deletions
diff --git a/src/ipcpd/eth/CMakeLists.txt b/src/ipcpd/eth/CMakeLists.txt index d57e1848..44299a59 100644 --- a/src/ipcpd/eth/CMakeLists.txt +++ b/src/ipcpd/eth/CMakeLists.txt @@ -85,18 +85,18 @@ if (HAVE_ETH) "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(IPCP_ETH_MPL 100 CACHE STRING + "Default maximum packet lifetime for the Ethernet IPCPs, in ms") set(ETH_LLC_SOURCES # Add source files here - ${CMAKE_CURRENT_SOURCE_DIR}/llc.c - ) + llc.c + ) set(ETH_DIX_SOURCES # Add source files here - ${CMAKE_CURRENT_SOURCE_DIR}/dix.c - ) + dix.c + ) set(IPCP_ETH_LLC_TARGET ipcpd-eth-llc CACHE INTERNAL "") set(IPCP_ETH_DIX_TARGET ipcpd-eth-dix CACHE INTERNAL "") diff --git a/src/ipcpd/eth/eth.c b/src/ipcpd/eth/eth.c index c0e6d0ce..0b6a91fb 100644 --- a/src/ipcpd/eth/eth.c +++ b/src/ipcpd/eth/eth.c @@ -88,31 +88,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) @@ -145,8 +145,6 @@ #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 +163,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 +206,9 @@ struct mgmt_frame { struct { struct shim_data * shim_data; -#ifdef __linux__ + int mtu; +#ifdef __linux__ int if_idx; #endif #if defined(HAVE_NETMAP) @@ -491,7 +489,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()); @@ -539,7 +536,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); @@ -694,11 +691,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 +726,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 +758,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: @@ -1217,106 +1213,123 @@ 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."); + goto fail_socket; + } + + if (ioctl(skfd, SIOCGIFHWADDR, ifr)) { + log_err("Failed to get hwaddr."); + goto fail_ifr; } + log_dbg("Interface %s hwaddr " MAC_FMT ".", ifr->ifr_name, + MAC_VAL(ifr->ifr_hwaddr.sa_data)); + + close(skfd); + + return 0; + + fail_ifr: + close(skfd); + fail_socket: + return -1; +} +#endif + +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."); - return -1; + goto fail_socket; } - if (ioctl(skfd, SIOCGIFMTU, &ifr)) { + if (ioctl(skfd, SIOCGIFMTU, ifr) < 0) { log_err("Failed to get MTU."); - close(skfd); + goto fail_mtu; + } + close(skfd); + + 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; } - log_dbg("Device MTU is %d.", ifr.ifr_mtu); + log_dbg("Device MTU is %d.", ifr->ifr_mtu); - eth_data.mtu = MIN((int) ETH_MTU_MAX, ifr.ifr_mtu); - if (memcmp(conf->eth.dev, "lo", 2) == 0 && + 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; } - #ifndef SHM_RDRB_MULTI_BLOCK maxsz = SHM_RDRB_BLOCK_SIZE - 5 * sizeof(size_t) - (DU_BUFF_HEADSPACE + DU_BUFF_TAILSPACE); @@ -1327,30 +1340,18 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) #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; - } - - close(skfd); - - idx = if_nametoindex(conf->eth.dev); - if (idx == 0) { - log_err("Failed to retrieve interface index."); - return -1; - } - eth_data.if_idx = idx; -#endif /* __FreeBSD__ */ - + 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 +1363,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 +1388,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 +1409,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 +1458,96 @@ 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 */ + +#ifndef SHM_RDRB_MULTI_BLOCK + size_t maxsz; +#endif + 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 +1555,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 +1564,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 +1583,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 +1600,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 +1609,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; } @@ -1599,7 +1695,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 +1704,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 +1719,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) |