On Thu, Aug 11, 2016 at 1:30 PM, Tobias Klauser <tklau...@distanz.ch> wrote: > On 2016-08-11 at 00:57:03 +0200, Vadim Kochan <vadi...@gmail.com> wrote: >> 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 (this >> trick is used for increment MAC/IPv6 addresses). >> >> 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). > > I'd split this patch into two: > > 1) Introduce generic infrastructure to dynamically update protocol > fields at runtime (which will then be used by the inc and rnd > functionality) > 2) Increment functionality > > And as mentioned in [1], I'd like to do the proto_ops/proto_hdr split > before applying this series as it further extends the current struct > proto_hdr with both static and runtime information. > > [1] https://groups.google.com/forum/#!msg/netsniff-ng/20RvwJdh50Y/eMkbmKSaBgAJ > > I'll send the RFC patch later today and would like to ask you to - if > the patch makes sense to you and you agree with it - to rebase v3 of > this series on top of it. > > Some more minor comments inline, but in general this looks good. > >> Signed-off-by: Vadim Kochan <vadi...@gmail.com> >> --- >> trafgen.c | 9 +++++++ >> trafgen_conf.h | 7 +++++ >> trafgen_proto.c | 84 >> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> trafgen_proto.h | 26 ++++++++++++++++++ >> 4 files changed, 126 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; > > This should be size_t as well. > >> }; >> >> 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; > > The double negation shouldn't be necessary. > >> +} >> + >> 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 4219794..72dbad3 100644 >> --- a/trafgen_proto.c >> +++ b/trafgen_proto.c >> @@ -407,6 +407,19 @@ void protos_init(const char *dev) >> protos_l4_init(); >> } >> >> +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 = current_packet()->headers; >> @@ -421,3 +434,74 @@ void proto_packet_finish(void) >> p->packet_finish(p); >> } >> } >> + >> +static inline unsigned int field_inc(struct proto_field *field) > > return type should be uint32_t > >> +{ >> + uint32_t min = field->func.min; >> + uint32_t max = field->func.max; >> + uint32_t val = field->func.val; >> + uint32_t inc = field->func.inc; >> + uint32_t next; >> + >> + next = (val + inc) % (max + 1); >> + field->func.val = max(next, min); >> + >> + return val; >> +} >> + >> +static void field_inc_func(struct proto_field *field) >> +{ >> + if (field->len == 1) { >> + proto_field_set_u8(field->hdr, field->id, field_inc(field)); >> + } else if (field->len == 2) { >> + proto_field_set_be16(field->hdr, field->id, field_inc(field)); >> + } else if (field->len == 4) { >> + proto_field_set_be32(field->hdr, field->id, field_inc(field)); >> + } else if (field->len > 4) { >> + uint8_t *bytes = __proto_field_get_bytes(field); >> + >> + bytes += field->len - 4; >> + >> + *(uint32_t *)bytes = bswap_32(field_inc(field)); >> + } >> +} >> + >> +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)); > > I'd rather have an explicit assignment of the respective members here, > i.e. type, inc, min, max. And set val and update_field explicitely to > 0/NULL. > >> + >> + field->func.max = field->func.max ?: UINT32_MAX - 1; > > Shouldnt't this be UINT32_MAX (without the -1)?
The reason is just because in field_inc function I use the following: next = (val + inc) % (max + 1); and in case when max == UINT32_MAX I will get division by 0. If you dont like UINT32_MAX - 1 then I will try to handle max + 1 overflow somehow differently ... > >> + >> + if (func->type & PROTO_FIELD_FUNC_INC) { >> + if (func->type & PROTO_FIELD_FUNC_MIN) >> + field->func.val = func->min; >> + else 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); >> + } >> + >> + 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 dbba700..2b48c68 100644 >> --- a/trafgen_proto.h >> +++ b/trafgen_proto.h >> @@ -27,8 +27,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; >> @@ -37,6 +53,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; >> @@ -55,7 +72,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); > > Is it necessary to pass the struct proto_hdr here? Isn't it always > field->hdr? > >> 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); >> }; >> >> @@ -65,6 +84,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); >> >> @@ -111,4 +132,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.9.2 >> -- 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.