summaryrefslogtreecommitdiff
path: root/src/ipcpd/eth/eth.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipcpd/eth/eth.c')
-rw-r--r--src/ipcpd/eth/eth.c394
1 files changed, 245 insertions, 149 deletions
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(&eth_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 *) &eth_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(&eth_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(&eth_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(&eth_data.packet_reader[idx], NULL,
+ for (i = 0; i < IPCP_ETH_RD_THR; i++) {
+ if (pthread_create(&eth_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(&eth_data.packet_writer[idx], NULL,
+ for (i = 0; i < IPCP_ETH_WR_THR; i++) {
+ if (pthread_create(&eth_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(&eth_data.flows_lock);
#ifdef BUILD_ETH_LLC
+ pthread_rwlock_wrlock(&eth_data.flows_lock);
ssap = bmp_allocate(eth_data.saps);
if (!bmp_is_id_valid(eth_data.saps, ssap)) {
pthread_rwlock_unlock(&eth_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(&eth_data.flows_lock);
-
- memcpy(r_addr, &addr, MAC_SIZE);
+#endif
if (eth_ipcp_alloc(r_addr,
#if defined(BUILD_ETH_DIX)