trafgen: proto: Allow to set field with variable length
[netsniff-ng.git] / trafgen_parser.y
blobb4eedea139e60838f9b76725aea58599745d15b5
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
5 * Swiss federal institute of technology (ETH Zurich)
6 * Subject to the GPL, version 2.
7 */
9 /* yacc-func-prefix: yy */
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdint.h>
16 #include <stdbool.h>
17 #include <errno.h>
18 #include <libgen.h>
19 #include <signal.h>
20 #include <unistd.h>
21 #include <net/if_arp.h>
22 #include <netinet/in.h>
23 #include <linux/icmp.h>
24 #include <linux/if_ether.h>
25 #include <linux/icmpv6.h>
27 #include "xmalloc.h"
28 #include "trafgen_parser.tab.h"
29 #include "trafgen_conf.h"
30 #include "trafgen_proto.h"
31 #include "trafgen_l2.h"
32 #include "trafgen_l3.h"
33 #include "trafgen_l4.h"
34 #include "built_in.h"
35 #include "die.h"
36 #include "str.h"
37 #include "csum.h"
38 #include "cpp.h"
40 #ifndef ETH_P_8021AD
41 #define ETH_P_8021AD 0x88A8
42 #endif
44 #define YYERROR_VERBOSE 0
45 #define YYDEBUG 0
46 #define YYLTYPE_IS_TRIVIAL 1
48 extern FILE *yyin;
49 extern int yylex(void);
50 extern void yy_scan_string(char *);
51 extern void yylex_destroy();
52 extern void yyerror(const char *);
53 extern int yylineno;
54 extern char *yytext;
56 extern struct packet *packets;
57 extern size_t plen;
59 #define packet_last (plen - 1)
61 #define payload_last (packets[packet_last].len - 1)
63 extern struct packet_dyn *packet_dyn;
64 extern size_t dlen;
66 #define packetd_last (dlen - 1)
68 #define packetdc_last (packet_dyn[packetd_last].clen - 1)
69 #define packetdr_last (packet_dyn[packetd_last].rlen - 1)
70 #define packetds_last (packet_dyn[packetd_last].slen - 1)
72 static int our_cpu, min_cpu = -1, max_cpu = -1;
74 enum field_expr_type_t {
75 FIELD_EXPR_UNKNOWN = 0,
76 FIELD_EXPR_NUMB = 1 << 0,
77 FIELD_EXPR_MAC = 1 << 1,
78 FIELD_EXPR_IP4_ADDR = 1 << 2,
79 FIELD_EXPR_IP6_ADDR = 1 << 3,
80 FIELD_EXPR_INC = 1 << 4,
81 FIELD_EXPR_RND = 1 << 5,
82 FIELD_EXPR_OFFSET = 1 << 6,
85 struct proto_field_expr {
86 enum field_expr_type_t type;
87 struct proto_field *field;
89 union {
90 struct in_addr ip4_addr;
91 struct in6_addr ip6_addr;
92 long long int number;
93 uint8_t mac[256];
94 struct proto_field_func func;
95 } val;
98 static struct proto_field_expr field_expr;
99 static struct proto_hdr *hdr;
101 static inline int test_ignore(void)
103 if (min_cpu < 0 && max_cpu < 0)
104 return 0;
105 else if (max_cpu >= our_cpu && min_cpu <= our_cpu)
106 return 0;
107 else
108 return 1;
111 static inline void __init_new_packet_slot(struct packet *slot)
113 memset(slot, 0, sizeof(*slot));
116 static inline void __init_new_counter_slot(struct packet_dyn *slot)
118 slot->cnt = NULL;
119 slot->clen = 0;
122 static inline void __init_new_randomizer_slot(struct packet_dyn *slot)
124 slot->rnd = NULL;
125 slot->rlen = 0;
128 static inline void __init_new_csum_slot(struct packet_dyn *slot)
130 slot->csum = NULL;
131 slot->slen = 0;
134 static inline void __init_new_fields_slot(struct packet_dyn *slot)
136 slot->fields = NULL;
137 slot->flen = 0;
140 static inline void __setup_new_counter(struct counter *c, uint8_t start,
141 uint8_t stop, uint8_t stepping,
142 int type)
144 c->min = start;
145 c->max = stop;
146 c->inc = stepping;
147 c->val = (type == TYPE_INC) ? start : stop;
148 c->off = payload_last;
149 c->type = type;
152 static inline void __setup_new_randomizer(struct randomizer *r)
154 r->off = payload_last;
157 static inline void __setup_new_csum16(struct csum16 *s, off_t from, off_t to,
158 enum csum which)
160 s->off = payload_last - 1;
161 s->from = from;
162 s->to = to;
163 s->which = which;
166 void realloc_packet(void)
168 if (test_ignore())
169 return;
171 plen++;
172 packets = xrealloc(packets, plen * sizeof(*packets));
174 __init_new_packet_slot(&packets[packet_last]);
176 dlen++;
177 packet_dyn = xrealloc(packet_dyn, dlen * sizeof(*packet_dyn));
179 __init_new_counter_slot(&packet_dyn[packetd_last]);
180 __init_new_randomizer_slot(&packet_dyn[packetd_last]);
181 __init_new_csum_slot(&packet_dyn[packetd_last]);
182 __init_new_fields_slot(&packet_dyn[packetd_last]);
185 struct packet *current_packet(void)
187 return &packets[packet_last];
190 uint32_t current_packet_id(void)
192 return packet_last;
195 struct packet *packet_get(uint32_t id)
197 return &packets[id];
200 static void set_byte(uint8_t val)
202 struct packet *pkt = &packets[packet_last];
204 if (test_ignore())
205 return;
207 pkt->len++;
208 pkt->payload = xrealloc(pkt->payload, pkt->len);
209 pkt->payload[payload_last] = val;
212 static void set_multi_byte(uint8_t *s, size_t len)
214 size_t i;
216 for (i = 0; i < len; ++i)
217 set_byte(s[i]);
220 void set_fill(uint8_t val, size_t len)
222 size_t i;
223 struct packet *pkt = &packets[packet_last];
225 if (test_ignore())
226 return;
228 pkt->len += len;
229 pkt->payload = xrealloc(pkt->payload, pkt->len);
230 for (i = 0; i < len; ++i)
231 pkt->payload[payload_last - i] = val;
234 static void __set_csum16_dynamic(size_t from, size_t to, enum csum which)
236 struct packet *pkt = &packets[packet_last];
237 struct packet_dyn *pktd = &packet_dyn[packetd_last];
239 pkt->len += 2;
240 pkt->payload = xrealloc(pkt->payload, pkt->len);
242 pktd->slen++;
243 pktd->csum = xrealloc(pktd->csum, pktd->slen * sizeof(struct csum16));
245 __setup_new_csum16(&pktd->csum[packetds_last], from, to, which);
248 static void __set_csum16_static(size_t from, size_t to, enum csum which __maybe_unused)
250 struct packet *pkt = &packets[packet_last];
251 uint16_t sum;
252 uint8_t *psum;
254 sum = htons(calc_csum(pkt->payload + from, to - from));
255 psum = (uint8_t *) &sum;
257 set_byte(psum[0]);
258 set_byte(psum[1]);
261 static inline bool is_dynamic_csum(enum csum which)
263 switch (which) {
264 case CSUM_UDP:
265 case CSUM_TCP:
266 case CSUM_UDP6:
267 case CSUM_TCP6:
268 return true;
269 default:
270 return false;
274 static void set_csum16(size_t from, size_t to, enum csum which)
276 struct packet *pkt = &packets[packet_last];
277 struct packet_dyn *pktd = &packet_dyn[packetd_last];
279 if (test_ignore())
280 return;
282 if (to < from) {
283 size_t tmp = to;
285 to = from;
286 from = tmp;
289 bug_on(!(from < to));
291 if (packet_dyn_has_elems(pktd) || to >= pkt->len || is_dynamic_csum(which))
292 __set_csum16_dynamic(from, to, which);
293 else
294 __set_csum16_static(from, to, which);
297 static void set_rnd(size_t len)
299 size_t i;
300 struct packet *pkt = &packets[packet_last];
302 if (test_ignore())
303 return;
305 pkt->len += len;
306 pkt->payload = xrealloc(pkt->payload, pkt->len);
307 for (i = 0; i < len; ++i)
308 pkt->payload[payload_last - i] = (uint8_t) rand();
311 static void set_sequential_inc(uint8_t start, size_t len, uint8_t stepping)
313 size_t i;
314 struct packet *pkt = &packets[packet_last];
316 if (test_ignore())
317 return;
319 pkt->len += len;
320 pkt->payload = xrealloc(pkt->payload, pkt->len);
321 for (i = 0; i < len; ++i) {
322 off_t off = len - 1 - i;
324 pkt->payload[payload_last - off] = start;
325 start += stepping;
329 static void set_sequential_dec(uint8_t start, size_t len, uint8_t stepping)
331 size_t i;
332 struct packet *pkt = &packets[packet_last];
334 if (test_ignore())
335 return;
337 pkt->len += len;
338 pkt->payload = xrealloc(pkt->payload, pkt->len);
339 for (i = 0; i < len; ++i) {
340 int off = len - 1 - i;
342 pkt->payload[payload_last - off] = start;
343 start -= stepping;
347 static void set_dynamic_rnd(void)
349 struct packet *pkt = &packets[packet_last];
350 struct packet_dyn *pktd = &packet_dyn[packetd_last];
352 if (test_ignore())
353 return;
355 pkt->len++;
356 pkt->payload = xrealloc(pkt->payload, pkt->len);
358 pktd->rlen++;
359 pktd->rnd = xrealloc(pktd->rnd, pktd->rlen * sizeof(struct randomizer));
361 __setup_new_randomizer(&pktd->rnd[packetdr_last]);
364 static void set_dynamic_incdec(uint8_t start, uint8_t stop, uint8_t stepping,
365 int type)
367 struct packet *pkt = &packets[packet_last];
368 struct packet_dyn *pktd = &packet_dyn[packetd_last];
370 if (test_ignore())
371 return;
373 pkt->len++;
374 pkt->payload = xrealloc(pkt->payload, pkt->len);
376 pktd->clen++;
377 pktd->cnt = xrealloc(pktd->cnt, pktd->clen * sizeof(struct counter));
379 __setup_new_counter(&pktd->cnt[packetdc_last], start, stop, stepping, type);
382 static void proto_add(enum proto_id pid)
384 hdr = proto_header_push(pid);
387 static void proto_field_set(uint32_t fid)
389 memset(&field_expr, 0, sizeof(field_expr));
390 field_expr.field = proto_hdr_field_by_id(hdr, fid);
393 static void proto_field_func_setup(struct proto_field *field, struct proto_field_func *func)
395 struct proto_field *field_copy;
396 struct packet_dyn *pkt_dyn;
398 field_copy = xmalloc(sizeof(*field));
399 memcpy(field_copy, field, sizeof(*field));
401 field_copy->pkt_offset += func->offset;
402 if (func->len)
403 field_copy->len = func->len;
405 proto_field_func_add(field_copy, func);
407 pkt_dyn = &packet_dyn[packetd_last];
408 pkt_dyn->flen++;
409 pkt_dyn->fields = xrealloc(pkt_dyn->fields, pkt_dyn->flen *
410 sizeof(struct proto_field *));
412 pkt_dyn->fields[pkt_dyn->flen - 1] = field_copy;
415 static void proto_field_expr_eval(void)
417 struct proto_field *field = field_expr.field;
419 if ((field_expr.type & FIELD_EXPR_OFFSET) &&
420 !((field_expr.type & FIELD_EXPR_INC) ||
421 (field_expr.type & FIELD_EXPR_RND))) {
423 panic("Field offset expression is valid only with function expression\n");
426 if (field_expr.type & FIELD_EXPR_NUMB) {
427 if (field->len == 1)
428 proto_field_set_u8(field, field_expr.val.number);
429 else if (field->len == 2)
430 proto_field_set_be16(field, field_expr.val.number);
431 else if (field->len == 4)
432 proto_field_set_be32(field, field_expr.val.number);
433 else
434 panic("Invalid value length %zu, can be 1,2 or 4\n", field->len);
435 } else if (field_expr.type & FIELD_EXPR_MAC) {
436 proto_field_set_bytes(field, field_expr.val.mac, 6);
437 } else if (field_expr.type & FIELD_EXPR_IP4_ADDR) {
438 proto_field_set_u32(field, field_expr.val.ip4_addr.s_addr);
439 } else if (field_expr.type & FIELD_EXPR_IP6_ADDR) {
440 proto_field_set_bytes(field, (uint8_t *)&field_expr.val.ip6_addr.s6_addr, 16);
441 } else if ((field_expr.type & FIELD_EXPR_INC) ||
442 (field_expr.type & FIELD_EXPR_RND)) {
444 if (field_expr.val.func.min
445 && field_expr.val.func.min >= field_expr.val.func.max)
446 panic("dinc(): min(%u) can't be >= max(%u)\n",
447 field_expr.val.func.min, field_expr.val.func.max);
449 proto_field_func_setup(field, &field_expr.val.func);
450 } else if ((field_expr.type & FIELD_EXPR_OFFSET) &&
451 !((field_expr.type & FIELD_EXPR_INC) ||
452 (field_expr.type & FIELD_EXPR_RND))) {
454 panic("Field expression is valid only for function value expression\n");
455 } else {
456 bug();
459 memset(&field_expr, 0, sizeof(field_expr));
462 static void field_index_validate(struct proto_field *field, uint16_t index, size_t len)
464 if (field_expr.field->len <= index) {
465 yyerror("Invalid [index] parameter");
466 panic("Index (%u) is bigger than field's length (%zu)\n",
467 index, field->len);
469 if (len != 1 && len != 2 && len != 4) {
470 yyerror("Invalid [index:len] parameter");
471 panic("Invalid index length - 1,2 or 4 is only allowed\n");
477 %union {
478 struct in_addr ip4_addr;
479 struct in6_addr ip6_addr;
480 long long int number;
481 uint8_t mac[6];
482 char *str;
485 %token K_COMMENT K_FILL K_RND K_SEQINC K_SEQDEC K_DRND K_DINC K_DDEC K_WHITE
486 %token K_CPU K_CSUMIP K_CSUMUDP K_CSUMTCP K_CSUMUDP6 K_CSUMTCP6 K_CONST8 K_CONST16 K_CONST32 K_CONST64
488 %token K_DADDR K_SADDR K_ETYPE K_TYPE
489 %token K_TIME K_PRIO
490 %token K_OPER K_SHA K_SPA K_THA K_TPA K_REQUEST K_REPLY K_PTYPE K_HTYPE
491 %token K_PROT K_TTL K_DSCP K_ECN K_TOS K_LEN K_ID K_FLAGS K_FRAG K_IHL K_VER K_CSUM K_DF K_MF
492 %token K_FLOW K_NEXT_HDR K_HOP_LIMIT
493 %token K_CODE K_ECHO_REQUEST K_ECHO_REPLY
494 %token K_SPORT K_DPORT
495 %token K_SEQ K_ACK_SEQ K_DOFF K_CWR K_ECE K_URG K_ACK K_PSH K_RST K_SYN K_FIN K_WINDOW K_URG_PTR
496 %token K_TPID K_TCI K_PCP K_DEI K_1Q K_1AD
497 %token K_LABEL K_TC K_LAST K_EXP
499 %token K_ADDR K_MTU
501 %token K_ETH
502 %token K_PAUSE
503 %token K_PFC
504 %token K_VLAN K_MPLS
505 %token K_ARP
506 %token K_IP4 K_IP6
507 %token K_ICMP4 K_ICMP6
508 %token K_UDP K_TCP
510 %token ',' '{' '}' '(' ')' '[' ']' ':' '-' '+' '*' '/' '%' '&' '|' '<' '>' '^'
512 %token number string mac ip4_addr ip6_addr
514 %type <number> number expression
515 %type <str> string
516 %type <mac> mac
517 %type <ip4_addr> ip4_addr
518 %type <ip6_addr> ip6_addr
520 %left '-' '+' '*' '/' '%' '&' '|' '<' '>' '^'
524 packets
525 : { }
526 | packets packet { }
527 | packets inline_comment { }
528 | packets K_WHITE { }
531 inline_comment
532 : K_COMMENT { }
535 cpu_delim
536 : ':' { }
537 | '-' { }
540 delimiter_nowhite
541 : ',' { }
542 | ',' K_WHITE { }
545 noenforce_white
546 : { }
547 | K_WHITE { }
548 | delimiter_nowhite { }
551 skip_white
552 : { }
553 | K_WHITE { }
555 packet
556 : '{' noenforce_white payload noenforce_white '}' {
557 min_cpu = max_cpu = -1;
559 proto_packet_finish();
561 realloc_packet();
563 | K_CPU '(' number cpu_delim number ')' ':' noenforce_white '{' noenforce_white payload noenforce_white '}' {
564 min_cpu = $3;
565 max_cpu = $5;
567 if (min_cpu > max_cpu) {
568 int tmp = min_cpu;
570 min_cpu = max_cpu;
571 max_cpu = tmp;
574 proto_packet_finish();
576 realloc_packet();
578 | K_CPU '(' number ')' ':' noenforce_white '{' noenforce_white payload noenforce_white '}' {
579 min_cpu = max_cpu = $3;
581 proto_packet_finish();
583 realloc_packet();
587 payload
588 : elem { }
589 | payload elem_delimiter { }
592 delimiter
593 : delimiter_nowhite { }
594 | K_WHITE { }
597 elem_delimiter
598 : delimiter elem { }
601 elem
602 : number { set_byte((uint8_t) $1); }
603 | string { set_multi_byte((uint8_t *) $1 + 1, strlen($1) - 2); }
604 | fill { }
605 | rnd { }
606 | drnd { }
607 | seqinc { }
608 | seqdec { }
609 | dinc { }
610 | ddec { }
611 | csum { }
612 | const { }
613 | proto { proto_header_finish(hdr); }
614 | inline_comment { }
617 expression
618 : number
619 { $$ = $1; }
620 | expression '+' expression
621 { $$ = $1 + $3; }
622 | expression '-' expression
623 { $$ = $1 - $3; }
624 | expression '*' expression
625 { $$ = $1 * $3; }
626 | expression '/' expression
627 { $$ = $1 / $3; }
628 | expression '%' expression
629 { $$ = $1 % $3; }
630 | expression '&' expression
631 { $$ = $1 & $3; }
632 | expression '|' expression
633 { $$ = $1 | $3; }
634 | expression '^' expression
635 { $$ = $1 ^ $3; }
636 | expression '<' '<' expression
637 { $$ = $1 << $4; }
638 | expression '>' '>' expression
639 { $$ = $1 >> $4; }
640 | '-' expression
641 { $$ = -1 * $2; }
642 | '(' expression ')'
643 { $$ = $2;}
646 fill
647 : K_FILL '(' number delimiter number ')'
648 { set_fill($3, $5); }
651 const
652 : K_CONST8 '(' expression ')'
653 { set_byte((uint8_t) $3); }
654 | K_CONST16 '(' expression ')' {
655 uint16_t __c = cpu_to_be16((uint16_t) $3);
657 set_multi_byte((uint8_t *) &__c, sizeof(__c));
659 | K_CONST32 '(' expression ')' {
660 uint32_t __c = cpu_to_be32((uint32_t) $3);
662 set_multi_byte((uint8_t *) &__c, sizeof(__c));
664 | K_CONST64 '(' expression ')' {
665 uint64_t __c = cpu_to_be64((uint64_t) $3);
667 set_multi_byte((uint8_t *) &__c, sizeof(__c));
672 : K_RND '(' number ')'
673 { set_rnd($3); }
676 csum
677 : K_CSUMIP '(' number delimiter number ')'
678 { set_csum16($3, $5, CSUM_IP); }
679 | K_CSUMTCP '(' number delimiter number ')'
680 { set_csum16($3, $5, CSUM_TCP); }
681 | K_CSUMUDP '(' number delimiter number ')'
682 { set_csum16($3, $5, CSUM_UDP); }
683 | K_CSUMTCP6 '(' number delimiter number ')'
684 { set_csum16($3, $5, CSUM_TCP6); }
685 | K_CSUMUDP6 '(' number delimiter number ')'
686 { set_csum16($3, $5, CSUM_UDP6); }
689 seqinc
690 : K_SEQINC '(' number delimiter number ')'
691 { set_sequential_inc($3, $5, 1); }
692 | K_SEQINC '(' number delimiter number delimiter number ')'
693 { set_sequential_inc($3, $5, $7); }
696 seqdec
697 : K_SEQDEC '(' number delimiter number ')'
698 { set_sequential_dec($3, $5, 1); }
699 | K_SEQDEC '(' number delimiter number delimiter number ')'
700 { set_sequential_dec($3, $5, $7); }
703 drnd
704 : K_DRND '(' ')'
705 { set_dynamic_rnd(); }
706 | K_DRND '(' number ')'
708 int i, max = $3;
709 for (i = 0; i < max; ++i)
710 set_dynamic_rnd();
714 dinc
715 : K_DINC '(' number delimiter number ')'
716 { set_dynamic_incdec($3, $5, 1, TYPE_INC); }
717 | K_DINC '(' number delimiter number delimiter number ')'
718 { set_dynamic_incdec($3, $5, $7, TYPE_INC); }
721 ddec
722 : K_DDEC '(' number delimiter number ')'
723 { set_dynamic_incdec($3, $5, 1, TYPE_DEC); }
724 | K_DDEC '(' number delimiter number delimiter number ')'
725 { set_dynamic_incdec($3, $5, $7, TYPE_DEC); }
728 proto
729 : eth_proto { }
730 | pause_proto { }
731 | pfc_proto { }
732 | vlan_proto { }
733 | mpls_proto { }
734 | arp_proto { }
735 | ip4_proto { }
736 | ip6_proto { }
737 | icmp4_proto { }
738 | icmpv6_proto { }
739 | udp_proto { }
740 | tcp_proto { }
743 field_expr
744 : '[' skip_white number skip_white ']'
745 { field_index_validate(field_expr.field, $3, 1);
746 field_expr.type |= FIELD_EXPR_OFFSET;
747 field_expr.val.func.offset = $3;
748 field_expr.val.func.len = 1; }
749 | '[' skip_white number skip_white ':' skip_white number skip_white ']'
750 { field_index_validate(field_expr.field, $3, $7);
751 field_expr.type |= FIELD_EXPR_OFFSET;
752 field_expr.val.func.offset = $3;
753 field_expr.val.func.len = $7; }
756 field_value_expr
757 : number { field_expr.type |= FIELD_EXPR_NUMB;
758 field_expr.val.number = $1; }
759 | mac { field_expr.type |= FIELD_EXPR_MAC;
760 memcpy(field_expr.val.mac, $1, sizeof(field_expr.val.mac)); }
761 | ip4_addr { field_expr.type |= FIELD_EXPR_IP4_ADDR;
762 field_expr.val.ip4_addr = $1; }
763 | ip6_addr { field_expr.type |= FIELD_EXPR_IP6_ADDR;
764 field_expr.val.ip6_addr = $1; }
765 | K_DINC '(' ')' { field_expr.type |= FIELD_EXPR_INC;
766 field_expr.val.func.type = PROTO_FIELD_FUNC_INC;
767 field_expr.val.func.inc = 1; }
768 | K_DINC '(' number ')'
769 { field_expr.type |= FIELD_EXPR_INC;
770 field_expr.val.func.type = PROTO_FIELD_FUNC_INC;
771 field_expr.val.func.inc = $3; }
772 | K_DINC '(' number delimiter number ')'
773 { field_expr.type |= FIELD_EXPR_INC;
774 field_expr.val.func.type = PROTO_FIELD_FUNC_INC;
775 field_expr.val.func.type |= PROTO_FIELD_FUNC_MIN;
776 field_expr.val.func.min = $3;
777 field_expr.val.func.max = $5;
778 field_expr.val.func.inc = 1; }
779 | K_DINC '(' number delimiter number delimiter number ')'
780 { field_expr.type |= FIELD_EXPR_INC;
781 field_expr.val.func.type = PROTO_FIELD_FUNC_INC;
782 field_expr.val.func.type |= PROTO_FIELD_FUNC_MIN;
783 field_expr.val.func.min = $3;
784 field_expr.val.func.max = $5;
785 field_expr.val.func.inc = $7; }
786 | K_DRND '(' ')' { field_expr.type |= FIELD_EXPR_RND;
787 field_expr.val.func.type = PROTO_FIELD_FUNC_RND; }
788 | K_DRND '(' number delimiter number ')'
789 { field_expr.type |= FIELD_EXPR_RND;
790 field_expr.val.func.type = PROTO_FIELD_FUNC_RND;
791 field_expr.val.func.min = $3;
792 field_expr.val.func.max = $5; }
795 eth_proto
796 : eth '(' eth_param_list ')' { }
800 : K_ETH { proto_add(PROTO_ETH); }
803 eth_param_list
804 : { }
805 | eth_expr { }
806 | eth_expr delimiter eth_param_list { }
809 eth_type
810 : K_ETYPE { }
811 | K_TYPE { }
812 | K_PROT { }
815 eth_field
816 : K_DADDR { proto_field_set(ETH_DST_ADDR); }
817 | K_SADDR { proto_field_set(ETH_SRC_ADDR); }
818 | eth_type { proto_field_set(ETH_TYPE); }
820 eth_expr
821 : eth_field field_expr skip_white '=' skip_white field_value_expr
822 { proto_field_expr_eval(); }
823 | eth_field skip_white '=' skip_white field_value_expr
824 { proto_field_expr_eval(); }
827 pause_proto
828 : pause '(' pause_param_list ')' { }
831 pause
832 : K_PAUSE { proto_add(PROTO_PAUSE); }
835 pause_param_list
836 : { }
837 | pause_expr { }
838 | pause_expr delimiter pause_param_list { }
841 pause_field
842 : K_CODE { proto_field_set(PAUSE_OPCODE); }
843 | K_TIME { proto_field_set(PAUSE_TIME); }
846 pause_expr
847 : pause_field field_expr skip_white '=' skip_white field_value_expr
848 { proto_field_expr_eval(); }
849 | pause_field skip_white '=' skip_white field_value_expr
850 { proto_field_expr_eval(); }
853 pfc_proto
854 : pfc '(' pfc_param_list ')' { }
858 : K_PFC { proto_add(PROTO_PFC); }
861 pfc_param_list
862 : { }
863 | pfc_expr { }
864 | pfc_expr delimiter pfc_param_list { }
867 pfc_field
868 : K_CODE { proto_field_set(PFC_OPCODE); }
869 | K_PRIO { proto_field_set(PFC_PRIO); }
870 | K_PRIO '(' number ')'
871 { if ($3 > 7) {
872 yyerror("pfc: Invalid prio(index) parameter");
873 panic("pfc: prio(0)..prio(7) is allowed only\n");
875 proto_field_set(PFC_PRIO_0 + $3); }
876 | K_TIME '(' number ')'
877 { if ($3 > 7) {
878 yyerror("pfc: Invalid time(index) parameter");
879 panic("pfc: time(0)..time(7) is allowed only\n");
881 proto_field_set(PFC_TIME_0 + $3); }
884 pfc_expr
885 : pfc_field field_expr skip_white '=' skip_white field_value_expr
886 { proto_field_expr_eval(); }
887 | pfc_field skip_white '=' skip_white field_value_expr
888 { proto_field_expr_eval(); }
891 vlan_proto
892 : vlan '(' vlan_param_list ')' { }
895 vlan
896 : K_VLAN { proto_add(PROTO_VLAN); }
899 vlan_param_list
900 : { }
901 | vlan_expr { }
902 | vlan_expr delimiter vlan_param_list { }
905 vlan_type
906 : K_TPID { }
907 | K_PROT
910 vlan_field
911 : vlan_type { proto_field_set(VLAN_TPID); }
912 | K_TCI { proto_field_set(VLAN_TCI); }
913 | K_PCP { proto_field_set(VLAN_PCP); }
914 | K_DEI { proto_field_set(VLAN_DEI); }
915 | K_ID { proto_field_set(VLAN_VID); }
918 vlan_expr
919 : vlan_field field_expr skip_white '=' skip_white field_value_expr
920 { proto_field_expr_eval(); }
921 | vlan_field skip_white '=' skip_white field_value_expr
922 { proto_field_expr_eval(); }
923 | K_1Q
924 { proto_hdr_field_set_be16(hdr, VLAN_TPID, ETH_P_8021Q); }
925 | K_1AD
926 { proto_hdr_field_set_be16(hdr, VLAN_TPID, ETH_P_8021AD); }
929 mpls_proto
930 : mpls '(' mpls_param_list ')' { }
933 mpls
934 : K_MPLS { proto_add(PROTO_MPLS); }
937 mpls_param_list
938 : { }
939 | mpls_expr { }
940 | mpls_expr delimiter mpls_param_list { }
943 mpls_tc
944 : K_TC { }
945 | K_EXP { }
948 mpls_field
949 : K_LABEL { proto_field_set(MPLS_LABEL); }
950 | mpls_tc { proto_field_set(MPLS_TC); }
951 | K_LAST { proto_field_set(MPLS_LAST); }
952 | K_TTL { proto_field_set(MPLS_TTL); }
955 mpls_expr
956 : mpls_field field_expr skip_white '=' skip_white field_value_expr
957 { proto_field_expr_eval(); }
958 | mpls_field skip_white '=' skip_white field_value_expr
959 { proto_field_expr_eval(); }
962 arp_proto
963 : arp '(' arp_param_list ')' { }
966 arp_param_list
967 : { }
968 | arp_expr { }
969 | arp_expr delimiter arp_param_list { }
972 arp_field
973 : K_HTYPE
974 { proto_field_set(ARP_HTYPE); }
975 | K_PTYPE
976 { proto_field_set(ARP_PTYPE); }
977 | K_SHA
978 { proto_field_set(ARP_SHA); }
979 | K_THA
980 { proto_field_set(ARP_THA); }
981 | K_SPA
982 { proto_field_set(ARP_SPA); }
983 | K_TPA
984 { proto_field_set(ARP_TPA); }
987 arp_expr
988 : arp_field field_expr skip_white '=' skip_white field_value_expr
989 { proto_field_expr_eval(); }
990 | arp_field skip_white '=' skip_white field_value_expr
991 { proto_field_expr_eval(); }
992 | K_OPER field_expr skip_white '=' skip_white field_value_expr
993 { proto_field_set(ARP_OPER);
994 proto_field_expr_eval(); }
995 | K_OPER skip_white '=' skip_white field_value_expr
996 { proto_field_set(ARP_OPER);
997 proto_field_expr_eval(); }
998 | K_OPER skip_white '=' skip_white K_REQUEST
999 { proto_hdr_field_set_be16(hdr, ARP_OPER, ARPOP_REQUEST); }
1000 | K_OPER skip_white '=' skip_white K_REPLY
1001 { proto_hdr_field_set_be16(hdr, ARP_OPER, ARPOP_REPLY); }
1002 | K_REQUEST
1003 { proto_hdr_field_set_be16(hdr, ARP_OPER, ARPOP_REQUEST); }
1004 | K_REPLY
1005 { proto_hdr_field_set_be16(hdr, ARP_OPER, ARPOP_REPLY); }
1009 : K_ARP { proto_add(PROTO_ARP); }
1012 ip4_proto
1013 : ip4 '(' ip4_param_list ')' { }
1016 ip4_param_list
1017 : { }
1018 | ip4_expr { }
1019 | ip4_expr delimiter ip4_param_list { }
1022 ip4_field
1023 : K_VER { proto_field_set(IP4_VER); }
1024 | K_IHL { proto_field_set(IP4_IHL); }
1025 | K_DADDR { proto_field_set(IP4_DADDR); }
1026 | K_SADDR { proto_field_set(IP4_SADDR); }
1027 | K_PROT { proto_field_set(IP4_PROTO); }
1028 | K_TTL { proto_field_set(IP4_TTL); }
1029 | K_DSCP { proto_field_set(IP4_DSCP); }
1030 | K_ECN { proto_field_set(IP4_ECN); }
1031 | K_TOS { proto_field_set(IP4_TOS); }
1032 | K_LEN { proto_field_set(IP4_LEN); }
1033 | K_ID { proto_field_set(IP4_ID); }
1034 | K_FLAGS { proto_field_set(IP4_FLAGS); }
1035 | K_FRAG { proto_field_set(IP4_FRAG_OFFS); }
1036 | K_CSUM { proto_field_set(IP4_CSUM); }
1039 ip4_expr
1040 : ip4_field field_expr skip_white '=' skip_white field_value_expr
1041 { proto_field_expr_eval(); }
1042 | ip4_field skip_white '=' skip_white field_value_expr
1043 { proto_field_expr_eval(); }
1044 | K_DF { proto_hdr_field_set_be16(hdr, IP4_DF, 1); }
1045 | K_MF { proto_hdr_field_set_be16(hdr, IP4_MF, 1); }
1049 : K_IP4 { proto_add(PROTO_IP4); }
1052 ip6_proto
1053 : ip6 '(' ip6_param_list ')' { }
1056 ip6_param_list
1057 : { }
1058 | ip6_expr { }
1059 | ip6_expr delimiter ip6_param_list { }
1062 ip6_hop_limit
1063 : K_HOP_LIMIT { }
1064 | K_TTL { }
1067 ip6_field
1068 : K_VER { proto_field_set(IP6_VER); }
1069 | K_TC { proto_field_set(IP6_CLASS); }
1070 | K_FLOW { proto_field_set(IP6_FLOW_LBL); }
1071 | K_LEN { proto_field_set(IP6_LEN); }
1072 | K_NEXT_HDR { proto_field_set(IP6_NEXT_HDR); }
1073 | ip6_hop_limit { proto_field_set(IP6_HOP_LIMIT); }
1074 | K_SADDR { proto_field_set(IP6_SADDR); }
1075 | K_DADDR { proto_field_set(IP6_DADDR) ; }
1078 ip6_expr
1079 : ip6_field field_expr skip_white '=' skip_white field_value_expr
1080 { proto_field_expr_eval(); }
1081 | ip6_field skip_white '=' skip_white field_value_expr
1082 { proto_field_expr_eval(); }
1086 : K_IP6 { proto_add(PROTO_IP6); }
1089 icmp4_proto
1090 : icmp4 '(' icmp4_param_list ')' { }
1093 icmp4_param_list
1094 : { }
1095 | icmp4_expr { }
1096 | icmp4_expr delimiter icmp4_param_list { }
1099 icmp4_field
1100 : K_TYPE { proto_field_set(ICMPV4_TYPE); }
1101 | K_CODE { proto_field_set(ICMPV4_CODE); }
1102 | K_ID { proto_field_set(ICMPV4_ID); }
1103 | K_SEQ { proto_field_set(ICMPV4_SEQ); }
1104 | K_MTU { proto_field_set(ICMPV4_MTU); }
1105 | K_ADDR { proto_field_set(ICMPV4_REDIR_ADDR); }
1108 icmp4_expr
1109 : icmp4_field field_expr skip_white '=' skip_white field_value_expr
1110 { proto_field_expr_eval(); }
1111 | icmp4_field skip_white '=' skip_white field_value_expr
1112 { proto_field_expr_eval(); }
1113 | K_ECHO_REQUEST
1114 { proto_hdr_field_set_u8(hdr, ICMPV4_TYPE, ICMP_ECHO);
1115 proto_hdr_field_set_u8(hdr, ICMPV4_CODE, 0); }
1116 | K_ECHO_REPLY
1117 { proto_hdr_field_set_u8(hdr, ICMPV4_TYPE, ICMP_ECHOREPLY);
1118 proto_hdr_field_set_u8(hdr, ICMPV4_CODE, 0); }
1121 icmp4
1122 : K_ICMP4 { proto_add(PROTO_ICMP4); }
1125 icmpv6_proto
1126 : icmp6 '(' icmp6_param_list ')' { }
1129 icmp6_param_list
1130 : { }
1131 | icmp6_expr { }
1132 | icmp6_expr delimiter icmp6_param_list { }
1135 icmp6_field
1136 : K_CODE { proto_field_set(ICMPV6_CODE); }
1137 | K_CSUM { proto_field_set(ICMPV6_CSUM); }
1140 icmp6_expr
1141 : icmp6_field field_expr skip_white '=' skip_white field_value_expr
1142 { proto_field_expr_eval(); }
1143 | icmp6_field skip_white '=' skip_white field_value_expr
1144 { proto_field_expr_eval(); }
1145 | K_TYPE field_expr skip_white '=' skip_white field_value_expr
1146 { proto_field_set(ICMPV6_TYPE);
1147 proto_field_expr_eval(); }
1148 | K_TYPE skip_white '=' skip_white field_value_expr
1149 { proto_field_set(ICMPV6_TYPE);
1150 proto_field_expr_eval(); }
1151 | K_TYPE skip_white '=' K_ECHO_REQUEST
1152 { proto_hdr_field_set_u8(hdr, ICMPV6_TYPE, ICMPV6_ECHO_REQUEST); }
1153 | K_ECHO_REQUEST
1154 { proto_hdr_field_set_u8(hdr, ICMPV6_TYPE, ICMPV6_ECHO_REQUEST); }
1155 | K_TYPE skip_white '=' K_ECHO_REPLY
1156 { proto_hdr_field_set_u8(hdr, ICMPV6_TYPE, ICMPV6_ECHO_REPLY); }
1157 | K_ECHO_REPLY
1158 { proto_hdr_field_set_u8(hdr, ICMPV6_TYPE, ICMPV6_ECHO_REPLY); }
1160 icmp6
1161 : K_ICMP6 { proto_add(PROTO_ICMP6); }
1164 udp_proto
1165 : udp '(' udp_param_list ')' { }
1168 udp_param_list
1169 : { }
1170 | udp_expr { }
1171 | udp_expr delimiter udp_param_list { }
1174 udp_field
1175 : K_SPORT { proto_field_set(UDP_SPORT); }
1176 | K_DPORT { proto_field_set(UDP_DPORT); }
1177 | K_LEN { proto_field_set(UDP_LEN); }
1178 | K_CSUM { proto_field_set(UDP_CSUM); }
1181 udp_expr
1182 : udp_field field_expr skip_white '=' skip_white field_value_expr
1183 { proto_field_expr_eval(); }
1184 | udp_field skip_white '=' skip_white field_value_expr
1185 { proto_field_expr_eval(); }
1189 : K_UDP { proto_add(PROTO_UDP); }
1192 tcp_proto
1193 : tcp '(' tcp_param_list ')' { }
1196 tcp_param_list
1197 : { }
1198 | tcp_expr { }
1199 | tcp_expr delimiter tcp_param_list { }
1202 tcp_field
1203 : K_SPORT { proto_field_set(TCP_SPORT); }
1204 | K_DPORT { proto_field_set(TCP_DPORT); }
1205 | K_SEQ { proto_field_set(TCP_SEQ); }
1206 | K_ACK_SEQ { proto_field_set(TCP_ACK_SEQ); }
1207 | K_DOFF { proto_field_set(TCP_DOFF); }
1208 | K_WINDOW { proto_field_set(TCP_WINDOW); }
1209 | K_CSUM { proto_field_set(TCP_CSUM); }
1210 | K_URG_PTR { proto_field_set(TCP_URG_PTR); }
1213 tcp_expr
1214 : tcp_field field_expr skip_white '=' skip_white field_value_expr
1215 { proto_field_expr_eval(); }
1216 | tcp_field skip_white '=' skip_white field_value_expr
1217 { proto_field_expr_eval(); }
1218 | K_CWR { proto_hdr_field_set_be16(hdr, TCP_CWR, 1); }
1219 | K_ECE { proto_hdr_field_set_be16(hdr, TCP_ECE, 1); }
1220 | K_URG { proto_hdr_field_set_be16(hdr, TCP_URG, 1); }
1221 | K_ACK { proto_hdr_field_set_be16(hdr, TCP_ACK, 1); }
1222 | K_PSH { proto_hdr_field_set_be16(hdr, TCP_PSH, 1); }
1223 | K_RST { proto_hdr_field_set_be16(hdr, TCP_RST, 1); }
1224 | K_SYN { proto_hdr_field_set_be16(hdr, TCP_SYN, 1); }
1225 | K_FIN { proto_hdr_field_set_be16(hdr, TCP_FIN, 1); }
1229 : K_TCP { proto_add(PROTO_TCP); }
1234 static void finalize_packet(void)
1236 /* XXX hack ... we allocated one packet pointer too much */
1237 plen--;
1238 dlen--;
1241 static void dump_conf(void)
1243 size_t i, j;
1245 for (i = 0; i < plen; ++i) {
1246 printf("[%zu] pkt\n", i);
1247 printf(" len %zu cnts %zu rnds %zu\n",
1248 packets[i].len,
1249 packet_dyn[i].clen,
1250 packet_dyn[i].rlen);
1252 printf(" payload ");
1253 for (j = 0; j < packets[i].len; ++j)
1254 printf("%02x ", packets[i].payload[j]);
1255 printf("\n");
1257 for (j = 0; j < packet_dyn[i].clen; ++j)
1258 printf(" cnt%zu [%u,%u], inc %u, off %jd type %s\n", j,
1259 packet_dyn[i].cnt[j].min,
1260 packet_dyn[i].cnt[j].max,
1261 packet_dyn[i].cnt[j].inc,
1262 (intmax_t)packet_dyn[i].cnt[j].off,
1263 packet_dyn[i].cnt[j].type == TYPE_INC ?
1264 "inc" : "dec");
1266 for (j = 0; j < packet_dyn[i].rlen; ++j)
1267 printf(" rnd%zu off %jd\n", j,
1268 (intmax_t)packet_dyn[i].rnd[j].off);
1272 void cleanup_packets(void)
1274 size_t i, j;
1276 for (i = 0; i < plen; ++i) {
1277 struct packet *pkt = &packets[i];
1279 if (pkt->len > 0)
1280 xfree(pkt->payload);
1282 for (j = 0; j < pkt->headers_count; j++) {
1283 struct proto_hdr *hdr = pkt->headers[j];
1285 if (hdr->fields)
1286 xfree(hdr->fields);
1287 xfree(hdr);
1291 free(packets);
1293 for (i = 0; i < dlen; ++i) {
1294 free(packet_dyn[i].cnt);
1295 free(packet_dyn[i].rnd);
1297 for (j = 0; j < packet_dyn[j].flen; j++)
1298 xfree(packet_dyn[i].fields[j]);
1300 free(packet_dyn[i].fields);
1303 free(packet_dyn);
1306 void compile_packets(char *file, bool verbose, unsigned int cpu,
1307 bool invoke_cpp, char *const cpp_argv[])
1309 char tmp_file[128];
1310 int ret = -1;
1312 if (access(file, R_OK)) {
1313 fprintf(stderr, "Cannot access %s: %s!\n", file, strerror(errno));
1314 die();
1317 memset(tmp_file, 0, sizeof(tmp_file));
1318 our_cpu = cpu;
1320 if (invoke_cpp) {
1321 if (cpp_exec(file, tmp_file, sizeof(tmp_file), cpp_argv)) {
1322 fprintf(stderr, "Failed to invoke C preprocessor!\n");
1323 goto err;
1325 file = tmp_file;
1328 if (!strncmp("-", file, strlen("-")))
1329 yyin = stdin;
1330 else
1331 yyin = fopen(file, "r");
1332 if (!yyin) {
1333 fprintf(stderr, "Cannot open %s: %s!\n", file, strerror(errno));
1334 goto err;
1337 realloc_packet();
1338 if (yyparse() != 0)
1339 goto err;
1340 finalize_packet();
1342 if (our_cpu == 0 && verbose)
1343 dump_conf();
1345 ret = 0;
1346 err:
1347 if (yyin && yyin != stdin)
1348 fclose(yyin);
1350 if (invoke_cpp)
1351 unlink(tmp_file);
1352 if (ret)
1353 die();
1356 void compile_packets_str(char *str, bool verbose, unsigned int cpu)
1358 int ret = 1;
1360 our_cpu = cpu;
1361 realloc_packet();
1363 yy_scan_string(str);
1364 if (yyparse() != 0)
1365 goto err;
1367 finalize_packet();
1368 if (our_cpu == 0 && verbose)
1369 dump_conf();
1371 ret = 0;
1372 err:
1373 yylex_destroy();
1375 if (ret)
1376 die();
1379 void yyerror(const char *err)
1381 fprintf(stderr, "Syntax error at line %d, char '%s': %s\n", yylineno, yytext, err);