From 647b7b76d63f8c847b17495e6ad24dc3b256899f Mon Sep 17 00:00:00 2001 From: Vadim Kochan Date: Sun, 18 Dec 2016 11:52:49 +0200 Subject: trafgen: parser: Allow to set function at field offset Extend proto field expression to: proto_field[{index}:{len}] = {func} which allows to specify function on the field offset via index and value length (default is 1 - 1 byte). This rule is optional. It was needed to keep of proto_field's copies in packet_dyn->fields instead of original fields which allows to scpecify different functions on the different parts of same field, also the copy of original proto_field allows to set custom length/pkt_offset which makes such field behave as virtual sub-field of the original one with different length/pkt_offset but point to the same piece of header. Signed-off-by: Vadim Kochan Signed-off-by: Tobias Klauser --- trafgen_parser.y | 168 +++++++++++++++++++++++++++++++++++++++---------------- trafgen_proto.c | 27 ++++----- trafgen_proto.h | 8 ++- 3 files changed, 136 insertions(+), 67 deletions(-) diff --git a/trafgen_parser.y b/trafgen_parser.y index a1b8b0c..cc1a110 100644 --- a/trafgen_parser.y +++ b/trafgen_parser.y @@ -74,13 +74,14 @@ extern size_t dlen; static int our_cpu, min_cpu = -1, max_cpu = -1; enum field_expr_type_t { - FIELD_EXPR_UNKNOWN, - FIELD_EXPR_NUMB, - FIELD_EXPR_MAC, - FIELD_EXPR_IP4_ADDR, - FIELD_EXPR_IP6_ADDR, - FIELD_EXPR_INC, - FIELD_EXPR_RND, + FIELD_EXPR_UNKNOWN = 0, + FIELD_EXPR_NUMB = 1 << 0, + FIELD_EXPR_MAC = 1 << 1, + FIELD_EXPR_IP4_ADDR = 1 << 2, + FIELD_EXPR_IP6_ADDR = 1 << 3, + FIELD_EXPR_INC = 1 << 4, + FIELD_EXPR_RND = 1 << 5, + FIELD_EXPR_OFFSET = 1 << 6, }; struct proto_field_expr { @@ -387,28 +388,44 @@ static void proto_add(enum proto_id pid) static void proto_field_set(uint32_t fid) { + memset(&field_expr, 0, sizeof(field_expr)); field_expr.field = proto_hdr_field_by_id(hdr, fid); } static void proto_field_func_setup(struct proto_field *field, struct proto_field_func *func) { + struct proto_field *field_copy; struct packet_dyn *pkt_dyn; - proto_hdr_field_func_add(field->hdr, field->id, func); + field_copy = xmalloc(sizeof(*field)); + memcpy(field_copy, field, sizeof(*field)); + + field_copy->pkt_offset += func->offset; + if (func->len) + field_copy->len = func->len; + + proto_field_func_add(field_copy, func); pkt_dyn = &packet_dyn[packetd_last]; pkt_dyn->flen++; pkt_dyn->fields = xrealloc(pkt_dyn->fields, pkt_dyn->flen * sizeof(struct proto_field *)); - pkt_dyn->fields[pkt_dyn->flen - 1] = field; + + pkt_dyn->fields[pkt_dyn->flen - 1] = field_copy; } static void proto_field_expr_eval(void) { struct proto_field *field = field_expr.field; - switch (field_expr.type) { - case FIELD_EXPR_NUMB: + if ((field_expr.type & FIELD_EXPR_OFFSET) && + !((field_expr.type & FIELD_EXPR_INC) || + (field_expr.type & FIELD_EXPR_RND))) { + + panic("Field offset expression is valid only with function expression\n"); + } + + if (field_expr.type & FIELD_EXPR_NUMB) { if (field->len == 1) proto_hdr_field_set_u8(hdr, field->id, field_expr.val.number); else if (field->len == 2) @@ -417,39 +434,47 @@ static void proto_field_expr_eval(void) proto_hdr_field_set_be32(hdr, field->id, field_expr.val.number); else proto_hdr_field_set_bytes(hdr, field->id, field_expr.val.bytes); - break; - - case FIELD_EXPR_MAC: + } else if (field_expr.type & FIELD_EXPR_MAC) { proto_hdr_field_set_bytes(hdr, field->id, field_expr.val.bytes); - break; - - case FIELD_EXPR_IP4_ADDR: + } else if (field_expr.type & FIELD_EXPR_IP4_ADDR) { proto_hdr_field_set_u32(hdr, field->id, field_expr.val.ip4_addr.s_addr); - break; - - case FIELD_EXPR_IP6_ADDR: + } else if (field_expr.type & FIELD_EXPR_IP6_ADDR) { proto_hdr_field_set_bytes(hdr, field->id, (uint8_t *)&field_expr.val.ip6_addr.s6_addr); - break; + } else if ((field_expr.type & FIELD_EXPR_INC) || + (field_expr.type & FIELD_EXPR_RND)) { - case FIELD_EXPR_INC: - case FIELD_EXPR_RND: if (field_expr.val.func.min && field_expr.val.func.min >= field_expr.val.func.max) panic("dinc(): min(%u) can't be >= max(%u)\n", field_expr.val.func.min, field_expr.val.func.max); proto_field_func_setup(field, &field_expr.val.func); - break; + } else if ((field_expr.type & FIELD_EXPR_OFFSET) && + !((field_expr.type & FIELD_EXPR_INC) || + (field_expr.type & FIELD_EXPR_RND))) { - case FIELD_EXPR_UNKNOWN: - default: + panic("Field expression is valid only for function value expression\n"); + } else { bug(); } memset(&field_expr, 0, sizeof(field_expr)); } +static void field_index_validate(struct proto_field *field, uint16_t index, size_t len) +{ + if (field_expr.field->len <= index) { + yyerror("Invalid [index] parameter"); + panic("Index (%u) is bigger than field's length (%zu)\n", + index, field->len); + } + if (len != 1 && len != 2 && len != 4) { + yyerror("Invalid [index:len] parameter"); + panic("Invalid index length - 1,2 or 4 is only allowed\n"); + } +} + %} %union { @@ -718,40 +743,53 @@ proto | tcp_proto { } ; +field_expr + : '[' skip_white number skip_white ']' + { field_index_validate(field_expr.field, $3, 1); + field_expr.type |= FIELD_EXPR_OFFSET; + field_expr.val.func.offset = $3; + field_expr.val.func.len = 1; } + | '[' skip_white number skip_white ':' skip_white number skip_white ']' + { field_index_validate(field_expr.field, $3, $7); + field_expr.type |= FIELD_EXPR_OFFSET; + field_expr.val.func.offset = $3; + field_expr.val.func.len = $7; } + ; + field_value_expr - : number { field_expr.type = FIELD_EXPR_NUMB; + : number { field_expr.type |= FIELD_EXPR_NUMB; field_expr.val.number = $1; } - | mac { field_expr.type = FIELD_EXPR_MAC; + | mac { field_expr.type |= FIELD_EXPR_MAC; memcpy(field_expr.val.bytes, $1, sizeof(field_expr.val.bytes)); } - | ip4_addr { field_expr.type = FIELD_EXPR_IP4_ADDR; + | ip4_addr { field_expr.type |= FIELD_EXPR_IP4_ADDR; field_expr.val.ip4_addr = $1; } - | ip6_addr { field_expr.type = FIELD_EXPR_IP6_ADDR; + | ip6_addr { field_expr.type |= FIELD_EXPR_IP6_ADDR; field_expr.val.ip6_addr = $1; } - | K_DINC '(' ')' { field_expr.type = FIELD_EXPR_INC; + | K_DINC '(' ')' { field_expr.type |= FIELD_EXPR_INC; field_expr.val.func.type = PROTO_FIELD_FUNC_INC; field_expr.val.func.inc = 1; } | K_DINC '(' number ')' - { field_expr.type = FIELD_EXPR_INC; + { field_expr.type |= FIELD_EXPR_INC; field_expr.val.func.type = PROTO_FIELD_FUNC_INC; field_expr.val.func.inc = $3; } | K_DINC '(' number delimiter number ')' - { field_expr.type = FIELD_EXPR_INC; + { field_expr.type |= FIELD_EXPR_INC; field_expr.val.func.type = PROTO_FIELD_FUNC_INC; field_expr.val.func.type |= PROTO_FIELD_FUNC_MIN; field_expr.val.func.min = $3; field_expr.val.func.max = $5; field_expr.val.func.inc = 1; } | K_DINC '(' number delimiter number delimiter number ')' - { field_expr.type = FIELD_EXPR_INC; + { field_expr.type |= FIELD_EXPR_INC; field_expr.val.func.type = PROTO_FIELD_FUNC_INC; field_expr.val.func.type |= PROTO_FIELD_FUNC_MIN; field_expr.val.func.min = $3; field_expr.val.func.max = $5; field_expr.val.func.inc = $7; } - | K_DRND '(' ')' { field_expr.type = FIELD_EXPR_RND; + | K_DRND '(' ')' { field_expr.type |= FIELD_EXPR_RND; field_expr.val.func.type = PROTO_FIELD_FUNC_RND; } | K_DRND '(' number delimiter number ')' - { field_expr.type = FIELD_EXPR_RND; + { field_expr.type |= FIELD_EXPR_RND; field_expr.val.func.type = PROTO_FIELD_FUNC_RND; field_expr.val.func.min = $3; field_expr.val.func.max = $5; } @@ -783,7 +821,9 @@ eth_field | eth_type { proto_field_set(ETH_TYPE); } eth_expr - : eth_field skip_white '=' skip_white field_value_expr + : eth_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | eth_field skip_white '=' skip_white field_value_expr { proto_field_expr_eval(); } ; @@ -807,7 +847,9 @@ pause_field ; pause_expr - : pause_field skip_white '=' skip_white field_value_expr + : pause_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | pause_field skip_white '=' skip_white field_value_expr { proto_field_expr_eval(); } ; @@ -843,7 +885,9 @@ pfc_field ; pfc_expr - : pfc_field skip_white '=' skip_white field_value_expr + : pfc_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | pfc_field skip_white '=' skip_white field_value_expr { proto_field_expr_eval(); } ; @@ -875,7 +919,9 @@ vlan_field ; vlan_expr - : vlan_field skip_white '=' skip_white field_value_expr + : vlan_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | vlan_field skip_white '=' skip_white field_value_expr { proto_field_expr_eval(); } | K_1Q { proto_hdr_field_set_be16(hdr, VLAN_TPID, ETH_P_8021Q); } @@ -910,7 +956,9 @@ mpls_field ; mpls_expr - : mpls_field skip_white '=' skip_white field_value_expr + : mpls_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | mpls_field skip_white '=' skip_white field_value_expr { proto_field_expr_eval(); } arp_proto @@ -939,8 +987,13 @@ arp_field ; arp_expr - : arp_field skip_white '=' skip_white field_value_expr + : arp_field field_expr skip_white '=' skip_white field_value_expr { proto_field_expr_eval(); } + | arp_field skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | K_OPER field_expr skip_white '=' skip_white field_value_expr + { proto_field_set(ARP_OPER); + proto_field_expr_eval(); } | K_OPER skip_white '=' skip_white field_value_expr { proto_field_set(ARP_OPER); proto_field_expr_eval(); } @@ -985,7 +1038,9 @@ ip4_field ; ip4_expr - : ip4_field skip_white '=' skip_white field_value_expr + : ip4_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | ip4_field skip_white '=' skip_white field_value_expr { proto_field_expr_eval(); } | K_DF { proto_hdr_field_set_be16(hdr, IP4_DF, 1); } | K_MF { proto_hdr_field_set_be16(hdr, IP4_MF, 1); } @@ -1022,7 +1077,9 @@ ip6_field ; ip6_expr - : ip6_field skip_white '=' skip_white field_value_expr + : ip6_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | ip6_field skip_white '=' skip_white field_value_expr { proto_field_expr_eval(); } ; @@ -1050,7 +1107,9 @@ icmp4_field ; icmp4_expr - : icmp4_field skip_white '=' skip_white field_value_expr + : icmp4_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | icmp4_field skip_white '=' skip_white field_value_expr { proto_field_expr_eval(); } | K_ECHO_REQUEST { proto_hdr_field_set_u8(hdr, ICMPV4_TYPE, ICMP_ECHO); @@ -1079,8 +1138,13 @@ icmp6_field ; icmp6_expr - : icmp6_field skip_white '=' skip_white field_value_expr + : icmp6_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | icmp6_field skip_white '=' skip_white field_value_expr { proto_field_expr_eval(); } + | K_TYPE field_expr skip_white '=' skip_white field_value_expr + { proto_field_set(ICMPV6_TYPE); + proto_field_expr_eval(); } | K_TYPE skip_white '=' skip_white field_value_expr { proto_field_set(ICMPV6_TYPE); proto_field_expr_eval(); } @@ -1115,7 +1179,9 @@ udp_field ; udp_expr - : udp_field skip_white '=' skip_white field_value_expr + : udp_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | udp_field skip_white '=' skip_white field_value_expr { proto_field_expr_eval(); } ; @@ -1145,7 +1211,9 @@ tcp_field ; tcp_expr - : tcp_field skip_white '=' skip_white field_value_expr + : tcp_field field_expr skip_white '=' skip_white field_value_expr + { proto_field_expr_eval(); } + | tcp_field skip_white '=' skip_white field_value_expr { proto_field_expr_eval(); } | K_CWR { proto_hdr_field_set_be16(hdr, TCP_CWR, 1); } | K_ECE { proto_hdr_field_set_be16(hdr, TCP_ECE, 1); } @@ -1225,6 +1293,10 @@ void cleanup_packets(void) for (i = 0; i < dlen; ++i) { free(packet_dyn[i].cnt); free(packet_dyn[i].rnd); + + for (j = 0; j < packet_dyn[j].flen; j++) + xfree(packet_dyn[i].fields[j]); + free(packet_dyn[i].fields); } diff --git a/trafgen_proto.c b/trafgen_proto.c index e2b80d4..88e0846 100644 --- a/trafgen_proto.c +++ b/trafgen_proto.c @@ -532,11 +532,11 @@ static inline uint32_t field_inc(struct proto_field *field) static void field_inc_func(struct proto_field *field) { if (field->len == 1) { - proto_hdr_field_set_u8(field->hdr, field->id, field_inc(field)); + proto_field_set_u8(field, field_inc(field)); } else if (field->len == 2) { - proto_hdr_field_set_be16(field->hdr, field->id, field_inc(field)); + proto_field_set_be16(field, field_inc(field)); } else if (field->len == 4) { - proto_hdr_field_set_be32(field->hdr, field->id, field_inc(field)); + proto_field_set_be32(field, field_inc(field)); } else if (field->len > 4) { uint8_t *bytes = __proto_field_get_bytes(field); @@ -554,14 +554,11 @@ static inline uint32_t field_rand(struct proto_field *field) static void field_rnd_func(struct proto_field *field) { if (field->len == 1) { - proto_hdr_field_set_u8(field->hdr, field->id, - (uint8_t) field_rand(field)); + proto_field_set_u8(field, (uint8_t) field_rand(field)); } else if (field->len == 2) { - proto_hdr_field_set_be16(field->hdr, field->id, - (uint16_t) field_rand(field)); + proto_field_set_be16(field, (uint16_t) field_rand(field)); } else if (field->len == 4) { - proto_hdr_field_set_be32(field->hdr, field->id, - (uint32_t) field_rand(field)); + proto_field_set_be32(field, (uint32_t) field_rand(field)); } else if (field->len > 4) { uint8_t *bytes = __proto_field_get_bytes(field); uint32_t i; @@ -571,11 +568,9 @@ static void field_rnd_func(struct proto_field *field) } } -void proto_hdr_field_func_add(struct proto_hdr *hdr, uint32_t fid, - struct proto_field_func *func) +void proto_field_func_add(struct proto_field *field, + struct proto_field_func *func) { - struct proto_field *field = proto_hdr_field_by_id(hdr, fid); - bug_on(!func); field->func.update_field = func->update_field; @@ -588,11 +583,11 @@ void proto_hdr_field_func_add(struct proto_hdr *hdr, uint32_t fid, if (func->type & PROTO_FIELD_FUNC_MIN) field->func.val = func->min; else if (field->len == 1) - field->func.val = proto_hdr_field_get_u8(hdr, fid); + field->func.val = proto_field_get_u8(field); else if (field->len == 2) - field->func.val = proto_hdr_field_get_u16(hdr, fid); + field->func.val = proto_field_get_u16(field); else if (field->len == 4) - field->func.val = proto_hdr_field_get_u32(hdr, fid); + field->func.val = proto_field_get_u32(field); else if (field->len > 4) { uint8_t *bytes = __proto_field_get_bytes(field); diff --git a/trafgen_proto.h b/trafgen_proto.h index d4427e6..29d68db 100644 --- a/trafgen_proto.h +++ b/trafgen_proto.h @@ -66,7 +66,9 @@ struct proto_field_func { uint32_t min; uint32_t max; int32_t inc; + uint16_t offset; uint32_t val; + size_t len; void (*update_field)(struct proto_field *field); }; @@ -142,9 +144,6 @@ extern void proto_hdr_field_set_default_dev_ipv6(struct proto_hdr *hdr, uint32_t extern void proto_field_dyn_apply(struct proto_field *field); -extern void proto_hdr_field_func_add(struct proto_hdr *hdr, uint32_t fid, - struct proto_field_func *func); - extern struct proto_field *proto_hdr_field_by_id(struct proto_hdr *hdr, uint32_t fid); @@ -157,4 +156,7 @@ extern uint32_t proto_field_get_u32(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_func_add(struct proto_field *field, + struct proto_field_func *func); + #endif /* TRAFGEN_PROTO_H */ -- cgit v1.2.3-54-g00ecf