pcap: Handle short writes in pcap_frame()
Currently pcap_frame() assumes that if write() doesn't return an error, it has written everything we want. That's not necessarily true, because it could return a short write. That's not likely to happen on a regular file, but there's not a lot of reason not to be robust here; it's conceivable we might want to direct the pcap fd at a named pipe or similar. So, make pcap_frame() handle short frames by using the write_remainder() helper. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> [sbrivio: Formatting fix, and avoid gcc warning in pcap_frame()] Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
parent
8bdb0883b4
commit
dda7945ca9
3 changed files with 30 additions and 19 deletions
44
pcap.c
44
pcap.c
|
@ -31,6 +31,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "passt.h"
|
#include "passt.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "pcap.h"
|
||||||
|
|
||||||
#define PCAP_VERSION_MINOR 4
|
#define PCAP_VERSION_MINOR 4
|
||||||
|
|
||||||
|
@ -67,25 +68,32 @@ struct pcap_pkthdr {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pcap_frame() - Capture a single frame to pcap file with given timestamp
|
* pcap_frame() - Capture a single frame to pcap file with given timestamp
|
||||||
* @iov: IO vector referencing buffer containing frame (with L2 headers)
|
* @iov: IO vector containing frame (with L2 headers and tap headers)
|
||||||
* @offset: Offset of the frame from @iov->iov_base
|
* @iovcnt: Number of buffers (@iov entries) in frame
|
||||||
|
* @offset: Byte offset of the L2 headers within @iov
|
||||||
* @tv: Timestamp
|
* @tv: Timestamp
|
||||||
*
|
*
|
||||||
* Returns: 0 on success, -errno on error writing to the file
|
* Returns: 0 on success, -errno on error writing to the file
|
||||||
*/
|
*/
|
||||||
static void pcap_frame(const struct iovec *iov, size_t offset,
|
static void pcap_frame(const struct iovec *iov, size_t iovcnt,
|
||||||
const struct timeval *tv)
|
size_t offset, const struct timeval *tv)
|
||||||
{
|
{
|
||||||
size_t len = iov->iov_len - offset;
|
size_t len = iov->iov_len - offset;
|
||||||
struct pcap_pkthdr h;
|
struct pcap_pkthdr h = {
|
||||||
|
.tv_sec = tv->tv_sec,
|
||||||
|
.tv_usec = tv->tv_usec,
|
||||||
|
.caplen = len,
|
||||||
|
.len = len
|
||||||
|
};
|
||||||
|
struct iovec hiov = { &h, sizeof(h) };
|
||||||
|
|
||||||
h.tv_sec = tv->tv_sec;
|
(void)iovcnt;
|
||||||
h.tv_usec = tv->tv_usec;
|
|
||||||
h.caplen = h.len = len;
|
|
||||||
|
|
||||||
if (write(pcap_fd, &h, sizeof(h)) < 0 ||
|
if (write_remainder(pcap_fd, &hiov, 1, 0) < 0 ||
|
||||||
write(pcap_fd, (char *)iov->iov_base + offset, len) < 0)
|
write_remainder(pcap_fd, iov, 1, offset) < 0) {
|
||||||
debug("Cannot log packet, length %zu", len);
|
debug("Cannot log packet, length %zu: %s",
|
||||||
|
len, strerror(errno));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -102,16 +110,18 @@ void pcap(const char *pkt, size_t len)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
pcap_frame(&iov, 0, &tv);
|
pcap_frame(&iov, 1, 0, &tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pcap_multiple() - Capture multiple frames
|
* pcap_multiple() - Capture multiple frames
|
||||||
* @iov: Array of iovecs, one entry per frame
|
* @iov: IO vector with @frame_parts * @n entries
|
||||||
* @n: Number of frames to capture
|
* @frame_parts: Number of IO vector items for each frame
|
||||||
* @offset: Offset of the frame within each iovec buffer
|
* @n: Number of frames to capture
|
||||||
|
* @offset: Offset of the L2 frame within each iovec buffer
|
||||||
*/
|
*/
|
||||||
void pcap_multiple(const struct iovec *iov, unsigned int n, size_t offset)
|
void pcap_multiple(const struct iovec *iov, size_t frame_parts, unsigned int n,
|
||||||
|
size_t offset)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
@ -122,7 +132,7 @@ void pcap_multiple(const struct iovec *iov, unsigned int n, size_t offset)
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
for (i = 0; i < n; i++)
|
for (i = 0; i < n; i++)
|
||||||
pcap_frame(iov + i, offset, &tv);
|
pcap_frame(iov + i * frame_parts, frame_parts, offset, &tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
3
pcap.h
3
pcap.h
|
@ -7,7 +7,8 @@
|
||||||
#define PCAP_H
|
#define PCAP_H
|
||||||
|
|
||||||
void pcap(const char *pkt, size_t len);
|
void pcap(const char *pkt, size_t len);
|
||||||
void pcap_multiple(const struct iovec *iov, unsigned int n, size_t offset);
|
void pcap_multiple(const struct iovec *iov, size_t frame_parts, unsigned int n,
|
||||||
|
size_t offset);
|
||||||
void pcap_init(struct ctx *c);
|
void pcap_init(struct ctx *c);
|
||||||
|
|
||||||
#endif /* PCAP_H */
|
#endif /* PCAP_H */
|
||||||
|
|
2
tap.c
2
tap.c
|
@ -433,7 +433,7 @@ size_t tap_send_frames(const struct ctx *c, const struct iovec *iov, size_t n)
|
||||||
if (m < n)
|
if (m < n)
|
||||||
debug("tap: failed to send %zu frames of %zu", n - m, n);
|
debug("tap: failed to send %zu frames of %zu", n - m, n);
|
||||||
|
|
||||||
pcap_multiple(iov, m, c->mode == MODE_PASST ? sizeof(uint32_t) : 0);
|
pcap_multiple(iov, 1, n, c->mode == MODE_PASST ? sizeof(uint32_t) : 0);
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue