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.c1457
1 files changed, 1014 insertions, 443 deletions
diff --git a/src/ipcpd/eth/eth.c b/src/ipcpd/eth/eth.c
index 932034d5..2d3bd249 100644
--- a/src/ipcpd/eth/eth.c
+++ b/src/ipcpd/eth/eth.c
@@ -1,5 +1,5 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2021
+ * Ouroboros - Copyright (C) 2016 - 2026
*
* IPC processes over Ethernet
*
@@ -37,20 +37,33 @@
#include "config.h"
+#include <ouroboros/atomics.h>
+#include <ouroboros/endian.h>
#include <ouroboros/hash.h>
#include <ouroboros/errno.h>
#include <ouroboros/list.h>
#include <ouroboros/utils.h>
#include <ouroboros/bitmap.h>
+#include <ouroboros/crc8.h>
#include <ouroboros/dev.h>
#include <ouroboros/ipcp-dev.h>
#include <ouroboros/fqueue.h>
#include <ouroboros/logs.h>
-#include <ouroboros/time_utils.h>
+#include <ouroboros/np1_flow.h>
+#include <ouroboros/time.h>
#include <ouroboros/fccntl.h>
#include <ouroboros/pthread.h>
+#include <ouroboros/rib.h>
+
+#ifndef IPCP_ETH_FLOW_STATS
+#undef FETCH_ADD_RELAXED
+#define FETCH_ADD_RELAXED(p, v) ((void) 0)
+#undef FETCH_SUB_RELAXED
+#define FETCH_SUB_RELAXED(p, v) ((void) 0)
+#endif
#include "ipcp.h"
+#include "np1.h"
#include "shim-data.h"
#include <signal.h>
@@ -70,6 +83,7 @@
#include <linux/if_ether.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
+#include <linux/sockios.h>
#endif
#ifdef __FreeBSD__
@@ -87,31 +101,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)
@@ -120,7 +134,8 @@
#define MGMT_EID 0
#define DIX_EID_SIZE sizeof(uint16_t)
#define DIX_LENGTH_SIZE sizeof(uint16_t)
-#define DIX_HEADER_SIZE (DIX_EID_SIZE + DIX_LENGTH_SIZE)
+#define DIX_HCS_SIZE CRC8_HASH_LEN
+#define DIX_HEADER_SIZE (DIX_EID_SIZE + DIX_LENGTH_SIZE + DIX_HCS_SIZE)
#define ETH_HEADER_TOT_SIZE (ETH_HEADER_SIZE + DIX_HEADER_SIZE)
#define MAX_EIDS (1 << (8 * DIX_EID_SIZE))
#define ETH_MAX_PACKET_SIZE (ETH_MTU - DIX_HEADER_SIZE)
@@ -128,24 +143,26 @@
#elif defined(BUILD_ETH_LLC)
#define THIS_TYPE IPCP_ETH_LLC
#define MGMT_SAP 0x01
-#define LLC_HEADER_SIZE 3
+#define LLC_FIELDS_SIZE 3
+#define LLC_HCS_SIZE CRC8_HASH_LEN
+#define LLC_HEADER_SIZE (LLC_FIELDS_SIZE + LLC_HCS_SIZE)
#define ETH_HEADER_TOT_SIZE (ETH_HEADER_SIZE + LLC_HEADER_SIZE)
#define MAX_SAPS 64
#define ETH_MAX_PACKET_SIZE (ETH_MTU - LLC_HEADER_SIZE)
#define ETH_FRAME_SIZE (ETH_HEADER_SIZE + ETH_MTU_MAX)
#endif
-#define ALLOC_TIMEO 10 /* ms */
-#define NAME_QUERY_TIMEO 2000 /* ms */
-#define MGMT_TIMEO 100 /* ms */
-#define MGMT_FRAME_SIZE 2048
+#define NAME_QUERY_TIMEO 1900 /* ms total budget */
+#define NAME_QUERY_RETRIES 3 /* retransmits, 4 attempts total */
+#define MGMT_TIMEO 100 /* ms */
+#define MGMT_FRAME_SIZE IPCP_ETH_MGMT_FRAME_SIZE
+#define ETH_RIB_PATH "eth"
#define FLOW_REQ 0
#define FLOW_REPLY 1
#define NAME_QUERY_REQ 2
#define NAME_QUERY_REPLY 3
-
-struct ipcp ipcpi;
+#define FLOW_IRM_UPDATE 4
struct mgmt_msg {
#if defined(BUILD_ETH_DIX)
@@ -164,13 +181,13 @@ struct mgmt_msg {
uint32_t ber;
uint32_t max_gap;
uint32_t delay;
- uint16_t cypher_s;
- uint8_t in_order;
+ uint32_t timeout;
+ int32_t response;
+ uint8_t service;
#if defined (BUILD_ETH_DIX)
uint8_t code;
uint8_t availability;
#endif
- int8_t response;
} __attribute__((packed));
struct eth_frame {
@@ -186,6 +203,7 @@ struct eth_frame {
uint8_t ssap;
uint8_t cf;
#endif
+ uint8_t hcs;
uint8_t payload;
} __attribute__((packed));
@@ -197,6 +215,17 @@ struct ef {
int8_t r_sap;
#endif
uint8_t r_addr[MAC_SIZE];
+#ifdef IPCP_ETH_FLOW_STATS
+ struct {
+ time_t stamp;
+ size_t p_rcv;
+ size_t b_rcv;
+ size_t p_dlv_f;
+ size_t p_snd;
+ size_t b_snd;
+ size_t p_snd_f;
+ } stat;
+#endif
};
struct mgmt_frame {
@@ -208,8 +237,9 @@ struct mgmt_frame {
struct {
struct shim_data * shim_data;
-#ifdef __linux__
+
int mtu;
+#ifdef __linux__
int if_idx;
#endif
#if defined(HAVE_NETMAP)
@@ -233,6 +263,22 @@ struct {
struct ef * fd_to_ef;
fset_t * np1_flows;
pthread_rwlock_t flows_lock;
+#ifdef IPCP_ETH_FLOW_STATS
+ struct {
+ size_t n_flows;
+ size_t n_rcv;
+ size_t n_snd;
+ size_t n_mgmt_rcv;
+ size_t n_mgmt_snd;
+ size_t n_bad_id;
+ size_t n_dlv_f;
+ size_t n_buf_f;
+ size_t n_rcv_f;
+ size_t n_snd_f;
+ size_t kern_rcv;
+ size_t kern_drp;
+ } stat;
+#endif
pthread_t packet_writer[IPCP_ETH_WR_THR];
pthread_t packet_reader[IPCP_ETH_RD_THR];
@@ -284,7 +330,14 @@ static int eth_data_init(void)
eth_data.fd_to_ef[i].r_sap = -1;
#endif
memset(&eth_data.fd_to_ef[i].r_addr, 0, MAC_SIZE);
+#ifdef IPCP_ETH_FLOW_STATS
+ memset(&eth_data.fd_to_ef[i].stat, 0,
+ sizeof(eth_data.fd_to_ef[i].stat));
+#endif
}
+#ifdef IPCP_ETH_FLOW_STATS
+ memset(&eth_data.stat, 0, sizeof(eth_data.stat));
+#endif
eth_data.shim_data = shim_data_create();
if (eth_data.shim_data == NULL)
@@ -357,6 +410,232 @@ static void eth_data_fini(void)
free(eth_data.fd_to_ef);
}
+#ifdef IPCP_ETH_FLOW_STATS
+static int eth_rib_read(const char * path,
+ char * buf,
+ size_t len)
+{
+ struct ef * flow;
+ int fd;
+ char tmstr[RIB_TM_STRLEN];
+ struct tm * tm;
+ time_t stamp;
+ char * entry;
+
+ entry = strstr(path, RIB_SEPARATOR) + 1;
+ assert(entry);
+
+ if (len < 2048)
+ return 0;
+
+ buf[0] = '\0';
+
+ if (strcmp(entry, "summary") == 0) {
+ int n;
+#if defined(HAVE_RAW_SOCKETS)
+ int rcvbuf = 0;
+ int sndbuf = 0;
+ int queued = 0;
+ socklen_t optlen = sizeof(rcvbuf);
+# if defined(__linux__)
+ int outq = 0;
+ struct tpacket_stats tp_stats;
+ socklen_t tp_len = sizeof(tp_stats);
+# endif
+
+ getsockopt(eth_data.s_fd, SOL_SOCKET,
+ SO_RCVBUF, &rcvbuf, &optlen);
+ optlen = sizeof(sndbuf);
+ getsockopt(eth_data.s_fd, SOL_SOCKET,
+ SO_SNDBUF, &sndbuf, &optlen);
+ ioctl(eth_data.s_fd, FIONREAD, &queued);
+# if defined(__linux__)
+ ioctl(eth_data.s_fd, SIOCOUTQ, &outq);
+ if (getsockopt(eth_data.s_fd, SOL_PACKET,
+ PACKET_STATISTICS,
+ &tp_stats, &tp_len) == 0) {
+ FETCH_ADD_RELAXED(&eth_data.stat.kern_rcv,
+ tp_stats.tp_packets);
+ FETCH_ADD_RELAXED(&eth_data.stat.kern_drp,
+ tp_stats.tp_drops);
+ }
+# endif
+#endif
+ n = sprintf(buf,
+ "Active flows: %20zu\n"
+ "Total frames received: %20zu\n"
+ "Total frames sent: %20zu\n"
+ "Management frames received: %20zu\n"
+ "Management frames sent: %20zu\n"
+ "Bad EID/SAP frames: %20zu\n"
+ "Delivery (N+1) failures: %20zu\n"
+ "Buffer alloc failures: %20zu\n"
+ "Frame read failures: %20zu\n"
+ "Frame send failures: %20zu\n",
+ LOAD_RELAXED(&eth_data.stat.n_flows),
+ LOAD_RELAXED(&eth_data.stat.n_rcv),
+ LOAD_RELAXED(&eth_data.stat.n_snd),
+ LOAD_RELAXED(&eth_data.stat.n_mgmt_rcv),
+ LOAD_RELAXED(&eth_data.stat.n_mgmt_snd),
+ LOAD_RELAXED(&eth_data.stat.n_bad_id),
+ LOAD_RELAXED(&eth_data.stat.n_dlv_f),
+ LOAD_RELAXED(&eth_data.stat.n_buf_f),
+ LOAD_RELAXED(&eth_data.stat.n_rcv_f),
+ LOAD_RELAXED(&eth_data.stat.n_snd_f));
+#if defined(HAVE_RAW_SOCKETS)
+ n += sprintf(buf + n,
+ "Socket rcvbuf (bytes): %20d\n"
+ "Socket sndbuf (bytes): %20d\n"
+ "Socket ingress (bytes): %20d\n",
+ rcvbuf, sndbuf, queued);
+# if defined(__linux__)
+ n += sprintf(buf + n,
+ "Socket egress (bytes): %20d\n"
+ "Kernel frames received: %20zu\n"
+ "Kernel frames dropped: %20zu\n",
+ outq,
+ LOAD_RELAXED(&eth_data.stat.kern_rcv),
+ LOAD_RELAXED(&eth_data.stat.kern_drp));
+# endif
+#endif
+ return n;
+ }
+
+ fd = atoi(entry);
+
+ if (fd < 0 || fd >= SYS_MAX_FLOWS)
+ return -1;
+
+ flow = &eth_data.fd_to_ef[fd];
+
+ pthread_rwlock_rdlock(&eth_data.flows_lock);
+
+ stamp = flow->stat.stamp;
+ if (stamp == 0) {
+ pthread_rwlock_unlock(&eth_data.flows_lock);
+ return 0;
+ }
+
+ pthread_rwlock_unlock(&eth_data.flows_lock);
+
+ tm = gmtime(&stamp);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
+
+ sprintf(buf,
+ "Flow established at: %20s\n"
+ "Sent (packets): %20zu\n"
+ "Sent (bytes): %20zu\n"
+ "Send failed (packets): %20zu\n"
+ "Received (packets): %20zu\n"
+ "Received (bytes): %20zu\n"
+ "Delivery (N+1) failures: %20zu\n",
+ tmstr,
+ LOAD_RELAXED(&flow->stat.p_snd),
+ LOAD_RELAXED(&flow->stat.b_snd),
+ LOAD_RELAXED(&flow->stat.p_snd_f),
+ LOAD_RELAXED(&flow->stat.p_rcv),
+ LOAD_RELAXED(&flow->stat.b_rcv),
+ LOAD_RELAXED(&flow->stat.p_dlv_f));
+
+ return strlen(buf);
+}
+
+static int eth_rib_readdir(char *** buf)
+{
+ char entry[RIB_PATH_LEN + 1];
+ size_t i;
+ int idx = 0;
+ int n_entries;
+
+ pthread_rwlock_rdlock(&eth_data.flows_lock);
+
+ n_entries = (int) LOAD_RELAXED(&eth_data.stat.n_flows) + 1;
+
+ *buf = malloc(sizeof(**buf) * n_entries);
+ if (*buf == NULL)
+ goto fail_entries;
+
+ (*buf)[idx] = malloc(strlen("summary") + 1);
+ if ((*buf)[idx] == NULL)
+ goto fail_entry;
+
+ strcpy((*buf)[idx++], "summary");
+
+ for (i = 0; i < SYS_MAX_FLOWS && idx < n_entries; ++i) {
+ if (eth_data.fd_to_ef[i].stat.stamp == 0)
+ continue;
+
+ sprintf(entry, "%zu", i);
+
+ (*buf)[idx] = malloc(strlen(entry) + 1);
+ if ((*buf)[idx] == NULL)
+ goto fail_entry;
+
+ strcpy((*buf)[idx++], entry);
+ }
+
+ pthread_rwlock_unlock(&eth_data.flows_lock);
+
+ return idx;
+
+ fail_entry:
+ while (idx-- > 0)
+ free((*buf)[idx]);
+
+ free(*buf);
+ fail_entries:
+ pthread_rwlock_unlock(&eth_data.flows_lock);
+ return -ENOMEM;
+}
+
+static int eth_rib_getattr(const char * path,
+ struct rib_attr * attr)
+{
+ int fd;
+ char * entry;
+ struct ef * flow;
+
+ entry = strstr(path, RIB_SEPARATOR) + 1;
+ assert(entry);
+
+ if (strcmp(entry, "summary") == 0) {
+ attr->size = 2048;
+ attr->mtime = 0;
+ return 0;
+ }
+
+ fd = atoi(entry);
+
+ if (fd < 0 || fd >= SYS_MAX_FLOWS) {
+ attr->size = 0;
+ attr->mtime = 0;
+ return 0;
+ }
+
+ flow = &eth_data.fd_to_ef[fd];
+
+ pthread_rwlock_rdlock(&eth_data.flows_lock);
+
+ if (flow->stat.stamp != 0) {
+ attr->size = 2048;
+ attr->mtime = flow->stat.stamp;
+ } else {
+ attr->size = 0;
+ attr->mtime = 0;
+ }
+
+ pthread_rwlock_unlock(&eth_data.flows_lock);
+
+ return 0;
+}
+
+static struct rib_ops eth_r_ops = {
+ .read = eth_rib_read,
+ .readdir = eth_rib_readdir,
+ .getattr = eth_rib_getattr
+};
+#endif /* IPCP_ETH_FLOW_STATS */
+
#ifdef BUILD_ETH_LLC
static uint8_t reverse_bits(uint8_t b)
{
@@ -409,12 +688,18 @@ static int eth_ipcp_send_frame(const uint8_t * dst_addr,
e_frame->ethertype = eth_data.ethertype;
e_frame->eid = htons(deid);
e_frame->length = htons(len);
+ mem_hash(HASH_CRC8, &e_frame->hcs,
+ (uint8_t *) &e_frame->eid,
+ DIX_EID_SIZE + DIX_LENGTH_SIZE);
frame_len = ETH_HEADER_TOT_SIZE + len;
#elif defined(BUILD_ETH_LLC)
e_frame->length = htons(LLC_HEADER_SIZE + len);
e_frame->dsap = dsap;
e_frame->ssap = ssap;
e_frame->cf = cf;
+ mem_hash(HASH_CRC8, &e_frame->hcs,
+ (uint8_t *) &e_frame->dsap,
+ LLC_FIELDS_SIZE);
frame_len = ETH_HEADER_TOT_SIZE + len;
#endif
@@ -440,10 +725,7 @@ static int eth_ipcp_send_frame(const uint8_t * dst_addr,
}
assert(FD_ISSET(eth_data.s_fd, &fds));
- if (sendto(eth_data.s_fd,
- frame,
- frame_len,
- 0,
+ if (sendto(eth_data.s_fd, frame, frame_len, 0,
(struct sockaddr *) &eth_data.device,
sizeof(eth_data.device)) <= 0) {
log_dbg("Failed to send message: %s.", strerror(errno));
@@ -451,19 +733,20 @@ static int eth_ipcp_send_frame(const uint8_t * dst_addr,
}
#endif /* HAVE_NETMAP */
+ FETCH_ADD_RELAXED(&eth_data.stat.n_snd, 1);
+
return 0;
}
-static int eth_ipcp_alloc(const uint8_t * dst_addr,
+static int eth_ipcp_alloc(const uint8_t * dst_addr,
#if defined(BUILD_ETH_DIX)
- uint16_t eid,
+ uint16_t eid,
#elif defined(BUILD_ETH_LLC)
- uint8_t ssap,
+ uint8_t ssap,
#endif
- const uint8_t * hash,
- qosspec_t qs,
- const void * data,
- size_t dlen)
+ const uint8_t * hash,
+ qosspec_t qs,
+ const buffer_t * data)
{
uint8_t * buf;
struct mgmt_msg * msg;
@@ -472,10 +755,12 @@ static int eth_ipcp_alloc(const uint8_t * dst_addr,
len = sizeof(*msg) + ipcp_dir_hash_len();
- buf = malloc(len + ETH_HEADER_TOT_SIZE + dlen);
+ buf = malloc(len + ETH_HEADER_TOT_SIZE + data->len);
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)
@@ -489,12 +774,13 @@ static int eth_ipcp_alloc(const uint8_t * dst_addr,
msg->availability = qs.availability;
msg->loss = hton32(qs.loss);
msg->ber = hton32(qs.ber);
- msg->in_order = qs.in_order;
+ msg->service = qs.service;
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());
- memcpy(buf + len + ETH_HEADER_TOT_SIZE, data, dlen);
+ if (data->len > 0)
+ memcpy(buf + len + ETH_HEADER_TOT_SIZE, data->data, data->len);
ret = eth_ipcp_send_frame(dst_addr,
#if defined(BUILD_ETH_DIX)
@@ -503,31 +789,35 @@ static int eth_ipcp_alloc(const uint8_t * dst_addr,
reverse_bits(MGMT_SAP),
reverse_bits(MGMT_SAP),
#endif
- buf, len + dlen);
+ buf, len + data->len);
free(buf);
+ if (ret == 0)
+ FETCH_ADD_RELAXED(&eth_data.stat.n_mgmt_snd, 1);
+
return ret;
}
-static int eth_ipcp_alloc_resp(uint8_t * dst_addr,
+static int eth_ipcp_alloc_resp(uint8_t * dst_addr,
#if defined(BUILD_ETH_DIX)
- uint16_t seid,
- uint16_t deid,
+ uint16_t seid,
+ uint16_t deid,
#elif defined(BUILD_ETH_LLC)
- uint8_t ssap,
- uint8_t dsap,
+ uint8_t ssap,
+ uint8_t dsap,
#endif
- int response,
- const void * data,
- size_t len)
+ int response,
+ const buffer_t * data)
{
struct mgmt_msg * msg;
uint8_t * buf;
- buf = malloc(sizeof(*msg) + ETH_HEADER_TOT_SIZE + len);
+ buf = malloc(sizeof(*msg) + ETH_HEADER_TOT_SIZE + data->len);
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;
@@ -538,9 +828,10 @@ static int eth_ipcp_alloc_resp(uint8_t * dst_addr,
msg->ssap = ssap;
msg->dsap = dsap;
#endif
- msg->response = response;
+ msg->response = hton32(response);
- memcpy(msg + 1, data, len);
+ if (data->len > 0)
+ memcpy(msg + 1, data->data, data->len);
if (eth_ipcp_send_frame(dst_addr,
#if defined(BUILD_ETH_DIX)
@@ -549,52 +840,85 @@ static int eth_ipcp_alloc_resp(uint8_t * dst_addr,
reverse_bits(MGMT_SAP),
reverse_bits(MGMT_SAP),
#endif
- buf, sizeof(*msg) + len)) {
+ buf, sizeof(*msg) + data->len)) {
free(buf);
return -1;
}
+ FETCH_ADD_RELAXED(&eth_data.stat.n_mgmt_snd, 1);
+
free(buf);
return 0;
}
-static int eth_ipcp_req(uint8_t * r_addr,
+static int eth_ipcp_flow_update(int fd,
+ const buffer_t * data)
+{
+ struct mgmt_msg * msg;
+ struct ef * flow;
+ uint8_t * buf;
+ uint8_t r_addr[MAC_SIZE];
+ int ret;
+
+ buf = malloc(sizeof(*msg) + ETH_HEADER_TOT_SIZE + data->len);
+ 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_IRM_UPDATE;
+
+ pthread_rwlock_rdlock(&eth_data.flows_lock);
+
+ flow = &eth_data.fd_to_ef[fd];
#if defined(BUILD_ETH_DIX)
- uint16_t r_eid,
+ msg->seid = htons((uint16_t) fd);
+ msg->deid = htons((uint16_t) flow->r_eid);
#elif defined(BUILD_ETH_LLC)
- uint8_t r_sap,
+ msg->ssap = flow->sap;
+ msg->dsap = (uint8_t) flow->r_sap;
#endif
- const uint8_t * dst,
- qosspec_t qs,
- const void * data,
- size_t len)
-{
- struct timespec ts = {0, ALLOC_TIMEO * MILLION};
- struct timespec abstime;
- int fd;
+ memcpy(r_addr, flow->r_addr, MAC_SIZE);
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ pthread_rwlock_unlock(&eth_data.flows_lock);
- pthread_mutex_lock(&ipcpi.alloc_lock);
+ if (data->len > 0)
+ memcpy(msg + 1, data->data, data->len);
- while (ipcpi.alloc_id != -1 && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
- &abstime);
- }
+ ret = eth_ipcp_send_frame(r_addr,
+#if defined(BUILD_ETH_DIX)
+ MGMT_EID,
+#elif defined(BUILD_ETH_LLC)
+ reverse_bits(MGMT_SAP),
+ reverse_bits(MGMT_SAP),
+#endif
+ buf, sizeof(*msg) + data->len);
+ free(buf);
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_dbg("Won't allocate over non-operational IPCP.");
- pthread_mutex_unlock(&ipcpi.alloc_lock);
- return -1;
- }
+ if (ret == 0)
+ FETCH_ADD_RELAXED(&eth_data.stat.n_mgmt_snd, 1);
+
+ return ret;
+}
- /* reply to IRM, called under lock to prevent race */
- fd = ipcp_flow_req_arr(dst, ipcp_dir_hash_len(), qs, data, len);
+static int eth_ipcp_req(uint8_t * r_addr,
+#if defined(BUILD_ETH_DIX)
+ uint16_t r_eid,
+#elif defined(BUILD_ETH_LLC)
+ uint8_t r_sap,
+#endif
+ const uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data)
+{
+ int fd;
+
+ fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_ETH_MPL,
+ ETH_MAX_PACKET_SIZE, data);
if (fd < 0) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
log_err("Could not get new flow from IRMd.");
return -1;
}
@@ -609,11 +933,6 @@ static int eth_ipcp_req(uint8_t * r_addr,
pthread_rwlock_unlock(&eth_data.flows_lock);
- ipcpi.alloc_id = fd;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
-
- pthread_mutex_unlock(&ipcpi.alloc_lock);
-
#if defined(BUILD_ETH_DIX)
log_dbg("New flow request, fd %d, remote endpoint %d.", fd, r_eid);
#elif defined(BUILD_ETH_LLC)
@@ -622,20 +941,20 @@ static int eth_ipcp_req(uint8_t * r_addr,
return 0;
}
-static int eth_ipcp_alloc_reply(uint8_t * r_addr,
+static int eth_ipcp_alloc_reply(uint8_t * r_addr,
#if defined(BUILD_ETH_DIX)
- uint16_t seid,
- uint16_t deid,
+ uint16_t seid,
+ uint16_t deid,
#elif defined(BUILD_ETH_LLC)
- uint8_t ssap,
- int dsap,
+ uint8_t ssap,
+ int dsap,
#endif
- int response,
- const void * data,
- size_t len)
+ int response,
+ const buffer_t * data)
{
- int ret = 0;
- int fd = -1;
+ int ret = 0;
+ int fd = -1;
+ time_t mpl = IPCP_ETH_MPL;
pthread_rwlock_wrlock(&eth_data.flows_lock);
@@ -645,7 +964,7 @@ static int eth_ipcp_alloc_reply(uint8_t * r_addr,
fd = eth_data.ef_to_fd[dsap];
#endif
if (fd < 0) {
- pthread_rwlock_unlock(& eth_data.flows_lock);
+ pthread_rwlock_unlock(&eth_data.flows_lock);
log_err("No flow found with that SAP.");
return -1; /* -EFLOWNOTFOUND */
}
@@ -670,11 +989,13 @@ static int eth_ipcp_alloc_reply(uint8_t * r_addr,
#elif defined(BUILD_ETH_LLC)
log_dbg("Flow reply, fd %d, SSAP %d, DSAP %d.", fd, ssap, dsap);
#endif
- if ((ret = ipcp_flow_alloc_reply(fd, response, data, len)) < 0)
+ if ((ret = ipcp_flow_alloc_reply(fd, response, mpl,
+ ETH_MAX_PACKET_SIZE, data)) < 0) {
+ log_err("Failed to reply to flow allocation.");
return -1;
+ }
return ret;
-
}
static int eth_ipcp_name_query_req(const uint8_t * hash,
@@ -691,6 +1012,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;
@@ -709,6 +1032,8 @@ static int eth_ipcp_name_query_req(const uint8_t * hash,
return -1;
}
+ FETCH_ADD_RELAXED(&eth_data.stat.n_mgmt_snd, 1);
+
free(buf);
}
@@ -718,17 +1043,55 @@ 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);
return 0;
}
+static int eth_ipcp_flow_update_arr(const uint8_t * buf,
+ size_t len)
+{
+ struct mgmt_msg * msg;
+ buffer_t data;
+ int fd;
+ int flow_id;
+
+ msg = (struct mgmt_msg *) buf;
+
+ data.data = (uint8_t *) buf + sizeof(*msg);
+ data.len = len - sizeof(*msg);
+
+ pthread_rwlock_rdlock(&eth_data.flows_lock);
+#if defined(BUILD_ETH_DIX)
+ fd = ntohs(msg->deid);
+#elif defined(BUILD_ETH_LLC)
+ fd = eth_data.ef_to_fd[msg->dsap];
+#endif
+ pthread_rwlock_unlock(&eth_data.flows_lock);
+
+ if (fd < 0 || fd >= SYS_MAX_FLOWS) {
+ log_err("Flow update for unknown endpoint.");
+ return -1;
+ }
+
+ flow_id = np1_flow_id(fd);
+ if (flow_id < 0)
+ return -1;
+
+ if (ipcp_flow_update_arr(flow_id, &data) < 0) {
+ log_err("Failed to relay flow update on fd %d.", fd);
+ return -1;
+ }
+
+ return 0;
+}
+
static int eth_ipcp_mgmt_frame(const uint8_t * buf,
size_t len,
uint8_t * r_addr)
@@ -736,6 +1099,10 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf,
struct mgmt_msg * msg;
size_t msg_len;
qosspec_t qs;
+ buffer_t data;
+
+ if (len < sizeof(*msg))
+ return -1;
msg = (struct mgmt_msg *) buf;
@@ -743,16 +1110,20 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf,
case FLOW_REQ:
msg_len = sizeof(*msg) + ipcp_dir_hash_len();
- assert(len >= msg_len);
+ if (len < msg_len)
+ return -1;
qs.delay = ntoh32(msg->delay);
qs.bandwidth = ntoh64(msg->bandwidth);
qs.availability = msg->availability;
qs.loss = ntoh32(msg->loss);
qs.ber = ntoh32(msg->ber);
- qs.in_order = msg->in_order;
+ qs.service = msg->service;
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;
+ data.len = len - msg_len;
if (shim_data_reg_has(eth_data.shim_data,
buf + sizeof(*msg))) {
@@ -764,12 +1135,12 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf,
#endif
buf + sizeof(*msg),
qs,
- buf + msg_len,
- len - msg_len);
+ &data);
}
break;
case FLOW_REPLY:
- assert(len >= sizeof(*msg));
+ data.data = (uint8_t *) buf + sizeof(*msg);
+ data.len = len - sizeof(*msg);
eth_ipcp_alloc_reply(r_addr,
#if defined(BUILD_ETH_DIX)
@@ -779,14 +1150,20 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf,
msg->ssap,
msg->dsap,
#endif
- msg->response,
- buf + sizeof(*msg),
- len - sizeof(*msg));
+ ntoh32(msg->response),
+ &data);
+ break;
+ case FLOW_IRM_UPDATE:
+ eth_ipcp_flow_update_arr(buf, len);
break;
case NAME_QUERY_REQ:
+ if (len < sizeof(*msg) + ipcp_dir_hash_len())
+ return -1;
eth_ipcp_name_query_req(buf + sizeof(*msg), r_addr);
break;
case NAME_QUERY_REPLY:
+ if (len < sizeof(*msg) + ipcp_dir_hash_len())
+ return -1;
eth_ipcp_name_query_reply(buf + sizeof(*msg), r_addr);
break;
default:
@@ -799,18 +1176,15 @@ static int eth_ipcp_mgmt_frame(const uint8_t * buf,
static void * eth_ipcp_mgmt_handler(void * o)
{
- int ret;
- struct timespec timeout = {(MGMT_TIMEO / 1000),
- (MGMT_TIMEO % 1000) * MILLION};
- struct timespec abstime;
- struct mgmt_frame * frame;
-
(void) o;
pthread_cleanup_push(__cleanup_mutex_unlock, &eth_data.mgmt_lock);
while (true) {
- ret = 0;
+ int ret = 0;
+ struct timespec timeout = TIMESPEC_INIT_MS(MGMT_TIMEO);
+ struct timespec abstime;
+ struct mgmt_frame * frame = NULL;
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeout, &abstime);
@@ -822,23 +1196,19 @@ static void * eth_ipcp_mgmt_handler(void * o)
ret = -pthread_cond_timedwait(&eth_data.mgmt_cond,
&eth_data.mgmt_lock,
&abstime);
+ if (ret != -ETIMEDOUT)
+ frame = list_first_entry((&eth_data.mgmt_frames),
+ struct mgmt_frame, next);
+ if (frame != NULL)
+ list_del(&frame->next);
- if (ret == -ETIMEDOUT) {
- pthread_mutex_unlock(&eth_data.mgmt_lock);
- continue;
- }
+ pthread_mutex_unlock(&eth_data.mgmt_lock);
- frame = list_first_entry((&eth_data.mgmt_frames),
- struct mgmt_frame, next);
- if (frame == NULL) {
- pthread_mutex_unlock(&eth_data.mgmt_lock);
+ if (frame == NULL)
continue;
- }
-
- list_del(&frame->next);
- pthread_mutex_unlock(&eth_data.mgmt_lock);
eth_ipcp_mgmt_frame(frame->buf, frame->len, frame->r_addr);
+
free(frame);
}
@@ -862,10 +1232,16 @@ 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
+#if defined(HAVE_RAW_SOCKETS)
+ struct sockaddr_ll src;
+ socklen_t slen;
+#endif
+ size_t eth_len;
+ uint8_t hcs;
struct eth_frame * e_frame;
struct mgmt_frame * frame;
@@ -884,7 +1260,7 @@ static void * eth_ipcp_packet_reader(void * o)
buf = nm_nextpkt(eth_data.nmd, &hdr);
if (buf == NULL) {
- log_err("Bad read from netmap device.");
+ log_dbg("Bad read from netmap device.");
continue;
}
#else
@@ -894,32 +1270,67 @@ 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)) {
+ FETCH_ADD_RELAXED(&eth_data.stat.n_buf_f, 1);
continue;
- buf = shm_du_buff_head_alloc(sdb, ETH_HEADER_TOT_SIZE);
+ }
+ buf = ssm_pk_buff_push(spb, ETH_HEADER_TOT_SIZE);
if (buf == NULL) {
log_dbg("Failed to allocate header.");
- ipcp_sdb_release(sdb);
+ ipcp_spb_release(spb);
+ FETCH_ADD_RELAXED(&eth_data.stat.n_buf_f, 1);
continue;
}
- frame_len = recv(eth_data.s_fd, buf,
- ETH_MTU + ETH_HEADER_TOT_SIZE, 0);
+ slen = sizeof(src);
+ /* MSG_DONTWAIT: RD_THR>1 race-loser bails with EAGAIN. */
+ frame_len = recvfrom(eth_data.s_fd, buf,
+ ETH_MTU + ETH_HEADER_TOT_SIZE,
+ MSG_DONTWAIT,
+ (struct sockaddr *) &src, &slen);
#endif
- if (frame_len <= 0) {
- ipcp_sdb_release(sdb);
+ if (frame_len == 0) {
+ ipcp_spb_release(spb);
+ continue; /* Spurious */
+ }
+
+ if (frame_len < 0) {
+ ipcp_spb_release(spb);
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ continue;
+
+ log_dbg("Failed to rcv frame: %s.", strerror(errno));
+ FETCH_ADD_RELAXED(&eth_data.stat.n_rcv_f, 1);
continue;
}
#endif
+#if defined(HAVE_NETMAP)
+ eth_len = hdr.len;
+#elif defined(HAVE_BPF)
+ eth_len = ((struct bpf_hdr *) buf)->bh_caplen;
+#else
+ eth_len = (size_t) frame_len;
+#endif
+ /* Defense in depth: reject before parsing dereferences. */
+ if (eth_len < ETH_HEADER_TOT_SIZE)
+ goto fail_frame;
+
+#if defined(HAVE_RAW_SOCKETS)
+ /* Drop our own egress. */
+ if (src.sll_pkttype == PACKET_OUTGOING)
+ goto fail_frame;
+#endif
+
#if defined(HAVE_BPF) && !defined(HAVE_NETMAP)
e_frame = (struct eth_frame *)
(buf + ((struct bpf_hdr *) buf)->bh_hdrlen);
@@ -937,39 +1348,63 @@ static void * eth_ipcp_packet_reader(void * o)
e_frame->dst_hwaddr,
MAC_SIZE) &&
memcmp(br_addr, e_frame->dst_hwaddr, MAC_SIZE)) {
+ FETCH_ADD_RELAXED(&eth_data.stat.n_bad_id, 1);
+ goto fail_frame;
}
#endif
length = ntohs(e_frame->length);
#if defined(BUILD_ETH_DIX)
- if (e_frame->ethertype != eth_data.ethertype) {
-#ifndef HAVE_NETMAP
- ipcp_sdb_release(sdb);
-#endif
- continue;
- }
+ if (e_frame->ethertype != eth_data.ethertype)
+ goto fail_frame;
+
+ if (length > ETH_MTU)
+ goto fail_frame;
deid = ntohs(e_frame->eid);
- if (deid == MGMT_EID) {
#elif defined (BUILD_ETH_LLC)
- if (length > 0x05FF) {/* DIX */
-#ifndef HAVE_NETMAP
- ipcp_sdb_release(sdb);
-#endif
- continue;
- }
+ if (length > 0x05FF) /* DIX */
+ goto fail_frame;
+
+ if (length < LLC_HEADER_SIZE || length > ETH_MTU)
+ goto fail_frame;
length -= LLC_HEADER_SIZE;
dsap = reverse_bits(e_frame->dsap);
ssap = reverse_bits(e_frame->ssap);
+#endif
+
+ if (eth_len < ETH_HEADER_TOT_SIZE + (size_t) length)
+ goto fail_frame;
+
+#if defined(BUILD_ETH_DIX)
+ mem_hash(HASH_CRC8, &hcs,
+ (uint8_t *) &e_frame->eid,
+ DIX_EID_SIZE + DIX_LENGTH_SIZE);
+#elif defined(BUILD_ETH_LLC)
+ mem_hash(HASH_CRC8, &hcs,
+ (uint8_t *) &e_frame->dsap,
+ LLC_FIELDS_SIZE);
+#endif
+ if (hcs != e_frame->hcs)
+ goto fail_frame;
+#if defined(BUILD_ETH_DIX)
+ if (deid == MGMT_EID) {
+#elif defined (BUILD_ETH_LLC)
if (ssap == MGMT_SAP && dsap == MGMT_SAP) {
#endif
+ 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);
+ continue;
+ }
+
frame = malloc(sizeof(*frame));
if (frame == NULL) {
-#ifndef HAVE_NETMAP
- ipcp_sdb_release(sdb);
-#endif
+ log_err("Failed to allocate frame.");
continue;
}
@@ -981,10 +1416,8 @@ static void * eth_ipcp_packet_reader(void * o)
list_add(&frame->next, &eth_data.mgmt_frames);
pthread_cond_signal(&eth_data.mgmt_cond);
pthread_mutex_unlock(&eth_data.mgmt_lock);
-
-#ifndef HAVE_NETMAP
- ipcp_sdb_release(sdb);
-#endif
+ FETCH_ADD_RELAXED(&eth_data.stat.n_rcv, 1);
+ FETCH_ADD_RELAXED(&eth_data.stat.n_mgmt_rcv, 1);
} else {
pthread_rwlock_rdlock(&eth_data.flows_lock);
@@ -995,10 +1428,8 @@ static void * eth_ipcp_packet_reader(void * o)
#endif
if (fd < 0) {
pthread_rwlock_unlock(&eth_data.flows_lock);
-#ifndef HAVE_NETMAP
- ipcp_sdb_release(sdb);
-#endif
- continue;
+ FETCH_ADD_RELAXED(&eth_data.stat.n_bad_id, 1);
+ goto fail_frame;
}
#ifdef BUILD_ETH_LLC
@@ -1006,20 +1437,38 @@ static void * eth_ipcp_packet_reader(void * o)
|| memcmp(eth_data.fd_to_ef[fd].r_addr,
e_frame->src_hwaddr, MAC_SIZE)) {
pthread_rwlock_unlock(&eth_data.flows_lock);
-#ifndef HAVE_NETMAP
- ipcp_sdb_release(sdb);
-#endif
- continue;
+ FETCH_ADD_RELAXED(&eth_data.stat.n_bad_id, 1);
+ goto fail_frame;
}
#endif
+ FETCH_ADD_RELAXED(&eth_data.fd_to_ef[fd].stat.p_rcv, 1);
+ FETCH_ADD_RELAXED(&eth_data.fd_to_ef[fd].stat.b_rcv,
+ length);
+ FETCH_ADD_RELAXED(&eth_data.stat.n_rcv, 1);
pthread_rwlock_unlock(&eth_data.flows_lock);
#ifndef HAVE_NETMAP
- shm_du_buff_head_release(sdb, ETH_HEADER_TOT_SIZE);
- shm_du_buff_truncate(sdb, length);
- ipcp_flow_write(fd, sdb);
+ ssm_pk_buff_pop(spb, ETH_HEADER_TOT_SIZE);
+ ssm_pk_buff_truncate(spb, length);
#else
- flow_write(fd, &e_frame->payload, length);
+ if (ipcp_spb_reserve(&spb, length))
+ continue;
+
+ buf = ssm_pk_buff_head(spb);
+ memcpy(buf, &e_frame->payload, length);
+#endif
+ if (np1_flow_write(fd, spb, NP1_GET_POOL(fd)) < 0) {
+ ipcp_spb_release(spb);
+ FETCH_ADD_RELAXED(
+ &eth_data.fd_to_ef[fd].stat.p_dlv_f,
+ 1);
+ FETCH_ADD_RELAXED(&eth_data.stat.n_dlv_f, 1);
+ }
+
+ continue;
+ fail_frame:
+#ifndef HAVE_NETMAP
+ ipcp_spb_release(spb);
#endif
}
}
@@ -1035,7 +1484,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;
@@ -1053,27 +1502,29 @@ static void * eth_ipcp_packet_writer(void * o)
(void) o;
- pthread_cleanup_push(cleanup_writer, fq);
-
ipcp_lock_to_core();
+ pthread_cleanup_push(cleanup_writer, fq);
+
while (true) {
fevent(eth_data.np1_flows, fq, NULL);
while ((fd = fqueue_next(fq)) >= 0) {
if (fqueue_type(fq) != FLOW_PKT)
continue;
- if (ipcp_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_tail(sdb) - shm_du_buff_head(sdb);
+ len = ssm_pk_buff_len(spb);
- if (shm_du_buff_head_alloc(sdb, ETH_HEADER_TOT_SIZE)
+ if (ssm_pk_buff_push(spb, ETH_HEADER_TOT_SIZE)
== NULL) {
log_dbg("Failed to allocate header.");
- ipcp_sdb_release(sdb);
+ ipcp_spb_release(spb);
+ FETCH_ADD_RELAXED(&eth_data.stat.n_buf_f, 1);
+ continue;
}
pthread_rwlock_rdlock(&eth_data.flows_lock);
@@ -1089,15 +1540,28 @@ static void * eth_ipcp_packet_writer(void * o)
pthread_rwlock_unlock(&eth_data.flows_lock);
- eth_ipcp_send_frame(r_addr,
+ if (eth_ipcp_send_frame(r_addr,
#if defined(BUILD_ETH_DIX)
deid,
#elif defined(BUILD_ETH_LLC)
dsap, ssap,
#endif
- shm_du_buff_head(sdb),
- len);
- ipcp_sdb_release(sdb);
+ ssm_pk_buff_head(spb),
+ len)) {
+ log_dbg("Failed to send frame.");
+ FETCH_ADD_RELAXED(
+ &eth_data.fd_to_ef[fd].stat.p_snd_f,
+ 1);
+ FETCH_ADD_RELAXED(&eth_data.stat.n_snd_f, 1);
+ } else {
+ FETCH_ADD_RELAXED(
+ &eth_data.fd_to_ef[fd].stat.p_snd,
+ 1);
+ FETCH_ADD_RELAXED(
+ &eth_data.fd_to_ef[fd].stat.b_snd,
+ len);
+ }
+ ipcp_spb_release(spb);
}
}
@@ -1246,148 +1710,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);
+ int idx;
- ipcpi.dir_hash_algo = conf->layer_info.dir_hash_algo;
- ipcpi.layer_name = strdup(conf->layer_info.layer_name);
- if (ipcpi.layer_name == NULL) {
- log_err("Failed to set layer name");
- return -ENOMEM;
+ if (getifaddrs(&ifaddr) < 0) {
+ log_err("Could not get interfaces.");
+ goto fail_ifaddrs;
}
- if (conf->dev == NULL) {
- log_err("Device name is NULL.");
- return -1;
+ for (ifa = ifaddr, idx = 0; ifa != NULL; ifa = ifa->ifa_next, ++idx) {
+ if (strcmp(ifa->ifa_name, ifr->ifr_name) == 0)
+ break;
}
- if (strlen(conf->dev) >= IFNAMSIZ) {
- log_err("Invalid device name: %s.", conf->dev);
- return -1;
+ if (ifa == NULL) {
+ log_err("Interface not found.");
+ goto fail_ifa;
}
- memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, conf->dev);
+ memcpy(&ifr->ifr_addr, ifa->ifa_addr, sizeof(*ifa->ifa_addr));
-#ifdef BUILD_ETH_DIX
- if (conf->ethertype < 0x0600 || conf->ethertype == 0xFFFF) {
- log_err("Invalid Ethertype.");
- return -1;
- }
- eth_data.ethertype = htons(conf->ethertype);
-#endif
+ log_dbg("Interface %s hwaddr " MAC_FMT ".", ifr->ifr_name,
+ MAC_VAL(ifr->ifr_addr.sa_data));
-#if defined(__FreeBSD__) || defined(__APPLE__)
- if (getifaddrs(&ifaddr) < 0) {
- log_err("Could not get interfaces.");
- return -1;
+ 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;
}
- for (ifa = ifaddr, idx = 0; ifa != NULL; ifa = ifa->ifa_next, ++idx) {
- if (strcmp(ifa->ifa_name, conf->dev))
- continue;
- log_dbg("Interface %s found.", conf->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 (ioctl(skfd, SIOCGIFHWADDR, ifr)) {
+ log_err("Failed to get hwaddr.");
+ goto fail_ifr;
}
- freeifaddrs(ifaddr);
+ log_dbg("Interface %s hwaddr " MAC_FMT ".", ifr->ifr_name,
+ MAC_VAL(ifr->ifr_hwaddr.sa_data));
- if (ifa == NULL) {
- log_err("Interface not found.");
- return -1;
- }
+ 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->dev, "lo", 2) == 0 && eth_data.mtu > IPCP_ETH_LO_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;
}
-#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;
- }
-#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->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->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));
@@ -1399,11 +1853,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);
@@ -1413,7 +1878,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;
}
@@ -1434,112 +1899,203 @@ 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)
+#define SOCKOPT()
+static int eth_init_raw_socket(struct ifreq * ifr)
+{
+ int idx;
+ int sndbuf;
+ int rcvbuf;
+#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.");
- return -1;
+ goto fail_socket;
}
- flags = fcntl(eth_data.s_fd, F_GETFL, 0);
- if (flags < 0) {
- log_err("Failed to get flags.");
- goto fail_device;
+#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
- if (fcntl(eth_data.s_fd, F_SETFL, flags | O_NONBLOCK)) {
- log_err("Failed to set socket non-blocking.");
- goto fail_device;
+ sndbuf = IPCP_ETH_SNDBUF;
+ if (sndbuf > 0) {
+ /* Never below one frame or sendto() cannot fit an SDU. */
+ sndbuf = MAX(sndbuf, (int) (ETH_HEADER_TOT_SIZE + ETH_MTU));
+ if (setsockopt(eth_data.s_fd, SOL_SOCKET, SO_SNDBUF,
+ &sndbuf, sizeof(sndbuf)))
+ log_info("Failed to set SO_SNDBUF to %d.", sndbuf);
}
- #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.");
+ rcvbuf = IPCP_ETH_RCVBUF;
+ if (rcvbuf > 0) {
+ /* SO_RCVBUFFORCE bypasses rmem_max; SO_RCVBUF is fallback. */
+ if (setsockopt(eth_data.s_fd, SOL_SOCKET, SO_RCVBUFFORCE,
+ &rcvbuf, sizeof(rcvbuf))
+ && setsockopt(eth_data.s_fd, SOL_SOCKET, SO_RCVBUF,
+ &rcvbuf, sizeof(rcvbuf)))
+ log_info("Failed to set SO_RCVBUF to %d.", rcvbuf);
}
- #endif
if (bind(eth_data.s_fd, (struct sockaddr *) &eth_data.device,
- sizeof(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 */
- ipcp_set_state(IPCP_OPERATIONAL);
-#if defined(__linux__)
- if (pthread_create(&eth_data.if_monitor,
- NULL,
- eth_ipcp_if_monitor,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
- goto fail_device;
+ 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 (pthread_create(&eth_data.mgmt_handler,
- NULL,
- eth_ipcp_mgmt_handler,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
+ 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 */
+#ifdef IPCP_ETH_FLOW_STATS
+ if (rib_reg(ETH_RIB_PATH, &eth_r_ops)) {
+ log_err("Failed to register RIB.");
+ goto fail_rib_reg;
+ }
+#endif
+#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_monitor;
+ }
+#endif
+ if (pthread_create(&eth_data.mgmt_handler, NULL,
+ eth_ipcp_mgmt_handler, NULL)) {
+ log_err("Failed to create mgmt handler thread: %s.",
+ strerror(errno));
goto fail_mgmt_handler;
}
- for (idx = 0; idx < IPCP_ETH_RD_THR; ++idx) {
- if (pthread_create(&eth_data.packet_reader[idx],
- NULL,
- eth_ipcp_packet_reader,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
+ 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));
goto fail_packet_reader;
}
}
- for (idx = 0; idx < IPCP_ETH_WR_THR; ++idx) {
- if (pthread_create(&eth_data.packet_writer[idx],
- NULL,
- eth_ipcp_packet_writer,
- NULL)) {
- ipcp_set_state(IPCP_INIT);
+ 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));
goto fail_packet_writer;
}
}
#if defined(BUILD_ETH_DIX)
log_dbg("Bootstrapped IPCP over DIX Ethernet with pid %d "
- "and Ethertype 0x%X.", getpid(), conf->ethertype);
+ "and Ethertype 0x%X.", getpid(), conf->eth.ethertype);
#elif defined(BUILD_ETH_LLC)
log_dbg("Bootstrapped IPCP over Ethernet with LLC with pid %d.",
getpid());
#endif
-
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);
@@ -1548,8 +2104,12 @@ 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
+#ifdef IPCP_ETH_FLOW_STATS
+ rib_unreg(ETH_RIB_PATH);
+ fail_rib_reg:
#endif
#if defined(HAVE_NETMAP)
nm_close(eth_data.nmd);
@@ -1564,13 +2124,11 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf)
static int eth_ipcp_reg(const uint8_t * hash)
{
if (shim_data_reg_add_entry(eth_data.shim_data, hash)) {
- log_err("Failed to add " HASH_FMT " to local registry.",
- HASH_VAL(hash));
+ log_err("Failed to add " HASH_FMT32 " to local registry.",
+ HASH_VAL32(hash));
return -1;
}
- log_dbg("Registered " HASH_FMT ".", HASH_VAL(hash));
-
return 0;
}
@@ -1584,13 +2142,14 @@ static int eth_ipcp_unreg(const uint8_t * hash)
static int eth_ipcp_query(const uint8_t * hash)
{
uint8_t r_addr[MAC_SIZE];
- struct timespec timeout = {(NAME_QUERY_TIMEO / 1000),
- (NAME_QUERY_TIMEO % 1000) * MILLION};
+ struct timespec timeout;
struct dir_query * query;
int ret;
+ int attempt;
uint8_t * buf;
struct mgmt_msg * msg;
size_t len;
+ long per_ms;
if (shim_data_dir_has(eth_data.shim_data, hash))
return 0;
@@ -1601,6 +2160,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;
@@ -1608,71 +2169,84 @@ static int eth_ipcp_query(const uint8_t * hash)
memset(r_addr, 0xff, MAC_SIZE);
- query = shim_data_dir_query_create(eth_data.shim_data, hash);
- if (query == NULL) {
- free(buf);
- return -1;
- }
+ per_ms = NAME_QUERY_TIMEO / (NAME_QUERY_RETRIES + 1);
+
+ ret = -1;
+ for (attempt = 0; attempt <= NAME_QUERY_RETRIES; ++attempt) {
+ query = shim_data_dir_query_create(eth_data.shim_data, hash);
+ if (query == NULL) {
+ ret = -1;
+ break;
+ }
- if (eth_ipcp_send_frame(r_addr,
+ if (eth_ipcp_send_frame(r_addr,
#if defined(BUILD_ETH_DIX)
- MGMT_EID,
+ MGMT_EID,
#elif defined(BUILD_ETH_LLC)
- reverse_bits(MGMT_SAP),
- reverse_bits(MGMT_SAP),
+ reverse_bits(MGMT_SAP),
+ reverse_bits(MGMT_SAP),
#endif
- buf, len)) {
- log_err("Failed to send management frame.");
+ buf, len)) {
+ log_err("Failed to send management frame.");
+ shim_data_dir_query_destroy(eth_data.shim_data,
+ query);
+ ret = -1;
+ break;
+ }
+
+ FETCH_ADD_RELAXED(&eth_data.stat.n_mgmt_snd, 1);
+
+ timeout.tv_sec = per_ms / 1000;
+ timeout.tv_nsec = (per_ms % 1000) * 1000000L;
+
+ ret = shim_data_dir_query_wait(query, &timeout);
+
shim_data_dir_query_destroy(eth_data.shim_data, query);
- free(buf);
- return -1;
+
+ if (ret != -ETIMEDOUT)
+ break;
}
free(buf);
- ret = shim_data_dir_query_wait(query, &timeout);
-
- shim_data_dir_query_destroy(eth_data.shim_data, query);
-
return ret;
}
-static int eth_ipcp_flow_alloc(int fd,
- const uint8_t * hash,
- qosspec_t qs,
- const void * data,
- size_t len)
+static int eth_ipcp_flow_alloc(int fd,
+ const uint8_t * hash,
+ qosspec_t qs,
+ const buffer_t * data)
{
#ifdef BUILD_ETH_LLC
uint8_t ssap = 0;
#endif
uint8_t r_addr[MAC_SIZE];
- uint64_t addr = 0;
-
- log_dbg("Allocating flow to " HASH_FMT ".", HASH_VAL(hash));
+ struct addr addr;
assert(hash);
if (!shim_data_dir_has(eth_data.shim_data, hash)) {
- log_err("Destination unreachable.");
+ log_err("Destination "HASH_FMT32 "unreachable.",
+ 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);
+ log_err("Failed to allocate SSAP.");
return -1;
}
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)
@@ -1682,34 +2256,37 @@ static int eth_ipcp_flow_alloc(int fd,
#endif
hash,
qs,
- data,
- len) < 0) {
+ data) < 0) {
#ifdef BUILD_ETH_LLC
pthread_rwlock_wrlock(&eth_data.flows_lock);
bmp_release(eth_data.saps, eth_data.fd_to_ef[fd].sap);
eth_data.fd_to_ef[fd].sap = -1;
eth_data.ef_to_fd[ssap] = -1;
pthread_rwlock_unlock(&eth_data.flows_lock);
+ log_err("Failed to allocate with peer.");
#endif
return -1;
}
fset_add(eth_data.np1_flows, fd);
-#if defined(BUILD_ETH_DIX)
- log_dbg("Pending flow with fd %d.", fd);
-#elif defined(BUILD_ETH_LLC)
- log_dbg("Pending flow with fd %d on SAP %d.", fd, ssap);
+#ifdef IPCP_ETH_FLOW_STATS
+ pthread_rwlock_wrlock(&eth_data.flows_lock);
+ memset(&eth_data.fd_to_ef[fd].stat, 0,
+ sizeof(eth_data.fd_to_ef[fd].stat));
+ eth_data.fd_to_ef[fd].stat.stamp = time(NULL);
+ FETCH_ADD_RELAXED(&eth_data.stat.n_flows, 1);
+ pthread_rwlock_unlock(&eth_data.flows_lock);
+#endif
+#if defined(BUILD_ETH_LLC)
+ log_dbg("Assigned SAP %d for fd %d.", ssap, fd);
#endif
return 0;
}
-static int eth_ipcp_flow_alloc_resp(int fd,
- int response,
- const void * data,
- size_t len)
+static int eth_ipcp_flow_alloc_resp(int fd,
+ int response,
+ const buffer_t * data)
{
- struct timespec ts = {0, ALLOC_TIMEO * MILLION};
- struct timespec abstime;
#if defined(BUILD_ETH_DIX)
uint16_t r_eid;
#elif defined(BUILD_ETH_LLC)
@@ -1718,27 +2295,11 @@ static int eth_ipcp_flow_alloc_resp(int fd,
#endif
uint8_t r_addr[MAC_SIZE];
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
-
- pthread_mutex_lock(&ipcpi.alloc_lock);
-
- while (ipcpi.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
- &abstime);
- }
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
+ if (ipcp_wait_flow_resp(fd) < 0) {
+ log_err("Failed to wait for flow response.");
return -1;
}
- ipcpi.alloc_id = -1;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
-
- pthread_mutex_unlock(&ipcpi.alloc_lock);
-
pthread_rwlock_wrlock(&eth_data.flows_lock);
#if defined(BUILD_ETH_DIX)
r_eid = eth_data.fd_to_ef[fd].r_eid;
@@ -1746,6 +2307,7 @@ static int eth_ipcp_flow_alloc_resp(int fd,
ssap = bmp_allocate(eth_data.saps);
if (!bmp_is_id_valid(eth_data.saps, ssap)) {
pthread_rwlock_unlock(&eth_data.flows_lock);
+ log_err("Failed to allocate SSAP.");
return -1;
}
@@ -1764,21 +2326,27 @@ static int eth_ipcp_flow_alloc_resp(int fd,
ssap, r_sap,
#endif
response,
- data,
- len) < 0) {
+ data) < 0) {
#ifdef BUILD_ETH_LLC
pthread_rwlock_wrlock(&eth_data.flows_lock);
bmp_release(eth_data.saps, eth_data.fd_to_ef[fd].sap);
pthread_rwlock_unlock(&eth_data.flows_lock);
#endif
+ log_err("Failed to respond to peer.");
return -1;
}
fset_add(eth_data.np1_flows, fd);
-#if defined(BUILD_ETH_DIX)
- log_dbg("Accepted flow, fd %d.", fd);
-#elif defined(BUILD_ETH_LLC)
- log_dbg("Accepted flow, fd %d, SAP %d.", fd, (uint8_t)ssap);
+#ifdef IPCP_ETH_FLOW_STATS
+ pthread_rwlock_wrlock(&eth_data.flows_lock);
+ memset(&eth_data.fd_to_ef[fd].stat, 0,
+ sizeof(eth_data.fd_to_ef[fd].stat));
+ eth_data.fd_to_ef[fd].stat.stamp = time(NULL);
+ FETCH_ADD_RELAXED(&eth_data.stat.n_flows, 1);
+ pthread_rwlock_unlock(&eth_data.flows_lock);
+#endif
+#if defined(BUILD_ETH_LLC)
+ log_dbg("Assigned SAP %d for fd %d.", ssap, fd);
#endif
return 0;
}
@@ -1805,11 +2373,15 @@ static int eth_ipcp_flow_dealloc(int fd)
#endif
memset(&eth_data.fd_to_ef[fd].r_addr, 0, MAC_SIZE);
- pthread_rwlock_unlock(&eth_data.flows_lock);
+#ifdef IPCP_ETH_FLOW_STATS
+ memset(&eth_data.fd_to_ef[fd].stat, 0,
+ sizeof(eth_data.fd_to_ef[fd].stat));
+ FETCH_SUB_RELAXED(&eth_data.stat.n_flows, 1);
+#endif
- flow_dealloc(fd);
+ pthread_rwlock_unlock(&eth_data.flows_lock);
- log_dbg("Flow with fd %d deallocated.", fd);
+ ipcp_flow_dealloc(fd);
return 0;
}
@@ -1825,7 +2397,8 @@ static struct ipcp_ops eth_ops = {
.ipcp_flow_alloc = eth_ipcp_flow_alloc,
.ipcp_flow_join = NULL,
.ipcp_flow_alloc_resp = eth_ipcp_flow_alloc_resp,
- .ipcp_flow_dealloc = eth_ipcp_flow_dealloc
+ .ipcp_flow_dealloc = eth_ipcp_flow_dealloc,
+ .ipcp_flow_update = eth_ipcp_flow_update
};
int main(int argc,
@@ -1833,9 +2406,6 @@ int main(int argc,
{
int i;
- if (ipcp_init(argc, argv, &eth_ops, THIS_TYPE) < 0)
- goto fail_init;
-
if (eth_data_init() < 0) {
#if defined(BUILD_ETH_DIX)
log_err("Failed to init eth-llc data.");
@@ -1845,18 +2415,17 @@ int main(int argc,
goto fail_data_init;
}
- if (ipcp_boot() < 0) {
- log_err("Failed to boot IPCP.");
- goto fail_boot;
+ if (ipcp_init(argc, argv, &eth_ops, THIS_TYPE) < 0) {
+ log_err("Failed to initialize IPCP.");
+ goto fail_init;
}
- if (ipcp_create_r(0)) {
- log_err("Failed to notify IRMd we are initialized.");
- ipcp_set_state(IPCP_NULL);
- goto fail_create_r;
+ if (ipcp_start() < 0) {
+ log_err("Failed to start IPCP.");
+ goto fail_start;
}
- ipcp_shutdown();
+ ipcp_sigwait();
if (ipcp_get_state() == IPCP_SHUTDOWN) {
for (i = 0; i < IPCP_ETH_WR_THR; ++i)
@@ -1877,21 +2446,23 @@ int main(int argc,
#ifdef __linux__
pthread_join(eth_data.if_monitor, NULL);
#endif
+#ifdef IPCP_ETH_FLOW_STATS
+ rib_unreg(ETH_RIB_PATH);
+#endif
}
- eth_data_fini();
+ ipcp_stop();
ipcp_fini();
+ eth_data_fini();
+
exit(EXIT_SUCCESS);
- fail_create_r:
- ipcp_shutdown();
- fail_boot:
- eth_data_fini();
- fail_data_init:
+ fail_start:
ipcp_fini();
fail_init:
- ipcp_create_r(-1);
+ eth_data_fini();
+ fail_data_init:
exit(EXIT_FAILURE);
}