mirror of
https://github.com/openvswitch/ovs
synced 2025-09-05 08:45:23 +00:00
pcap-file: Add support for Linux SLL formatted PCAP files.
Someone sent me one of these and OVS couldn't read it. This fixes the problem. Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
@@ -39,9 +39,15 @@ enum ts_resolution {
|
||||
PCAP_NSEC,
|
||||
};
|
||||
|
||||
enum network_type {
|
||||
PCAP_ETHERNET = 0,
|
||||
PCAP_LINUX_SLL = 0x71
|
||||
};
|
||||
|
||||
struct pcap_file {
|
||||
FILE *file;
|
||||
enum ts_resolution resolution;
|
||||
enum network_type network;
|
||||
};
|
||||
|
||||
struct pcap_hdr {
|
||||
@@ -130,10 +136,13 @@ ovs_pcap_read_header(struct pcap_file *p_file)
|
||||
VLOG_WARN("failed to read pcap header: %s", ovs_retval_to_string(error));
|
||||
return error;
|
||||
}
|
||||
bool byte_swap;
|
||||
if (ph.magic_number == 0xa1b2c3d4 || ph.magic_number == 0xd4c3b2a1) {
|
||||
byte_swap = ph.magic_number == 0xd4c3b2a1;
|
||||
p_file->resolution = PCAP_USEC;
|
||||
} else if (ph.magic_number == 0xa1b23c4d ||
|
||||
ph.magic_number == 0x4d3cb2a1) {
|
||||
byte_swap = ph.magic_number == 0x4d3cb2a1;
|
||||
p_file->resolution = PCAP_NSEC;
|
||||
} else {
|
||||
VLOG_WARN("bad magic 0x%08"PRIx32" reading pcap file "
|
||||
@@ -141,6 +150,13 @@ ovs_pcap_read_header(struct pcap_file *p_file)
|
||||
"or 0x4d3cb2a1)", ph.magic_number);
|
||||
return EPROTO;
|
||||
}
|
||||
p_file->network = byte_swap ? uint32_byteswap(ph.network) : ph.network;
|
||||
if (p_file->network != PCAP_ETHERNET &&
|
||||
p_file->network != PCAP_LINUX_SLL) {
|
||||
VLOG_WARN("unknown network type %"PRIu16" reading pcap file",
|
||||
p_file->network);
|
||||
return EPROTO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -218,6 +234,44 @@ ovs_pcap_read(struct pcap_file *p_file, struct dp_packet **bufp,
|
||||
dp_packet_delete(buf);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (p_file->network == PCAP_LINUX_SLL) {
|
||||
/* This format doesn't include the destination Ethernet address, which
|
||||
* is weird. */
|
||||
|
||||
struct sll_header {
|
||||
ovs_be16 packet_type;
|
||||
ovs_be16 arp_hrd;
|
||||
ovs_be16 lla_len;
|
||||
struct eth_addr dl_src;
|
||||
ovs_be16 reserved;
|
||||
ovs_be16 protocol;
|
||||
};
|
||||
const struct sll_header *sll;
|
||||
if (len < sizeof *sll) {
|
||||
VLOG_WARN("pcap packet too short for SLL header");
|
||||
dp_packet_delete(buf);
|
||||
return EPROTO;
|
||||
}
|
||||
|
||||
/* Pull Linux SLL header. */
|
||||
sll = dp_packet_pull(buf, sizeof *sll);
|
||||
if (sll->lla_len != htons(6)) {
|
||||
ovs_hex_dump(stdout, sll, sizeof *sll, 0, false);
|
||||
VLOG_WARN("bad SLL header");
|
||||
dp_packet_delete(buf);
|
||||
return EPROTO;
|
||||
}
|
||||
|
||||
/* Push Ethernet header. */
|
||||
struct eth_header eth = {
|
||||
/* eth_dst is all zeros because the format doesn't include it. */
|
||||
.eth_src = sll->dl_src,
|
||||
.eth_type = sll->protocol,
|
||||
};
|
||||
dp_packet_push(buf, ð, sizeof eth);
|
||||
}
|
||||
|
||||
*bufp = buf;
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user