summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Kochan <vadim4j@gmail.com>2016-12-18 11:52:49 +0200
committerTobias Klauser <tklauser@distanz.ch>2016-12-21 16:57:53 +0100
commit647b7b76d63f8c847b17495e6ad24dc3b256899f (patch)
tree4d4d488a0f65118cdaf45f381277408b9797364a
parent44e97b2009dc2bee93f25684b274f458f50ea667 (diff)
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 <vadim4j@gmail.com> Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
-rw-r--r--trafgen_parser.y168
-rw-r--r--trafgen_proto.c27
-rw-r--r--trafgen_proto.h8
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 */