pespin has submitted this change. (
https://gerrit.osmocom.org/c/osmo-pcap/+/39370?usp=email )
Change subject: server: zero-copy msgb from tcp read to file write
......................................................................
server: zero-copy msgb from tcp read to file write
Related: SYS#7080
Change-Id: Iae9b9eaec42ad8ec86d1a8144d676115fa057766
---
M include/osmo-pcap/osmo_pcap_server.h
M src/osmo_server_core.c
M src/osmo_server_network.c
3 files changed, 97 insertions(+), 67 deletions(-)
Approvals:
osmith: Looks good to me, but someone else must approve
fixeria: Looks good to me, but someone else must approve
Jenkins Builder: Verified
pespin: Looks good to me, approved
diff --git a/include/osmo-pcap/osmo_pcap_server.h b/include/osmo-pcap/osmo_pcap_server.h
index e71096b..f97e4ae 100644
--- a/include/osmo-pcap/osmo_pcap_server.h
+++ b/include/osmo-pcap/osmo_pcap_server.h
@@ -121,15 +121,13 @@
/* pcap stuff */
enum osmo_pcap_fmt file_fmt;
bool pcapng_endian_swapped;
- uint8_t *file_hdr;
- uint32_t file_hdr_len;
+ struct msgb *file_hdr_msg;
/* last time */
struct tm last_write;
/* read buffering */
int state;
- int pend;
bool reopen_delayed;
size_t data_max_len; /* size of allocated buffer in data->data. */
@@ -141,13 +139,13 @@
size_t tls_limit_read;
struct osmo_tls_session tls_session;
struct osmo_wqueue rem_wq;
- struct osmo_pcap_data *data; /* Used to store TLS decoded data */
+ struct msgb *rx_tls_dec_msg; /* Used to store TLS decoded data */
};
void osmo_pcap_conn_free(struct osmo_pcap_conn *conn);
void vty_server_init(void);
void osmo_pcap_conn_close(struct osmo_pcap_conn *conn);
-int osmo_pcap_conn_process_data(struct osmo_pcap_conn *conn, const uint8_t *data, size_t
len);
+int osmo_pcap_conn_process_data(struct osmo_pcap_conn *conn, struct msgb *msg);
void osmo_pcap_conn_restart_trace(struct osmo_pcap_conn *conn);
void osmo_pcap_conn_close_trace(struct osmo_pcap_conn *conn);
void osmo_pcap_conn_event(struct osmo_pcap_conn *conn,
diff --git a/src/osmo_server_core.c b/src/osmo_server_core.c
index 04c14c1..9629423 100644
--- a/src/osmo_server_core.c
+++ b/src/osmo_server_core.c
@@ -109,7 +109,7 @@
talloc_free(event_name);
pcap_zmq_send(conn->server->zmq_publ,
- conn->file_hdr, conn->file_hdr_len,
+ msgb_data(conn->file_hdr_msg), msgb_length(conn->file_hdr_msg),
ZMQ_SNDMORE);
pcap_zmq_send(conn->server->zmq_publ,
data, len,
@@ -199,7 +199,6 @@
INIT_LLIST_HEAD(&conn->wrf_flushing_list);
conn->data_max_len = calc_data_max_len(server);
- conn->data = talloc_zero_size(conn, sizeof(struct osmo_pcap_data) +
conn->data_max_len);
/* a bit nasty. we do not work with ids but names */
desc = talloc_zero(conn, struct rate_ctr_group_desc);
if (!desc) {
@@ -289,9 +288,11 @@
close(conn->rem_wq.bfd.fd);
conn->rem_wq.bfd.fd = -1;
osmo_tls_release(&conn->tls_session);
+ msgb_free(conn->rx_tls_dec_msg);
+ conn->rx_tls_dec_msg = NULL;
}
- TALLOC_FREE(conn->file_hdr);
- conn->file_hdr_len = 0;
+ msgb_free(conn->file_hdr_msg);
+ conn->file_hdr_msg = NULL;
osmo_pcap_conn_close_trace(conn);
osmo_pcap_conn_event(conn, "disconnect", NULL);
@@ -318,6 +319,7 @@
struct tm tm;
int rc;
char *real_base_path, *curr_filename;
+ struct msgb *msg;
osmo_pcap_conn_close_trace(conn);
@@ -352,10 +354,10 @@
if (rc < 0)
return;
- /* TODO: get msgb from conn object stored: */
- struct msgb *msg = msgb_alloc_c(conn->wrf, conn->file_hdr_len,
"local_iofd_hdr");
- memcpy(msgb_put(msg, conn->file_hdr_len), conn->file_hdr, conn->file_hdr_len);
-
+ /* We need to keep a clone assigned to conn to check for incoming hdr changes: */
+ OSMO_ASSERT(conn->file_hdr_msg);
+ msg = msgb_copy_c(conn->wrf, conn->file_hdr_msg, "wrf_hdr");
+ OSMO_ASSERT(msg);
rc = osmo_pcap_wr_file_write_msgb(conn->wrf, msg);
if (rc < 0) {
LOGP(DSERVER, LOGL_ERROR, "Failed to write the header: %d\n", errno);
@@ -518,16 +520,17 @@
}
/* New recorded packet is received.
- * Returns 0 on success, negative on error. */
-int osmo_pcap_conn_process_data(struct osmo_pcap_conn *conn, const uint8_t *data, size_t
len)
+ * Returns 0 on success (and owns msgb), negative on error (msgb to be freed by caller).
*/
+int osmo_pcap_conn_process_data(struct osmo_pcap_conn *conn, struct msgb *msg)
{
time_t now = time(NULL);
int rc;
- zmq_send_client_data(conn, data, len);
+ zmq_send_client_data(conn, msgb_data(msg), msgb_length(msg));
if (!conn->store) {
update_last_write(conn, now);
+ msgb_free(msg);
return 0;
}
@@ -537,20 +540,18 @@
}
/* Check if we are past the limit or on a day change. */
- if (!check_restart_pcap_max_size(conn, len))
+ if (!check_restart_pcap_max_size(conn, msgb_length(msg)))
check_restart_pcap_localtime(conn, now);
- /* TODO: get msgb from caller: */
- struct msgb *msg = msgb_alloc_c(conn->wrf, len, "local_iofd_msg");
- memcpy(msgb_put(msg, len), data, len);
-
+ talloc_steal(conn->wrf, msg);
rc = osmo_pcap_wr_file_write_msgb(conn->wrf, msg);
if (rc < 0) {
LOGP(DSERVER, LOGL_ERROR, "%s: Failed writing to file\n", conn->name);
- msgb_free(msg);
+ /* msgb will be freed by caller */
return -1;
}
update_last_write(conn, now);
+ /* msgb is now owned by conn->wrf. */
return 0;
}
diff --git a/src/osmo_server_network.c b/src/osmo_server_network.c
index 5c7a008..da14480 100644
--- a/src/osmo_server_network.c
+++ b/src/osmo_server_network.c
@@ -121,9 +121,29 @@
}
}
-/* returns >0 on success, <= 0 on failure (closes conn) */
-static int rx_link_hdr(struct osmo_pcap_conn *conn, const struct osmo_pcap_data *data)
+/* Updates conn->file_hdr_msg, owns (frees) msg. */
+static void update_conn_file_hdr_msg(struct osmo_pcap_conn *conn, struct msgb *msg)
{
+ /* The msg chunk of memory to hold the hdr data may actually be a lot bigger than
+ * the actual data (len << data_len).
+ * Hence, since we may keep this around for a big time (life of the conn), let's
+ * better keep a reduced memory footprint msgb instead of the original one: */
+ msgb_free(conn->file_hdr_msg);
+ conn->file_hdr_msg = msgb_copy_resize_c(conn, msg, msgb_length(msg),
"conn_file_hdr_msg");
+ OSMO_ASSERT(conn->file_hdr_msg);
+ msgb_free(msg);
+
+ /* pull to l2 is done here at the copy since anyway msgb_copy_resize
+ * cannot shrink available headroom: */
+ msgb_pull_to_l2(conn->file_hdr_msg);
+
+ osmo_pcap_conn_restart_trace(conn);
+}
+
+/* returns >0 on success (msg becomes owned), <= 0 on failure (closes conn) */
+static int rx_link_hdr(struct osmo_pcap_conn *conn, struct msgb *msg)
+{
+ struct osmo_pcap_data *data = (struct osmo_pcap_data *)msg->l1h;
int rc;
rc = osmo_pcap_file_discover_fmt(data->data, data->len, &conn->file_fmt);
@@ -148,19 +168,11 @@
if (conn->store && !conn->wrf) {
/* First received link hdr in conn */
- talloc_free(conn->file_hdr);
- conn->file_hdr = talloc_size(conn, data->len);
- memcpy(conn->file_hdr, data->data, data->len);
- conn->file_hdr_len = data->len;
- osmo_pcap_conn_restart_trace(conn);
- } else if (conn->file_hdr_len != data->len ||
- memcmp(&conn->file_hdr, data->data, data->len) != 0) {
+ update_conn_file_hdr_msg(conn, msg);
+ } else if (msgb_l2len(conn->file_hdr_msg) != msgb_l2len(msg) ||
+ memcmp(msgb_l2(conn->file_hdr_msg), msgb_l2(msg), msgb_l2len(msg)) != 0) {
/* Client changed the link hdr in conn */
- talloc_free(conn->file_hdr);
- conn->file_hdr = talloc_size(conn, data->len);
- memcpy(conn->file_hdr, data->data, data->len);
- conn->file_hdr_len = data->len;
- osmo_pcap_conn_restart_trace(conn);
+ update_conn_file_hdr_msg(conn, msg);
}
return 1;
@@ -247,22 +259,25 @@
}
/* returns >0 on success, <= 0 on failure (closes conn) */
-static int rx_link_data(struct osmo_pcap_conn *conn, const struct osmo_pcap_data *data)
+static int rx_link_data(struct osmo_pcap_conn *conn, struct msgb *msg)
{
int rc;
- if ((rc = validate_link_data(conn, data)) < 0)
+ if ((rc = validate_link_data(conn, (struct osmo_pcap_data *)msg->l1h)) < 0)
return rc;
- if ((rc = osmo_pcap_conn_process_data(conn, &data->data[0], data->len)) <
0)
+ msgb_pull_to_l2(msg);
+ if ((rc = osmo_pcap_conn_process_data(conn, msg)) < 0)
return rc;
return 1;
}
/* Read segment payload, of size data->len.
- * returns >0 on success, <= 0 on failure (closes conn) */
-static int rx_link(struct osmo_pcap_conn *conn, const struct osmo_pcap_data *data)
+ * returns >0 on success, <= 0 on failure (closes conn).
+ * Message is always owned or freed here. */
+static int rx_link(struct osmo_pcap_conn *conn, struct msgb *msg)
{
+ struct osmo_pcap_data *data = (struct osmo_pcap_data *)msg->l1h;
int rc;
/* count the full packet we got */
@@ -275,15 +290,18 @@
switch (data->type) {
case PKT_LINK_HDR:
- rc = rx_link_hdr(conn, data);
+ rc = rx_link_hdr(conn, msg);
break;
case PKT_LINK_DATA:
- rc = rx_link_data(conn, data);
+ rc = rx_link_data(conn, msg);
break;
default:
OSMO_ASSERT(0);
}
+ if (rc <= 0)
+ msgb_free(msg);
+
if (conn->reopen_delayed) {
LOGP(DSERVER, LOGL_INFO, "Reopening log for %s now.\n", conn->name);
osmo_pcap_conn_restart_trace(conn);
@@ -306,60 +324,69 @@
static int tls_read_cb_initial(struct osmo_pcap_conn *conn)
{
int rc;
+ struct msgb *msg = conn->rx_tls_dec_msg;
+ msg->l1h = msgb_data(msg);
+ struct osmo_pcap_data *pdata = (struct osmo_pcap_data *)msg->l1h;
+ size_t pend = sizeof(*pdata) - msgb_length(msg);
- rc = do_read_tls(conn, ((uint8_t *)conn->data) + sizeof(*conn->data) -
conn->pend, conn->pend);
+ OSMO_ASSERT(sizeof(*pdata) > msgb_length(msg));
+
+ rc = do_read_tls(conn, msg->tail, pend);
if (rc <= 0) {
LOGP(DSERVER, LOGL_ERROR,
- "Too short packet. Got %d, wanted %d\n", rc, conn->data->len);
+ "Too short packet. Got %d, wanted %zu\n", rc, pend);
return -1;
}
-
- conn->pend -= rc;
- if (conn->pend < 0) {
+ if (rc > pend) {
LOGP(DSERVER, LOGL_ERROR,
- "Someone got the pending read wrong: %d\n", conn->pend);
+ "Someone got the pending read wrong: %zu\n", pend);
return -1;
}
- if (conn->pend > 0)
+ msgb_put(msg, rc);
+
+ if (pend > rc)
return 1; /* Wait for more data before continuing */
- conn->data->len = ntohs(conn->data->len);
+ pdata->len = ntohs(pdata->len);
- if (conn->data->len > conn->data_max_len) {
+ if (pdata->len + sizeof(*pdata) > conn->data_max_len) {
LOGP(DSERVER, LOGL_ERROR, "Implausible data length: %u > %zu (snaplen
%u)\n",
- conn->data->len, conn->data_max_len, conn->server->max_snaplen);
+ pdata->len, conn->data_max_len, conn->server->max_snaplen);
return -1;
}
conn->state = STATE_DATA;
- conn->pend = conn->data->len;
+ msg->l2h = msg->tail;
return 1;
}
static int tls_read_cb_data(struct osmo_pcap_conn *conn)
{
int rc;
+ struct msgb *msg = conn->rx_tls_dec_msg;
+ struct osmo_pcap_data *pdata = (struct osmo_pcap_data *)msg->l1h;
+ size_t pend = pdata->len - msgb_l2len(msg);
- rc = do_read_tls(conn, &conn->data->data[conn->data->len -
conn->pend], conn->pend);
+ rc = do_read_tls(conn, msg->tail, pend);
if (rc <= 0) {
LOGP(DSERVER, LOGL_ERROR,
- "Too short packet. Got %d, wanted %d\n", rc, conn->data->len);
+ "Too short packet. Got %d, wanted %u\n", rc, pdata->len);
return -1;
}
-
- conn->pend -= rc;
- if (conn->pend < 0) {
+ if (rc > pend) {
LOGP(DSERVER, LOGL_ERROR,
- "Someone got the pending read wrong: %d\n", conn->pend);
+ "Someone got the pending read wrong: %zu\n", pend);
return -1;
}
- if (conn->pend > 0)
+ msgb_put(msg, rc);
+
+ if (pend > rc)
return 1; /* Wait for more data before continuing */
conn->state = STATE_INITIAL;
- conn->pend = sizeof(*conn->data);
+ conn->rx_tls_dec_msg = msgb_alloc_c(conn, conn->data_max_len,
"rx_tls_dec_data");
- return rx_link(conn, conn->data);
+ return rx_link(conn, msg);
}
/* returns >0 on success, <= 0 on failure (closes conn) */
@@ -422,11 +449,15 @@
return 0;
}
- data = (struct osmo_pcap_data *)msgb_data(msg);
+ OSMO_ASSERT(msgb_length(msg) >= sizeof(*data));
+
+ msg->l1h = msgb_data(msg);
+ data = (struct osmo_pcap_data *)msg->l1h;
data->len = osmo_ntohs(data->len);
- rc = rx_link(conn, data);
- msgb_free(msg);
+ msg->l2h = msg->l1h + sizeof(*data);
+
+ rc = rx_link(conn, msg);
if (rc <= 0)
osmo_pcap_conn_close(conn);
return 0;
@@ -485,7 +516,7 @@
}
/* Prepare for first read of segment header: */
conn->state = STATE_INITIAL;
- conn->pend = sizeof(struct osmo_pcap_data);
+ conn->rx_tls_dec_msg = msgb_alloc_c(conn, conn->data_max_len,
"rx_tls_dec_data");
if (!osmo_tls_init_server_session(conn, server)) {
osmo_pcap_conn_close(conn);
return;
--
To view, visit
https://gerrit.osmocom.org/c/osmo-pcap/+/39370?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-pcap
Gerrit-Branch: master
Gerrit-Change-Id: Iae9b9eaec42ad8ec86d1a8144d676115fa057766
Gerrit-Change-Number: 39370
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>