summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--trafgen.84
-rw-r--r--trafgen.c54
-rw-r--r--trafgen/Makefile1
-rw-r--r--trafgen_conf.h2
-rw-r--r--trafgen_dev.c36
-rw-r--r--trafgen_dev.h4
-rw-r--r--trafgen_dump.c258
-rw-r--r--trafgen_dump.h8
-rw-r--r--trafgen_l2.c33
-rw-r--r--trafgen_l3.c21
-rw-r--r--trafgen_parser.y5
-rw-r--r--trafgen_proto.c69
-rw-r--r--trafgen_proto.h7
13 files changed, 460 insertions, 42 deletions
diff --git a/trafgen.8 b/trafgen.8
index 67aaaf9..f720043 100644
--- a/trafgen.8
+++ b/trafgen.8
@@ -74,9 +74,9 @@ It is also possible to specify PCAP file with .pcap extension via -i,--in option
by default packets will be sent at rate considering timestamp from PCAP file which
might be reset via -b/-t options.
.PP
-.SS -o <dev|pcap>, -d <dev|pcap>, --out <dev|pcap>, --dev <dev|pcap>
+.SS -o <dev|.pcap|.cfg>, -d <dev|.pcap|.cfg>, --out <dev|.pcap|.cfg>, --dev <dev|.pcap|.cfg>
Defines the outgoing networking device such as eth0, wlan0 and others or
-a pcap file.
+a *.pcap or *.cfg file. Pcap and configuration files are identified by extension.
.PP
.SS -p, --cpp
Pass the packet configuration to the C preprocessor before reading it into
diff --git a/trafgen.c b/trafgen.c
index 97ac046..9b54399 100644
--- a/trafgen.c
+++ b/trafgen.c
@@ -185,31 +185,31 @@ static void __noreturn help(void)
puts("http://www.netsniff-ng.org\n\n"
"Usage: trafgen [options] [packet]\n"
"Options:\n"
- " -i|-c|--in|--conf <cfg/-> Packet configuration file/stdin\n"
- " -o|-d|--out|--dev <netdev> Networking device i.e., eth0\n"
- " -p|--cpp Run packet config through C preprocessor\n"
- " -D|--define Add macro/define for C preprocessor\n"
- " -J|--jumbo-support Support 64KB super jumbo frames (def: 2048B)\n"
- " -R|--rfraw Inject raw 802.11 frames\n"
- " -s|--smoke-test <ipv4> Probe if machine survived fuzz-tested packet\n"
- " -n|--num <uint> Number of packets until exit (def: 0)\n"
- " -r|--rand Randomize packet selection (def: round robin)\n"
- " -P|--cpus <uint> Specify number of forks(<= CPUs) (def: #CPUs)\n"
- " -t|--gap <time> Set approx. interpacket gap (s/ms/us/ns, def: us)\n"
- " -b|--rate <rate> Send traffic at specified rate (pps/B/kB/MB/GB/kbit/Mbit/Gbit/KiB/MiB/GiB)\n"
- " -S|--ring-size <size> Manually set mmap size (KiB/MiB/GiB)\n"
- " -E|--seed <uint> Manually set srand(3) seed\n"
- " -u|--user <userid> Drop privileges and change to userid\n"
- " -g|--group <groupid> Drop privileges and change to groupid\n"
- " -H|--prio-high Make this high priority process\n"
- " -A|--no-sock-mem Don't tune core socket memory\n"
- " -Q|--notouch-irq Do not touch IRQ CPU affinity of NIC\n"
- " -q|--qdisc-path Enable qdisc kernel path (default off since 3.14)\n"
- " -V|--verbose Be more verbose\n"
- " -C|--no-cpu-stats Do not print CPU time statistics on exit\n"
- " -v|--version Show version and exit\n"
- " -e|--example Show built-in packet config example\n"
- " -h|--help Guess what?!\n\n"
+ " -i|-c|--in|--conf <cfg/-> Packet configuration file/stdin\n"
+ " -o|-d|--out|--dev <netdev|.cfg|.pcap> Networking device or configuration file i.e., eth0\n"
+ " -p|--cpp Run packet config through C preprocessor\n"
+ " -D|--define Add macro/define for C preprocessor\n"
+ " -J|--jumbo-support Support 64KB super jumbo frames (def: 2048B)\n"
+ " -R|--rfraw Inject raw 802.11 frames\n"
+ " -s|--smoke-test <ipv4> Probe if machine survived fuzz-tested packet\n"
+ " -n|--num <uint> Number of packets until exit (def: 0)\n"
+ " -r|--rand Randomize packet selection (def: round robin)\n"
+ " -P|--cpus <uint> Specify number of forks(<= CPUs) (def: #CPUs)\n"
+ " -t|--gap <time> Set approx. interpacket gap (s/ms/us/ns, def: us)\n"
+ " -b|--rate <rate> Send traffic at specified rate (pps/B/kB/MB/GB/kbit/Mbit/Gbit/KiB/MiB/GiB)\n"
+ " -S|--ring-size <size> Manually set mmap size (KiB/MiB/GiB)\n"
+ " -E|--seed <uint> Manually set srand(3) seed\n"
+ " -u|--user <userid> Drop privileges and change to userid\n"
+ " -g|--group <groupid> Drop privileges and change to groupid\n"
+ " -H|--prio-high Make this high priority process\n"
+ " -A|--no-sock-mem Don't tune core socket memory\n"
+ " -Q|--notouch-irq Do not touch IRQ CPU affinity of NIC\n"
+ " -q|--qdisc-path Enable qdisc kernel path (default off since 3.14)\n"
+ " -V|--verbose Be more verbose\n"
+ " -C|--no-cpu-stats Do not print CPU time statistics on exit\n"
+ " -v|--version Show version and exit\n"
+ " -e|--example Show built-in packet config example\n"
+ " -h|--help Guess what?!\n\n"
"Examples:\n"
" trafgen --dev eth0 --conf trafgen.cfg\n"
" trafgen -e | trafgen -i - -o eth0 --cpp -n 1\n"
@@ -1284,8 +1284,8 @@ int main(int argc, char **argv)
protos_init(ctx.dev_out);
- if (shaper_is_set(&ctx.sh) || (ctx.dev_in && dev_io_is_pcap(ctx.dev_in))
- || dev_io_is_pcap(ctx.dev_out)) {
+ if (shaper_is_set(&ctx.sh) || (ctx.dev_in && !dev_io_is_netdev(ctx.dev_in))
+ || !dev_io_is_netdev(ctx.dev_out)) {
prctl(PR_SET_TIMERSLACK, 1UL);
/* Fall back to single core to not mess up correct timing.
diff --git a/trafgen/Makefile b/trafgen/Makefile
index 381f94d..a1bff80 100644
--- a/trafgen/Makefile
+++ b/trafgen/Makefile
@@ -26,6 +26,7 @@ trafgen-objs = xmalloc.o \
pcap_mm.o \
iosched.o \
trafgen_dev.o \
+ trafgen_dump.o \
trafgen_proto.o \
trafgen_l2.o \
trafgen_l3.o \
diff --git a/trafgen_conf.h b/trafgen_conf.h
index 7e922fe..a0bbe43 100644
--- a/trafgen_conf.h
+++ b/trafgen_conf.h
@@ -37,11 +37,13 @@ struct csum16 {
};
struct packet {
+ uint32_t id;
uint8_t *payload;
size_t len;
struct proto_hdr *headers[PROTO_MAX_LAYERS];
size_t headers_count;
struct timespec tstamp;
+ bool is_created;
};
struct packet_dyn {
diff --git a/trafgen_dev.c b/trafgen_dev.c
index d613cce..f65442f 100644
--- a/trafgen_dev.c
+++ b/trafgen_dev.c
@@ -20,6 +20,7 @@
#include "linktype.h"
#include "trafgen_dev.h"
#include "trafgen_conf.h"
+#include "trafgen_dump.h"
static int dev_pcap_open(struct dev_io *dev, const char *name, enum dev_io_mode_t mode)
{
@@ -90,6 +91,7 @@ static struct packet *dev_pcap_read(struct dev_io *dev)
pkt = realloc_packet();
pkt->len = pkt_len;
+ pkt->is_created = true;
pkt->payload = xzmalloc(pkt_len);
memcpy(pkt->payload, buf, pkt_len);
pcap_get_tstamp(&phdr, dev->pcap_magic, &pkt->tstamp);
@@ -97,7 +99,7 @@ static struct packet *dev_pcap_read(struct dev_io *dev)
return pkt;
}
-static int dev_pcap_write(struct dev_io *dev, const struct packet *pkt)
+static int dev_pcap_write(struct dev_io *dev, struct packet *pkt)
{
uint8_t *buf = pkt->payload;
size_t len = pkt->len;
@@ -172,7 +174,7 @@ static int dev_net_open(struct dev_io *dev, const char *name, enum dev_io_mode_t
return 0;
}
-static int dev_net_write(struct dev_io *dev, const struct packet *pkt)
+static int dev_net_write(struct dev_io *dev, struct packet *pkt)
{
struct sockaddr_ll saddr = {
.sll_family = PF_PACKET,
@@ -215,6 +217,31 @@ static const struct dev_io_ops dev_net_ops = {
.close = dev_net_close,
};
+static int dev_cfg_open(struct dev_io *dev, const char *name, enum dev_io_mode_t mode)
+{
+ dev->fd = open_or_die_m(name, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, DEFFILEMODE);
+ return 0;
+}
+
+static int dev_cfg_write(struct dev_io *dev, struct packet *pkt)
+{
+ if (packet_dump_fd(pkt, dev->fd))
+ return -1;
+
+ return pkt->len;
+}
+
+static void dev_cfg_close(struct dev_io *dev)
+{
+ close(dev->fd);
+}
+
+static const struct dev_io_ops dev_cfg_ops = {
+ .open = dev_cfg_open,
+ .write = dev_cfg_write,
+ .close = dev_cfg_close,
+};
+
struct dev_io *dev_io_open(const char *name, enum dev_io_mode_t mode)
{
struct dev_io *dev = xzmalloc(sizeof(struct dev_io));
@@ -222,6 +249,9 @@ struct dev_io *dev_io_open(const char *name, enum dev_io_mode_t mode)
if (strstr(name, ".pcap")) {
dev->name = xstrdup(name);
dev->ops = &dev_pcap_ops;
+ } else if (strstr(name, ".cfg")) {
+ dev->name = xstrdup(name);
+ dev->ops = &dev_cfg_ops;
} else if (device_mtu(name) > 0) {
dev->name = xstrndup(name, IFNAMSIZ);
dev->ops = &dev_net_ops;
@@ -240,7 +270,7 @@ struct dev_io *dev_io_open(const char *name, enum dev_io_mode_t mode)
return dev;
};
-int dev_io_write(struct dev_io *dev, const struct packet *pkt)
+int dev_io_write(struct dev_io *dev, struct packet *pkt)
{
bug_on(!dev);
bug_on(!dev->ops);
diff --git a/trafgen_dev.h b/trafgen_dev.h
index 6708eb8..80086d7 100644
--- a/trafgen_dev.h
+++ b/trafgen_dev.h
@@ -33,14 +33,14 @@ struct dev_io {
struct dev_io_ops {
int(*open) (struct dev_io *dev, const char *name, enum dev_io_mode_t mode);
- int(*write) (struct dev_io *dev, const struct packet *pkt);
+ int(*write) (struct dev_io *dev, struct packet *pkt);
struct packet *(*read) (struct dev_io *dev);
int(*set_link_type) (struct dev_io *dev, int link_type);
void(*close) (struct dev_io *dev);
};
extern struct dev_io *dev_io_open(const char *name, enum dev_io_mode_t mode);
-extern int dev_io_write(struct dev_io *dev, const struct packet *pkt);
+extern int dev_io_write(struct dev_io *dev, struct packet *pkt);
extern struct packet *dev_io_read(struct dev_io *dev);
extern int dev_io_ifindex_get(struct dev_io *dev);
extern int dev_io_fd_get(struct dev_io *dev);
diff --git a/trafgen_dump.c b/trafgen_dump.c
new file mode 100644
index 0000000..ff68e8b
--- /dev/null
+++ b/trafgen_dump.c
@@ -0,0 +1,258 @@
+/*
+ * netsniff-ng - the packet sniffing beast
+ * Subject to the GPL, version 2.
+ */
+
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <net/ethernet.h>
+
+#include "trafgen_l2.h"
+#include "trafgen_l3.h"
+#include "trafgen_l4.h"
+#include "trafgen_proto.h"
+#include "trafgen_dump.h"
+
+#define DUMP(fmt, ...) fprintf((ctx)->file, fmt, ##__VA_ARGS__)
+
+#define PKT_START() DUMP("{\n")
+#define PKT_END() DUMP("}\n")
+
+#define HDR_START(h) DUMP(" %s(", h)
+#define HDR_END(h) DUMP(" ),\n")
+
+#define FIELD_START(fmt, ...) DUMP(fmt",\n", ##__VA_ARGS__)
+#define FIELD_END(fmt, ...) DUMP(" "fmt"\n", ##__VA_ARGS__)
+#define FIELD(fmt, ...) DUMP(" "fmt",\n", ##__VA_ARGS__)
+
+struct dump_ctx {
+ FILE *file;
+};
+
+static int proto_dump_eth(struct dump_ctx *ctx, struct proto_hdr *hdr)
+{
+ uint8_t *mac;
+
+ HDR_START("eth");
+
+ mac = proto_hdr_field_get_bytes(hdr, ETH_DST_ADDR);
+ FIELD_START("da=%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ mac = proto_hdr_field_get_bytes(hdr, ETH_SRC_ADDR);
+ FIELD("sa=%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ FIELD_END("type=0x%x", proto_hdr_field_get_u16(hdr, ETH_TYPE));
+
+ HDR_END();
+ return 0;
+}
+
+static int proto_dump_vlan(struct dump_ctx *ctx, struct proto_hdr *hdr)
+{
+ HDR_START("vlan");
+
+ FIELD_START("id=%d", proto_hdr_field_get_u16(hdr, VLAN_VID));
+ FIELD("pcp=%d", proto_hdr_field_get_u16(hdr, VLAN_PCP));
+ FIELD("dei=%d", proto_hdr_field_get_u16(hdr, VLAN_DEI));
+ FIELD_END("tpid=0x%x", proto_hdr_field_get_u16(hdr, VLAN_TPID));
+
+ HDR_END();
+ return 0;
+}
+
+static int proto_dump_arp(struct dump_ctx *ctx, struct proto_hdr *hdr)
+{
+ char ip_str[INET_ADDRSTRLEN];
+ uint16_t oper;
+ uint8_t *mac;
+ uint32_t ip;
+
+ HDR_START("arp");
+
+ mac = proto_hdr_field_get_bytes(hdr, ARP_SHA);
+ FIELD_START("smac=%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ ip = proto_hdr_field_get_be32(hdr, ARP_SPA);
+ inet_ntop(AF_INET, &ip, ip_str, sizeof(ip_str));
+ FIELD("sip=%s", ip_str);
+
+ mac = proto_hdr_field_get_bytes(hdr, ARP_THA);
+ FIELD("tmac=%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ ip = proto_hdr_field_get_be32(hdr, ARP_TPA);
+ inet_ntop(AF_INET, &ip, ip_str, sizeof(ip_str));
+ FIELD("tip=%s", ip_str);
+
+ oper = proto_hdr_field_get_u16(hdr, ARP_OPER);
+
+ if (oper == ARPOP_REQUEST)
+ FIELD_END("op=request");
+ else if (oper == ARPOP_REPLY)
+ FIELD_END("op=reply");
+ else
+ FIELD_END("op=0x%x", oper);
+
+ HDR_END();
+ return 0;
+}
+
+static int proto_dump_ip4(struct dump_ctx *ctx, struct proto_hdr *hdr)
+{
+ char ip_sa_str[INET_ADDRSTRLEN];
+ char ip_da_str[INET_ADDRSTRLEN];
+ uint32_t ip;
+
+ ip = proto_hdr_field_get_be32(hdr, IP4_SADDR);
+ inet_ntop(AF_INET, &ip, ip_sa_str, sizeof(ip_sa_str));
+
+ ip = proto_hdr_field_get_be32(hdr, IP4_DADDR);
+ inet_ntop(AF_INET, &ip, ip_da_str, sizeof(ip_da_str));
+
+ HDR_START("ip4");
+
+ FIELD_START("ver=0x%x", proto_hdr_field_get_u8(hdr, IP4_VER));
+ FIELD("ihl=0x%x", proto_hdr_field_get_u8(hdr, IP4_IHL));
+ FIELD("dscp=0x%x", proto_hdr_field_get_u8(hdr, IP4_DSCP));
+ FIELD("ecn=0x%x", proto_hdr_field_get_u8(hdr, IP4_ECN));
+ FIELD("tos=0x%x", proto_hdr_field_get_u8(hdr, IP4_TOS));
+ FIELD("len=%d", proto_hdr_field_get_u16(hdr, IP4_LEN));
+ FIELD("id=0x%x", proto_hdr_field_get_u16(hdr, IP4_ID));
+ FIELD("flags=0x%x", proto_hdr_field_get_u16(hdr, IP4_FLAGS));
+ if (proto_hdr_field_get_u16(hdr, IP4_MF))
+ FIELD("mf");
+ if (proto_hdr_field_get_u16(hdr, IP4_DF))
+ FIELD("df");
+ FIELD("frag=0x%x", proto_hdr_field_get_u16(hdr, IP4_FRAG_OFFS));
+ FIELD("ttl=%d", proto_hdr_field_get_u8(hdr, IP4_TTL));
+ FIELD("proto=0x%x", proto_hdr_field_get_u8(hdr, IP4_PROTO));
+ FIELD("csum=0x%x", proto_hdr_field_get_u16(hdr, IP4_CSUM));
+ FIELD("sa=%s", ip_sa_str);
+ FIELD_END("da=%s", ip_da_str);
+
+ HDR_END();
+ return 0;
+}
+
+static int proto_dump_udp(struct dump_ctx *ctx, struct proto_hdr *hdr)
+{
+ HDR_START("udp");
+
+ FIELD_START("dp=%d", proto_hdr_field_get_u16(hdr, UDP_SPORT));
+ FIELD("sp=%d", proto_hdr_field_get_u16(hdr, UDP_DPORT));
+ FIELD("len=%d", proto_hdr_field_get_u16(hdr, UDP_LEN));
+ FIELD_END("csum=0x%x", proto_hdr_field_get_u16(hdr, UDP_CSUM));
+
+ HDR_END();
+ return 0;
+}
+
+static int proto_dump_tcp(struct dump_ctx *ctx, struct proto_hdr *hdr)
+{
+ HDR_START("tcp");
+
+ FIELD_START("dp=%d", proto_hdr_field_get_u16(hdr, TCP_SPORT));
+ FIELD("sp=%d", proto_hdr_field_get_u16(hdr, TCP_DPORT));
+ FIELD("seq=0x%x", proto_hdr_field_get_u32(hdr, TCP_SEQ));
+ FIELD("ackseq=0x%x", proto_hdr_field_get_u32(hdr, TCP_ACK_SEQ));
+ FIELD("hlen=%d", proto_hdr_field_get_u16(hdr, TCP_DOFF));
+ if (proto_hdr_field_get_u16(hdr, TCP_CWR))
+ FIELD("cwr");
+ if (proto_hdr_field_get_u16(hdr, TCP_ECE))
+ FIELD("ecn");
+ if (proto_hdr_field_get_u16(hdr, TCP_URG))
+ FIELD("urg");
+ if (proto_hdr_field_get_u16(hdr, TCP_ACK))
+ FIELD("ack");
+ if (proto_hdr_field_get_u16(hdr, TCP_PSH))
+ FIELD("psh");
+ if (proto_hdr_field_get_u16(hdr, TCP_RST))
+ FIELD("rst");
+ if (proto_hdr_field_get_u16(hdr, TCP_SYN))
+ FIELD("syn");
+ if (proto_hdr_field_get_u16(hdr, TCP_FIN))
+ FIELD("fin");
+ FIELD("win=%d", proto_hdr_field_get_u16(hdr, TCP_WINDOW));
+ FIELD("csum=0x%x", proto_hdr_field_get_u16(hdr, TCP_CSUM));
+ FIELD_END("urgptr=0x%x", proto_hdr_field_get_u16(hdr, TCP_URG_PTR));
+
+ HDR_END();
+ return 0;
+}
+
+static int proto_dump_hdr(struct dump_ctx *ctx, struct proto_hdr *hdr)
+{
+ switch (hdr->ops->id) {
+ case PROTO_ETH:
+ return proto_dump_eth(ctx, hdr);
+ case PROTO_VLAN:
+ return proto_dump_vlan(ctx, hdr);
+ case PROTO_ARP:
+ return proto_dump_arp(ctx, hdr);
+ case PROTO_IP4:
+ return proto_dump_ip4(ctx, hdr);
+ case PROTO_UDP:
+ return proto_dump_udp(ctx, hdr);
+ case PROTO_TCP:
+ return proto_dump_tcp(ctx, hdr);
+ default:
+ return -1;
+ }
+}
+
+int packet_dump_fd(struct packet *pkt, int fd)
+{
+ struct proto_hdr *hdr;
+ enum proto_id pid;
+ struct dump_ctx _ctx;
+ struct dump_ctx *ctx = &_ctx;
+ size_t dump_len = 0;
+ uint32_t i;
+
+ _ctx.file = fdopen(fd, "w");
+ if (!_ctx.file)
+ return -1;
+
+ /* handle case if there is already proto headers */
+ if (pkt->headers_count == 0) {
+ hdr = proto_packet_apply(PROTO_ETH, pkt);
+
+ while ((pid = proto_hdr_get_next_proto(hdr)) != __PROTO_MAX) {
+ if (hdr->pkt_offset + hdr->len >= pkt->len)
+ break;
+
+ hdr = proto_packet_apply(pid, pkt);
+ }
+ }
+
+ PKT_START();
+ for (i = 0; i < pkt->headers_count; i++) {
+ hdr = pkt->headers[i];
+
+ if (proto_dump_hdr(ctx, hdr))
+ break;
+
+ dump_len += hdr->len;
+ }
+
+ /* print rest as a bytes */
+ if (dump_len < pkt->len) {
+ int j = 1;
+
+ DUMP(" ");
+ for (i = dump_len; i < pkt->len; ++i, ++j) {
+ if (j % 15 == 0)
+ DUMP("\n ");
+ DUMP("0x%02x,", pkt->payload[i]);
+ }
+ DUMP("\n");
+ }
+ PKT_END();
+
+ fflush(ctx->file);
+ return 0;
+}
diff --git a/trafgen_dump.h b/trafgen_dump.h
new file mode 100644
index 0000000..860a956
--- /dev/null
+++ b/trafgen_dump.h
@@ -0,0 +1,8 @@
+#ifndef TRAFGEN_DUMP_H
+#define TRAFGEN_DUMP_H
+
+#include "trafgen_conf.h"
+
+extern int packet_dump_fd(struct packet *pkt, int fd);
+
+#endif /* TRAFGEN_DUMP_H */
diff --git a/trafgen_l2.c b/trafgen_l2.c
index 4858c5f..48c6f6f 100644
--- a/trafgen_l2.c
+++ b/trafgen_l2.c
@@ -40,11 +40,37 @@ static uint16_t pid_to_eth(enum proto_id pid)
}
}
+static uint16_t eth_to_pid(uint16_t etype)
+{
+ switch (etype) {
+ case ETH_P_ARP:
+ return PROTO_ARP;
+ case ETH_P_IP:
+ return PROTO_IP4;
+ case ETH_P_IPV6:
+ return PROTO_IP6;
+ case ETH_P_MPLS_UC:
+ return PROTO_MPLS;
+ case ETH_P_8021Q:
+ case ETH_P_8021AD:
+ return PROTO_VLAN;
+ case ETH_P_PAUSE:
+ return PROTO_PAUSE;
+ default:
+ return __PROTO_MAX;
+ }
+}
+
static void eth_set_next_proto(struct proto_hdr *hdr, enum proto_id pid)
{
proto_hdr_field_set_default_be16(hdr, ETH_TYPE, pid_to_eth(pid));
}
+static enum proto_id eth_get_next_proto(struct proto_hdr *hdr)
+{
+ return eth_to_pid(proto_hdr_field_get_u16(hdr, ETH_TYPE));
+}
+
static void eth_header_init(struct proto_hdr *hdr)
{
proto_header_fields_add(hdr, eth_fields, array_size(eth_fields));
@@ -59,6 +85,7 @@ static const struct proto_ops eth_proto_ops = {
.layer = PROTO_L2,
.header_init = eth_header_init,
.set_next_proto = eth_set_next_proto,
+ .get_next_proto = eth_get_next_proto,
};
static struct proto_field pause_fields[] = {
@@ -158,11 +185,17 @@ static void vlan_set_next_proto(struct proto_hdr *hdr, enum proto_id pid)
proto_hdr_field_set_be16(hdr, VLAN_ETYPE, pid_to_eth(pid));
}
+static enum proto_id vlan_get_next_proto(struct proto_hdr *hdr)
+{
+ return eth_to_pid(proto_hdr_field_get_u16(hdr, VLAN_ETYPE));
+}
+
static const struct proto_ops vlan_proto_ops = {
.id = PROTO_VLAN,
.layer = PROTO_L2,
.header_init = vlan_header_init,
.set_next_proto = vlan_set_next_proto,
+ .get_next_proto = vlan_get_next_proto,
};
static struct proto_field arp_fields[] = {
diff --git a/trafgen_l3.c b/trafgen_l3.c
index 48790e5..a3f711d 100644
--- a/trafgen_l3.c
+++ b/trafgen_l3.c
@@ -38,7 +38,7 @@ static void ipv4_header_init(struct proto_hdr *hdr)
struct dev_io *dev = proto_dev_get();
/* In case of tun interface we do not need to create Ethernet header */
- if (dev_io_is_pcap(dev) || device_type(dev_io_name_get(dev)) != ARPHRD_NONE)
+ if (!dev_io_is_netdev(dev) || device_type(dev_io_name_get(dev)) != ARPHRD_NONE)
proto_lower_default_add(hdr, PROTO_ETH);
proto_header_fields_add(hdr, ipv4_fields, array_size(ipv4_fields));
@@ -117,6 +117,24 @@ static void ipv4_set_next_proto(struct proto_hdr *hdr, enum proto_id pid)
proto_hdr_field_set_default_u8(hdr, IP4_PROTO, ip_proto);
}
+static enum proto_id ipv4_get_next_proto(struct proto_hdr *hdr)
+{
+ switch (proto_hdr_field_get_u8(hdr, IP4_PROTO)) {
+ case IPPROTO_IPIP:
+ return PROTO_IP4;
+ case IPPROTO_IPV6:
+ return PROTO_IP6;
+ case IPPROTO_ICMP:
+ return PROTO_ICMP4;
+ case IPPROTO_UDP:
+ return PROTO_UDP;
+ case IPPROTO_TCP:
+ return PROTO_TCP;
+ default:
+ return __PROTO_MAX;
+ }
+}
+
static const struct proto_ops ipv4_proto_ops = {
.id = PROTO_IP4,
.layer = PROTO_L3,
@@ -125,6 +143,7 @@ static const struct proto_ops ipv4_proto_ops = {
.field_changed = ipv4_field_changed,
.packet_finish = ipv4_packet_finish,
.set_next_proto = ipv4_set_next_proto,
+ .get_next_proto = ipv4_get_next_proto,
};
static struct proto_field ipv6_fields[] = {
diff --git a/trafgen_parser.y b/trafgen_parser.y
index 74015b5..38f170a 100644
--- a/trafgen_parser.y
+++ b/trafgen_parser.y
@@ -169,6 +169,8 @@ static inline void __setup_new_csum16(struct csum16 *s, off_t from, off_t to,
struct packet *realloc_packet(void)
{
+ uint32_t i;
+
if (test_ignore())
return NULL;
@@ -185,6 +187,9 @@ struct packet *realloc_packet(void)
__init_new_csum_slot(&packet_dyn[packetd_last]);
__init_new_fields_slot(&packet_dyn[packetd_last]);
+ for (i = 0; i < plen; i++)
+ packets[i].id = i;
+
return &packets[packet_last];
}
diff --git a/trafgen_proto.c b/trafgen_proto.c
index 1d978e3..be2f8f4 100644
--- a/trafgen_proto.c
+++ b/trafgen_proto.c
@@ -35,6 +35,16 @@ struct packet *proto_hdr_packet(struct proto_hdr *hdr)
return packet_get(hdr->pkt_id);
}
+struct proto_hdr *packet_last_header(struct packet *pkt)
+{
+ struct proto_hdr **headers = &pkt->headers[0];
+
+ if (pkt->headers_count == 0)
+ return NULL;
+
+ return headers[pkt->headers_count - 1];
+}
+
struct proto_hdr *proto_lower_header(struct proto_hdr *hdr)
{
struct packet *pkt = packet_get(hdr->pkt_id);
@@ -90,12 +100,18 @@ void proto_header_fields_add(struct proto_hdr *hdr,
struct proto_field *f;
int i;
- if (!hdr->fields)
- hdr->pkt_offset = pkt->len;
+ if (pkt->headers_count > 0) {
+ struct proto_hdr *last = packet_last_header(pkt);
+ bug_on(!last);
+
+ hdr->pkt_offset = last->pkt_offset + last->len;
+ }
proto_fields_realloc(hdr, hdr->fields_count + count);
for (i = 0; count >= 1; count--, i++) {
+ int fill_len;
+
f = &hdr->fields[hdr->fields_count - count];
f->id = fields[i].id;
@@ -109,9 +125,12 @@ void proto_header_fields_add(struct proto_hdr *hdr,
if (!f->len)
continue;
- if (f->pkt_offset + f->len > pkt->len) {
+ fill_len = (f->pkt_offset + f->len) - (hdr->pkt_offset + hdr->len);
+ if (fill_len > 0) {
+ if (!pkt->is_created)
+ set_fill(0, (f->pkt_offset + f->len) - pkt->len);
+
hdr->len += f->len;
- set_fill(0, (f->pkt_offset + f->len) - pkt->len);
}
}
}
@@ -133,9 +152,8 @@ bool proto_hdr_field_is_set(struct proto_hdr *hdr, uint32_t fid)
return field ? field->is_set : false;
}
-struct proto_hdr *proto_header_push(enum proto_id pid)
+struct proto_hdr *proto_packet_apply(enum proto_id pid, struct packet *pkt)
{
- struct packet *pkt = current_packet();
struct proto_hdr **headers = &pkt->headers[0];
const struct proto_ops *ops = proto_ops_by_id(pid);
struct proto_hdr *hdr;
@@ -144,7 +162,7 @@ struct proto_hdr *proto_header_push(enum proto_id pid)
hdr = xzmalloc(sizeof(*hdr));
hdr->ops = ops;
- hdr->pkt_id = current_packet_id();
+ hdr->pkt_id = pkt->id;
if (ops && ops->header_init)
ops->header_init(hdr);
@@ -157,12 +175,25 @@ struct proto_hdr *proto_header_push(enum proto_id pid)
return hdr;
}
+struct proto_hdr *proto_header_push(enum proto_id pid)
+{
+ return proto_packet_apply(pid, current_packet());
+}
+
void proto_header_finish(struct proto_hdr *hdr)
{
if (hdr && hdr->ops && hdr->ops->header_finish)
hdr->ops->header_finish(hdr);
}
+enum proto_id proto_hdr_get_next_proto(struct proto_hdr *hdr)
+{
+ if (hdr->ops && hdr->ops->get_next_proto)
+ return hdr->ops->get_next_proto(hdr);
+
+ return __PROTO_MAX;
+}
+
struct proto_hdr *proto_hdr_push_sub_header(struct proto_hdr *hdr, int id)
{
struct proto_hdr *sub_hdr;
@@ -408,6 +439,13 @@ static uint8_t *__proto_field_get_bytes(struct proto_field *field)
return &packet_get(field->hdr->pkt_id)->payload[field->pkt_offset];
}
+uint8_t *proto_hdr_field_get_bytes(struct proto_hdr *hdr, uint32_t fid)
+{
+ struct proto_field *field = proto_hdr_field_by_id(hdr, fid);
+
+ return __proto_field_get_bytes(field);
+}
+
void proto_hdr_field_set_u8(struct proto_hdr *hdr, uint32_t fid, uint8_t val)
{
proto_hdr_field_set_bytes(hdr, fid, (uint8_t *)&val, 1);
@@ -447,6 +485,14 @@ uint32_t proto_hdr_field_get_u32(struct proto_hdr *hdr, uint32_t fid)
return field_unmask_and_unshift(field, be32_to_cpu(val));
}
+uint32_t proto_hdr_field_get_be32(struct proto_hdr *hdr, uint32_t fid)
+{
+ struct proto_field *field = proto_hdr_field_by_id(hdr, fid);
+ uint32_t val = *(uint32_t *)__proto_field_get_bytes(field);
+
+ return field_unmask_and_unshift(field, val);
+}
+
void proto_hdr_field_set_default_bytes(struct proto_hdr *hdr, uint32_t fid,
const uint8_t *bytes, size_t len)
{
@@ -647,6 +693,13 @@ uint32_t proto_field_get_u32(struct proto_field *field)
return field_unmask_and_unshift(field, be32_to_cpu(val));
}
+uint32_t proto_field_get_be32(struct proto_field *field)
+{
+ uint32_t val = *(uint32_t *)__proto_field_get_bytes(field);
+
+ return field_unmask_and_unshift(field, val);
+}
+
void proto_field_set_be16(struct proto_field *field, uint16_t val)
{
__proto_field_set_bytes(field, (uint8_t *)&val, 2, false, true);
@@ -709,6 +762,8 @@ void proto_packet_finish(void)
if (ops && ops->packet_finish)
ops->packet_finish(hdr);
}
+
+ current_packet()->is_created = true;
}
static inline uint32_t field_inc(struct proto_field *field)
diff --git a/trafgen_proto.h b/trafgen_proto.h
index 36b8f2b..d756aca 100644
--- a/trafgen_proto.h
+++ b/trafgen_proto.h
@@ -49,6 +49,7 @@ struct proto_ops {
void (*packet_finish)(struct proto_hdr *hdr);
void (*packet_update)(struct proto_hdr *hdr);
void (*set_next_proto)(struct proto_hdr *hdr, enum proto_id pid);
+ enum proto_id (*get_next_proto)(struct proto_hdr *hdr);
};
struct proto_hdr {
@@ -101,11 +102,13 @@ struct proto_field {
extern void protos_init(struct dev_io *dev);
extern void proto_ops_register(const struct proto_ops *ops);
+struct proto_hdr *proto_packet_apply(enum proto_id pid, struct packet *pkt);
extern struct proto_hdr *proto_header_push(enum proto_id pid);
extern void proto_header_finish(struct proto_hdr *hdr);
extern void proto_packet_finish(void);
extern void proto_packet_update(uint32_t idx);
+extern enum proto_id proto_hdr_get_next_proto(struct proto_hdr *hdr);
extern struct packet *proto_hdr_packet(struct proto_hdr *hdr);
extern struct proto_hdr *proto_hdr_push_sub_header(struct proto_hdr *hdr, int id);
extern void proto_hdr_move_sub_header(struct proto_hdr *hdr, struct proto_hdr *from,
@@ -114,6 +117,7 @@ extern void proto_hdr_move_sub_header(struct proto_hdr *hdr, struct proto_hdr *f
extern struct proto_hdr *proto_lower_default_add(struct proto_hdr *hdr,
enum proto_id pid);
+extern struct proto_hdr *packet_last_header(struct packet *pkt);
extern struct proto_hdr *proto_lower_header(struct proto_hdr *hdr);
extern struct proto_hdr *proto_upper_header(struct proto_hdr *hdr);
extern uint8_t *proto_header_ptr(struct proto_hdr *hdr);
@@ -123,6 +127,7 @@ extern void proto_header_fields_add(struct proto_hdr *hdr,
size_t count);
extern bool proto_hdr_field_is_set(struct proto_hdr *hdr, uint32_t fid);
+extern uint8_t *proto_hdr_field_get_bytes(struct proto_hdr *hdr, uint32_t fid);
extern void proto_hdr_field_set_bytes(struct proto_hdr *hdr, uint32_t fid,
const uint8_t *bytes, size_t len);
extern void proto_hdr_field_set_u8(struct proto_hdr *hdr, uint32_t fid, uint8_t val);
@@ -131,6 +136,7 @@ extern void proto_hdr_field_set_u16(struct proto_hdr *hdr, uint32_t fid, uint16_
extern uint16_t proto_hdr_field_get_u16(struct proto_hdr *hdr, uint32_t fid);
extern void proto_hdr_field_set_u32(struct proto_hdr *hdr, uint32_t fid, uint32_t val);
extern uint32_t proto_hdr_field_get_u32(struct proto_hdr *hdr, uint32_t fid);
+extern uint32_t proto_hdr_field_get_be32(struct proto_hdr *hdr, uint32_t fid);
extern void proto_hdr_field_set_default_bytes(struct proto_hdr *hdr, uint32_t fid,
const uint8_t *bytes, size_t len);
@@ -172,6 +178,7 @@ extern void proto_field_set_u16(struct proto_field *field, uint16_t val);
extern uint16_t proto_field_get_u16(struct proto_field *field);
extern void proto_field_set_u32(struct proto_field *field, uint32_t val);
extern uint32_t proto_field_get_u32(struct proto_field *field);
+extern uint32_t proto_field_get_be32(struct proto_field *field);
extern void proto_field_set_be16(struct proto_field *field, uint16_t val);
extern void proto_field_set_be32(struct proto_field *field, uint32_t val);
extern void proto_field_set_bytes(struct proto_field *field, const uint8_t *bytes, size_t len);