summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--trafgen.840
-rw-r--r--trafgen_l3.c3
-rw-r--r--trafgen_l4.c42
-rw-r--r--trafgen_l4.h10
-rw-r--r--trafgen_lexer.l6
-rw-r--r--trafgen_parser.y41
-rw-r--r--trafgen_proto.h1
7 files changed, 142 insertions, 1 deletions
diff --git a/trafgen.8 b/trafgen.8
index b011276..c958794 100644
--- a/trafgen.8
+++ b/trafgen.8
@@ -498,6 +498,46 @@ By default, if the lower level header is Ethernet, its EtherType field is set to
By default, if the lower level header is Ethernet, its EtherType field is set to
0x86DD (IPv6).
+.I ICMPv4
+:
+.B icmp4|icmpv4(type=<number>, code=<number>, echorequest, echoreply,
+.B csum=<number>, mtu=<number>, seq=<number>, id=<number>, addr=<ip4_addr>)
+.sp
+.in +4
+.B type
+- Message type (default: 0 - Echo reply)
+.sp
+.B code
+- Message code (default: 0)
+.sp
+.B echorequest
+- ICMPv4 echo (ping) request (type: 8, code: 0)
+.sp
+.B echoreply
+- ICMPv4 echo (ping) reply (type: 0, code: 0)
+.sp
+.B csum
+- Checksum of ICMPv4 header and payload (calculated by default)
+.sp
+.B mtu
+- Next-hop MTU field used in 'Datagram is too big' message type (default; 0)
+.sp
+.B seq
+- Sequence number used in Echo/Timestamp/Address mask messages (default: 0)
+.sp
+.B id
+- Identifier used in Echo/Timestamp/Address mask messages (default: 0)
+.sp
+.B addr
+- IPv4 address used in Redirect messages (default: 0.0.0.0)
+.sp
+.in -4
+Example ICMP echo request (ping):
+.in +4
+.sp
+{ icmpv4(echorequest, seq=1, id=1326) }
+.in -4
+
.I ICMPv6
:
.B icmp6|icmpv6(type=<number>, echorequest, echoreply, code=<number>,
diff --git a/trafgen_l3.c b/trafgen_l3.c
index cbdbe6c..ae3f136 100644
--- a/trafgen_l3.c
+++ b/trafgen_l3.c
@@ -69,6 +69,9 @@ static void ipv4_set_next_proto(struct proto_hdr *hdr, enum proto_id pid)
case PROTO_IP4:
ip_proto = IPPROTO_IPIP;
break;
+ case PROTO_ICMP4:
+ ip_proto = IPPROTO_ICMP;
+ break;
case PROTO_UDP:
ip_proto = IPPROTO_UDP;
break;
diff --git a/trafgen_l4.c b/trafgen_l4.c
index 886e2b2..c109675 100644
--- a/trafgen_l4.c
+++ b/trafgen_l4.c
@@ -138,6 +138,47 @@ static struct proto_hdr tcp_hdr = {
.packet_finish = tcp_packet_finish,
};
+static struct proto_field icmpv4_fields[] = {
+ { .id = ICMPV4_TYPE, .len = 1, .offset = 0 },
+ { .id = ICMPV4_CODE, .len = 1, .offset = 1 },
+ { .id = ICMPV4_CSUM, .len = 2, .offset = 2 },
+ /* Echo/Ping fields */
+ { .id = ICMPV4_ID, .len = 2, .offset = 4 },
+ { .id = ICMPV4_SEQ, .len = 2, .offset = 6 },
+ /* Redirect field */
+ { .id = ICMPV4_REDIR_ADDR, .len = 4, .offset = 4 },
+ /* Next-hop MTU */
+ { .id = ICMPV4_MTU, .len = 2, .offset = 6 },
+};
+
+static void icmpv4_header_init(struct proto_hdr *hdr)
+{
+ proto_lower_default_add(hdr, PROTO_IP4);
+
+ proto_header_fields_add(hdr, icmpv4_fields, array_size(icmpv4_fields));
+}
+
+static void icmpv4_packet_finish(struct proto_hdr *hdr)
+{
+ struct packet *pkt;
+ uint16_t csum;
+
+ if (proto_field_is_set(hdr, ICMPV4_CSUM))
+ return;
+
+ pkt = current_packet();
+
+ csum = htons(calc_csum(proto_header_ptr(hdr), pkt->len - hdr->pkt_offset));
+ proto_field_set_u16(hdr, ICMPV4_CSUM, bswap_16(csum));
+}
+
+static struct proto_hdr icmpv4_hdr = {
+ .id = PROTO_ICMP4,
+ .layer = PROTO_L4,
+ .header_init = icmpv4_header_init,
+ .packet_finish = icmpv4_packet_finish,
+};
+
static struct proto_field icmpv6_fields[] = {
{ .id = ICMPV6_TYPE, .len = 1, .offset = 0 },
{ .id = ICMPV6_CODE, .len = 1, .offset = 1 },
@@ -190,5 +231,6 @@ void protos_l4_init(void)
{
proto_header_register(&udp_hdr);
proto_header_register(&tcp_hdr);
+ proto_header_register(&icmpv4_hdr);
proto_header_register(&icmpv6_hdr);
}
diff --git a/trafgen_l4.h b/trafgen_l4.h
index e94ff23..9537cbf 100644
--- a/trafgen_l4.h
+++ b/trafgen_l4.h
@@ -27,6 +27,16 @@ enum tcp_field {
TCP_URG_PTR,
};
+enum icmpv4_field {
+ ICMPV4_TYPE,
+ ICMPV4_CODE,
+ ICMPV4_CSUM,
+ ICMPV4_ID,
+ ICMPV4_SEQ,
+ ICMPV4_REDIR_ADDR,
+ ICMPV4_MTU,
+};
+
enum icmpv6_field {
ICMPV6_TYPE,
ICMPV6_CODE,
diff --git a/trafgen_lexer.l b/trafgen_lexer.l
index 87db504..5873eec 100644
--- a/trafgen_lexer.l
+++ b/trafgen_lexer.l
@@ -162,6 +162,11 @@ ip6_addr (({a_hex}?:)?({a_hex}?:)?({a_hex}?:)?({a_hex}?:)?({a_hex}?:)?({a_hex}?:
"nh"|"nexthdr" { return K_NEXT_HDR; }
"hl"|"hoplimit" { return K_HOP_LIMIT; }
+
+ /* ICMPv4 */
+"addr" { return K_ADDR; }
+"mtu" { return K_MTU; }
+
/* ICMPv6 */
"code" { return K_CODE; }
"echorequest" { return K_ECHO_REQUEST; }
@@ -192,6 +197,7 @@ ip6_addr (({a_hex}?:)?({a_hex}?:)?({a_hex}?:)?({a_hex}?:)?({a_hex}?:)?({a_hex}?:
"arp" { return K_ARP; }
"ip4"|"ipv4" { return K_IP4; }
"ip6"|"ipv6" { return K_IP6; }
+"icmp4"|"icmpv4" { return K_ICMP4; }
"icmp6"|"icmpv6" { return K_ICMP6; }
"udp" { return K_UDP; }
"tcp" { return K_TCP; }
diff --git a/trafgen_parser.y b/trafgen_parser.y
index adb7f5e..0fe8674 100644
--- a/trafgen_parser.y
+++ b/trafgen_parser.y
@@ -19,6 +19,7 @@
#include <libgen.h>
#include <net/if_arp.h>
#include <netinet/in.h>
+#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/icmpv6.h>
@@ -362,11 +363,13 @@ static void proto_add(enum proto_id pid)
%token K_TPID K_TCI K_PCP K_DEI K_1Q K_1AD
%token K_LABEL K_TC K_LAST K_EXP
+%token K_ADDR K_MTU
+
%token K_ETH
%token K_VLAN K_MPLS
%token K_ARP
%token K_IP4 K_IP6
-%token K_ICMP6
+%token K_ICMP4 K_ICMP6
%token K_UDP K_TCP
%token ',' '{' '}' '(' ')' '[' ']' ':' '-' '+' '*' '/' '%' '&' '|' '<' '>' '^'
@@ -594,6 +597,7 @@ proto
| arp_proto { }
| ip4_proto { }
| ip6_proto { }
+ | icmp4_proto { }
| icmpv6_proto { }
| udp_proto { }
| tcp_proto { }
@@ -817,6 +821,41 @@ ip6
: K_IP6 { proto_add(PROTO_IP6); }
;
+icmp4_proto
+ : icmp4 '(' icmp4_param_list ')' { }
+ ;
+
+icmp4_param_list
+ : { }
+ | icmp4_field { }
+ | icmp4_field delimiter icmp4_param_list { }
+ ;
+
+icmp4_field
+ : K_TYPE skip_white '=' skip_white number
+ { proto_field_set_u8(hdr, ICMPV4_TYPE, $5); }
+ | K_CODE skip_white '=' skip_white number
+ { proto_field_set_u8(hdr, ICMPV4_CODE, $5); }
+ | K_ID skip_white '=' skip_white number
+ { proto_field_set_be16(hdr, ICMPV4_ID, $5); }
+ | K_SEQ skip_white '=' skip_white number
+ { proto_field_set_be16(hdr, ICMPV4_SEQ, $5); }
+ | K_MTU skip_white '=' skip_white number
+ { proto_field_set_be16(hdr, ICMPV4_MTU, $5); }
+ | K_ADDR skip_white '=' skip_white ip4_addr
+ { proto_field_set_u32(hdr, ICMPV4_REDIR_ADDR, $5.s_addr); }
+ | K_ECHO_REQUEST
+ { proto_field_set_u8(hdr, ICMPV4_TYPE, ICMP_ECHO);
+ proto_field_set_u8(hdr, ICMPV4_CODE, 0); }
+ | K_ECHO_REPLY
+ { proto_field_set_u8(hdr, ICMPV4_TYPE, ICMP_ECHOREPLY);
+ proto_field_set_u8(hdr, ICMPV4_CODE, 0); }
+ ;
+
+icmp4
+ : K_ICMP4 { proto_add(PROTO_ICMP4); }
+ ;
+
icmpv6_proto
: icmp6 '(' icmp6_param_list ')' { }
diff --git a/trafgen_proto.h b/trafgen_proto.h
index 5528704..822d841 100644
--- a/trafgen_proto.h
+++ b/trafgen_proto.h
@@ -16,6 +16,7 @@ enum proto_id {
PROTO_ARP,
PROTO_MPLS,
PROTO_IP4,
+ PROTO_ICMP4,
PROTO_IP6,
PROTO_ICMP6,
PROTO_UDP,