On 2016-07-26 at 21:35:10 +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.
> 
> 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).

The documentation of these callbacks would also make sense where they're
defined.

> 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 = &current_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;

Shouldn't this be

        val = (val + field->func.inc) % (field->func.max - field->func.min + 1)

to be consistent with apply_counter()?

Also, I think you should probably get rid of as many pointer
dereferences as possible in these runtime functions, i.e. store max and
min in temporary variables.

> +     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);

Assignment on declaration please. Or even better:

                proto_field_set_u8(field->hdr, field->id, field_inc(field));

> +     } else if (field->len == 2) {
> +             uint16_t val;
> +
> +             val = field_inc(field);
> +             proto_field_set_be16(field->hdr, field->id, val);

Same.

> +     } else if (field->len == 4) {
> +             uint32_t val;
> +
> +             val = field_inc(field);
> +             proto_field_set_be32(field->hdr, field->id, val);

Same.

> +     } 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);

This part looks really odd. Did you actually verify it produces the
correct result on both big/little endian and for various field lengths?

To be honest I don't see much use for counters going beyond UINT32_T_MAX
(or maybe UINT64_T_MAX, which should be handled as a separate case if
then). Or do you know of a protocol with sequence numbers (or similar) >
64 bit for which this would really be useful?

> +     }
> +}
> +
> +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;

To me it is not entirely obvious why you do this here (I assume it has
something to do with reducing calculations at runtime?). In any case
this needs an explanatory comment.

> +             } else {
> +                     field->func.max = (uint32_t)~0;
> +             }
> +
> +             if (func->type & PROTO_FIELD_FUNC_MIN)
> +                     field->func.val = field->func.min;

Why does this need an own condition? Don't we expect to start
incrementing from the min value in any case?

> +
> +             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.

Reply via email to