From 90ef31873c773d02eb7be746e3ec07d511214651 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 29 Jan 2021 20:28:38 +0100 Subject: [PATCH] add module parameter "sleep_on_enobufs" to work around -ENOBUFS AF_PACKET sockets have these incredibly useful semantics in where for both non-blocking and blocking I/O, they will tell you the socket is rwite-able, but then still return -1 and sett errno=ENOBUFS if the current socket buffer / transmit queue is full. All we can do is usleep and retry. The new module parameter, if set to non-zero, determines the number of microseconds we shall sleep before any retry. If set to zero, the existing behavior is preserved: TTCN_error(). Related: SYS#5343 Change-Id: I1608403d94a10ae52c7e1de0f1b02687b048c01e --- src/AF_PACKET_PT.cc | 21 ++++++++++++++++----- src/AF_PACKET_PT.hh | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/AF_PACKET_PT.cc b/src/AF_PACKET_PT.cc index aa2def6..935f47c 100644 --- a/src/AF_PACKET_PT.cc +++ b/src/AF_PACKET_PT.cc @@ -108,6 +108,8 @@ void AF__PACKET__PT_PROVIDER::set_parameter(const char *parameter_name, const ch mNetdev_name = NULL; } mNetdev_name = strdup(parameter_value); + } else if (!strcmp(parameter_name, "sleep_on_enobufs")) { + mSleepUsOnEnobufs = atoi(parameter_value); } else TTCN_error("Unsupported test port parameter `%s'.", parameter_name); } @@ -204,13 +206,22 @@ void AF__PACKET__PT_PROVIDER::user_stop() void AF__PACKET__PT_PROVIDER::outgoing_send(const AF__PACKET__Unitdata& send_par) { - int rc; - assert(mSocket >= 0); - rc = write(mSocket, send_par.data(), send_par.data().lengthof()); - if (rc < send_par.data().lengthof()) - TTCN_error("Short write on AF_PACKET socket: %s", strerror(errno)); + while (true) { + int rc = write(mSocket, send_par.data(), send_par.data().lengthof()); + if (rc == send_par.data().lengthof()) + break; + if (mSleepUsOnEnobufs && rc == -1 && errno == -ENOBUFS) { + /* This is fscking insane. Even select() would tell us the FD + * is write-able, but then we still get -ENOBUFS. The only way + * to do this os to sleep. */ + usleep(mSleepUsOnEnobufs); + } else if (rc < send_par.data().lengthof()) { + TTCN_error("Short write on AF_PACKET socket: %s", strerror(errno)); + break; + } + } } diff --git a/src/AF_PACKET_PT.hh b/src/AF_PACKET_PT.hh index 7f8f6b5..ab3e8c6 100644 --- a/src/AF_PACKET_PT.hh +++ b/src/AF_PACKET_PT.hh @@ -50,6 +50,7 @@ public: private: char *mNetdev_name; /* name of the network interface */ + bool mSleepUsOnEnobufs; /* how many us to sleep on ENOBUFS */ int mIfindex; /* interface index of the network device */ int mSocket; /* socket/file descriptor of the AF_PACKET socket */ uint8_t mRxBuf[2048]; /* read buffer */