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
This commit is contained in:
parent
cd698095c7
commit
7d6688f9bc
|
@ -108,6 +108,8 @@ void AF__PACKET__PT_PROVIDER::set_parameter(const char *parameter_name, const ch
|
||||||
mNetdev_name = NULL;
|
mNetdev_name = NULL;
|
||||||
}
|
}
|
||||||
mNetdev_name = strdup(parameter_value);
|
mNetdev_name = strdup(parameter_value);
|
||||||
|
} else if (!strcmp(parameter_name, "sleep_on_enobufs")) {
|
||||||
|
mSleepUsOnEnobufs = atoi(parameter_value);
|
||||||
} else
|
} else
|
||||||
TTCN_error("Unsupported test port parameter `%s'.", parameter_name);
|
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)
|
void AF__PACKET__PT_PROVIDER::outgoing_send(const AF__PACKET__Unitdata& send_par)
|
||||||
{
|
{
|
||||||
int rc;
|
|
||||||
|
|
||||||
assert(mSocket >= 0);
|
assert(mSocket >= 0);
|
||||||
|
|
||||||
rc = write(mSocket, send_par.data(), send_par.data().lengthof());
|
while (true) {
|
||||||
if (rc < send_par.data().lengthof())
|
int rc = write(mSocket, send_par.data(), send_par.data().lengthof());
|
||||||
TTCN_error("Short write on AF_PACKET socket: %s", strerror(errno));
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char *mNetdev_name; /* name of the network interface */
|
char *mNetdev_name; /* name of the network interface */
|
||||||
|
int mSleepUsOnEnobufs; /* how many us to sleep on ENOBUFS */
|
||||||
int mIfindex; /* interface index of the network device */
|
int mIfindex; /* interface index of the network device */
|
||||||
int mSocket; /* socket/file descriptor of the AF_PACKET socket */
|
int mSocket; /* socket/file descriptor of the AF_PACKET socket */
|
||||||
uint8_t mRxBuf[2048]; /* read buffer */
|
uint8_t mRxBuf[2048]; /* read buffer */
|
||||||
|
|
Loading…
Reference in New Issue