Extended 'struct packet_dyn' with proto fields which has dynamically changing values at runtime.
Implement incrementing of proto field at runtime with min & max parameters, by default if the 'min' parameter is not specified then original value is used. For fields which len is greater than 4 - last 4 bytes are incremented as unsigned int value. Added 'field_changed' callback for proto header which may be used for check if csum updating is needed. This callback is called after field was changed at runtime. Added 'packet_update' callback to let proto header know when to apply final proto header changes at runtime (csum update). Signed-off-by: Vadim Kochan <vadi...@gmail.com> --- trafgen.c | 9 ++++++ trafgen_conf.h | 7 ++++ trafgen_proto.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ trafgen_proto.h | 26 +++++++++++++++ 4 files changed, 141 insertions(+) diff --git a/trafgen.c b/trafgen.c index b76b5d7..553dfa5 100644 --- a/trafgen.c +++ b/trafgen.c @@ -619,6 +619,15 @@ static inline void packet_apply_dyn_elements(int idx) apply_randomizer(idx); apply_csum16(idx); } + + if (packet_dyn_has_fields(&packet_dyn[idx])) { + uint32_t i; + + for (i = 0; i < packet_dyn[idx].flen; i++) + proto_field_dyn_apply(packet_dyn[idx].fields[i]); + + proto_packet_update(idx); + } } static void xmit_slowpath_or_die(struct ctx *ctx, unsigned int cpu, unsigned long orig_num) diff --git a/trafgen_conf.h b/trafgen_conf.h index 934f8fe..7f3616c 100644 --- a/trafgen_conf.h +++ b/trafgen_conf.h @@ -49,6 +49,8 @@ struct packet_dyn { size_t rlen; struct csum16 *csum; size_t slen; + struct proto_field **fields; + uint32_t flen; }; static inline bool packet_dyn_has_elems(struct packet_dyn *p) @@ -61,6 +63,11 @@ static inline bool packet_dyn_has_only_csums(struct packet_dyn *p) return (p->clen == 0 && p->rlen == 0 && p->slen); } +static inline bool packet_dyn_has_fields(struct packet_dyn *p) +{ + return !!p->flen; +} + extern void compile_packets_str(char *str, bool verbose, unsigned int cpu); extern void compile_packets(char *file, bool verbose, unsigned int cpu, bool invoke_cpp, char *const cpp_argv[]); diff --git a/trafgen_proto.c b/trafgen_proto.c index ce389ce..069aa00 100644 --- a/trafgen_proto.c +++ b/trafgen_proto.c @@ -419,6 +419,19 @@ void protos_init(const char *dev) p->ctx = &ctx; } +void proto_packet_update(uint32_t idx) +{ + struct packet *pkt = packet_get(idx); + ssize_t i; + + for (i = pkt->headers_count - 1; i >= 0; i--) { + struct proto_hdr *hdr = pkt->headers[i]; + + if (hdr->packet_update) + hdr->packet_update(hdr); + } +} + void proto_packet_finish(void) { struct proto_hdr **headers = ¤t_packet()->headers[0]; @@ -433,3 +446,89 @@ void proto_packet_finish(void) p->packet_finish(p); } } + +static inline unsigned int field_inc(struct proto_field *field) +{ + uint32_t val; + + val = field->func.val - field->func.min; + val = (val + field->func.inc) % field->func.max; + field->func.val = val + field->func.min; + + return field->func.val; +} + +static void field_inc_func(struct proto_field *field) +{ + if (field->len == 1) { + uint8_t val; + + val = field_inc(field); + proto_field_set_u8(field->hdr, field->id, val); + } else if (field->len == 2) { + uint16_t val; + + val = field_inc(field); + proto_field_set_be16(field->hdr, field->id, val); + } else if (field->len == 4) { + uint32_t val; + + val = field_inc(field); + proto_field_set_be32(field->hdr, field->id, val); + } else if (field->len > 4) { + uint8_t *bytes = __proto_field_get_bytes(field); + uint32_t val; + + bytes += field->len - 4; + val = field_inc(field); + + *(uint32_t *)bytes = bswap_32(val); + } +} + +void proto_field_func_add(struct proto_hdr *hdr, uint32_t fid, + struct proto_field_func *func) +{ + struct proto_field *field = proto_field_by_id(hdr, fid); + + bug_on(!func); + + memcpy(&field->func, func, sizeof(*func)); + + if (func->type & PROTO_FIELD_FUNC_INC) { + if (field->len == 1) + field->func.val = proto_field_get_u8(hdr, fid); + else if (field->len == 2) + field->func.val = proto_field_get_u16(hdr, fid); + else if (field->len == 4) + field->func.val = proto_field_get_u32(hdr, fid); + else if (field->len > 4) { + uint8_t *bytes = __proto_field_get_bytes(field); + + bytes += field->len - 4; + field->func.val = bswap_32(*(uint32_t *)bytes); + } + + if (field->func.max) { + field->func.max = (field->func.max - field->func.min + + field->func.inc) ?: + 1; + } else { + field->func.max = (uint32_t)~0; + } + + if (func->type & PROTO_FIELD_FUNC_MIN) + field->func.val = field->func.min; + + field->func.update_field = field_inc_func; + } +} + +void proto_field_dyn_apply(struct proto_field *field) +{ + if (field->func.update_field) + field->func.update_field(field); + + if (field->hdr->field_changed) + field->hdr->field_changed(field->hdr, field); +} diff --git a/trafgen_proto.h b/trafgen_proto.h index 41e5b76..64f4366 100644 --- a/trafgen_proto.h +++ b/trafgen_proto.h @@ -32,8 +32,24 @@ enum proto_layer { PROTO_L4, }; +struct proto_field; struct proto_hdr; +enum proto_field_func_t { + PROTO_FIELD_FUNC_INC = 1 << 0, + PROTO_FIELD_FUNC_MIN = 1 << 1, +}; + +struct proto_field_func { + enum proto_field_func_t type; + uint32_t min; + uint32_t max; + int32_t inc; + uint32_t val; + + void (* update_field)(struct proto_field *field); +}; + struct proto_field { uint32_t id; size_t len; @@ -42,6 +58,7 @@ struct proto_field { /* might be negative (e.g. VLAN TPID field) */ int16_t offset; + struct proto_field_func func; bool is_set; uint16_t pkt_offset; struct proto_hdr *hdr; @@ -61,7 +78,9 @@ struct proto_hdr { void (*header_init)(struct proto_hdr *hdr); void (*header_finish)(struct proto_hdr *hdr); + void (*field_changed)(struct proto_hdr *hdr, struct proto_field *field); void (*packet_finish)(struct proto_hdr *hdr); + void (*packet_update)(struct proto_hdr *hdr); void (*set_next_proto)(struct proto_hdr *hdr, enum proto_id pid); }; @@ -71,6 +90,8 @@ extern void proto_header_register(struct proto_hdr *hdr); extern struct proto_hdr *proto_header_init(enum proto_id pid); extern void proto_header_finish(struct proto_hdr *hdr); extern void proto_packet_finish(void); +extern void proto_packet_update(uint32_t idx); + extern struct proto_hdr *proto_lower_default_add(struct proto_hdr *hdr, enum proto_id pid); @@ -117,4 +138,9 @@ extern void proto_field_set_default_dev_ipv4(struct proto_hdr *hdr, uint32_t fid extern void proto_field_set_dev_ipv6(struct proto_hdr *hdr, uint32_t fid); extern void proto_field_set_default_dev_ipv6(struct proto_hdr *hdr, uint32_t fid); +extern void proto_field_dyn_apply(struct proto_field *field); + +extern void proto_field_func_add(struct proto_hdr *hdr, uint32_t fid, + struct proto_field_func *func); + #endif /* TRAFGEN_PROTO_H */ -- 2.6.3 -- You received this message because you are subscribed to the Google Groups "netsniff-ng" group. To unsubscribe from this group and stop receiving emails from it, send an email to netsniff-ng+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.