Skip to content

Commit

Permalink
trafgen: proto: Add ICMPv4 header generation
Browse files Browse the repository at this point in the history
Support for generating ICMPv4 headers using the 'icmp4()/icmpv4()'
trafgen generation functions.

Fields supported:

    type      Set type field (default 0: Echo reply)
              Supported keywords: echorequest, echoreply
    code      Set code field (default 0)
    csum      Set checksum field (calculated by default)
    mtu	      Set mtu field for destination unreachable (default 0)
    seq	      Set sequence field (default 0)
    id        Set identifier field (default 0)
    addr      Set redirect address (default 0.0.0.0)

Example (send ping request):

  { icmpv4(echorequest, seq=1, id=1326) }

Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
[tk: squash commits, consistency between functionality and docu]
Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
  • Loading branch information
vkochan authored and tklauser committed Jul 13, 2016
1 parent e6fcf1f commit 423bb07
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 1 deletion.
40 changes: 40 additions & 0 deletions trafgen.8
Expand Up @@ -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>,
Expand Down
3 changes: 3 additions & 0 deletions trafgen_l3.c
Expand Up @@ -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;
Expand Down
42 changes: 42 additions & 0 deletions trafgen_l4.c
Expand Up @@ -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 },
Expand Down Expand Up @@ -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);
}
10 changes: 10 additions & 0 deletions trafgen_l4.h
Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions trafgen_lexer.l
Expand Up @@ -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; }
Expand Down Expand Up @@ -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; }
Expand Down
41 changes: 40 additions & 1 deletion trafgen_parser.y
Expand Up @@ -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>

Expand Down Expand Up @@ -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 ',' '{' '}' '(' ')' '[' ']' ':' '-' '+' '*' '/' '%' '&' '|' '<' '>' '^'
Expand Down Expand Up @@ -594,6 +597,7 @@ proto
| arp_proto { }
| ip4_proto { }
| ip6_proto { }
| icmp4_proto { }
| icmpv6_proto { }
| udp_proto { }
| tcp_proto { }
Expand Down Expand Up @@ -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 ')' { }

Expand Down
1 change: 1 addition & 0 deletions trafgen_proto.h
Expand Up @@ -16,6 +16,7 @@ enum proto_id {
PROTO_ARP,
PROTO_MPLS,
PROTO_IP4,
PROTO_ICMP4,
PROTO_IP6,
PROTO_ICMP6,
PROTO_UDP,
Expand Down

0 comments on commit 423bb07

Please sign in to comment.