On 28 Jun 2024, at 18:40, Adrián Moreno wrote:
> On Wed, Jun 26, 2024 at 02:11:51PM GMT, Eelco Chaudron wrote: >> On 5 Jun 2024, at 22:23, Adrian Moreno wrote: >> >>> Use the newly added emit_sample to implement OpenFlow sample() actions >>> with local sampling configuration. >> >> See some comments below. >> >> Cheers, >> >> Eelco >> >>> Signed-off-by: Adrian Moreno <amore...@redhat.com> >>> --- >>> ofproto/ofproto-dpif-lsample.c | 17 ++++ >>> ofproto/ofproto-dpif-lsample.h | 6 ++ >>> ofproto/ofproto-dpif-xlate.c | 163 ++++++++++++++++++++++++--------- >>> ofproto/ofproto-dpif-xlate.h | 3 +- >>> ofproto/ofproto-dpif.c | 2 +- >>> 5 files changed, 144 insertions(+), 47 deletions(-) >>> >>> diff --git a/ofproto/ofproto-dpif-lsample.c b/ofproto/ofproto-dpif-lsample.c >>> index 7bdafac19..2c0b5da89 100644 >>> --- a/ofproto/ofproto-dpif-lsample.c >>> +++ b/ofproto/ofproto-dpif-lsample.c >>> @@ -139,6 +139,23 @@ dpif_lsample_set_options(struct dpif_lsample *lsample, >>> return changed; >>> } >>> >>> +/* Returns the group_id of the exporter with the given collector_set_id, >>> if it >>> + * exists. */ >> >> nit: The below will fit on one line >> >> /* Returns the exporter group_id for a given collector_set_id, if it exists. >> */ >> > > Ack. > >>> +bool >>> +dpif_lsample_get_group_id(struct dpif_lsample *ps, uint32_t >>> collector_set_id, >>> + uint32_t *group_id) >>> +{ >>> + struct lsample_exporter_node *node; >>> + bool found = false; >>> + >>> + node = dpif_lsample_find_exporter_node(ps, collector_set_id); >>> + if (node) { >>> + found = true; >>> + *group_id = node->exporter.options.group_id; >>> + } >>> + return found; >>> +} >>> + >>> struct dpif_lsample * >>> dpif_lsample_create(void) >>> { >>> diff --git a/ofproto/ofproto-dpif-lsample.h b/ofproto/ofproto-dpif-lsample.h >>> index c23ea8372..f13425575 100644 >>> --- a/ofproto/ofproto-dpif-lsample.h >>> +++ b/ofproto/ofproto-dpif-lsample.h >>> @@ -19,6 +19,7 @@ >>> >>> #include <stdbool.h> >>> #include <stdlib.h> >>> +#include <stdint.h> >> >> Maybe add in alphabetical order. >> > > Ack. > >>> struct dpif_lsample; >>> struct ofproto_lsample_options; >>> @@ -31,4 +32,9 @@ bool dpif_lsample_set_options(struct dpif_lsample *, >>> const struct ofproto_lsample_options *, >>> size_t n_opts); >>> >>> +bool dpif_lsample_get_group_id(struct dpif_lsample *, >>> + uint32_t collector_set_id, >>> + uint32_t *group_id); >>> + >>> #endif /* OFPROTO_DPIF_LSAMPLE_H */ >>> + >> >> Accedantely added a newline? >> > > Ack. > >>> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c >>> index 7c4950895..5bd215d31 100644 >>> --- a/ofproto/ofproto-dpif-xlate.c >>> +++ b/ofproto/ofproto-dpif-xlate.c >>> @@ -47,6 +47,7 @@ >>> #include "ofproto/ofproto-dpif-ipfix.h" >>> #include "ofproto/ofproto-dpif-mirror.h" >>> #include "ofproto/ofproto-dpif-monitor.h" >>> +#include "ofproto/ofproto-dpif-lsample.h" >>> #include "ofproto/ofproto-dpif-sflow.h" >>> #include "ofproto/ofproto-dpif-trace.h" >>> #include "ofproto/ofproto-dpif-xlate-cache.h" >>> @@ -117,6 +118,7 @@ struct xbridge { >>> struct dpif_sflow *sflow; /* SFlow handle, or null. */ >>> struct dpif_ipfix *ipfix; /* Ipfix handle, or null. */ >>> struct netflow *netflow; /* Netflow handle, or null. */ >>> + struct dpif_lsample *lsample; /* Local sample handle, or null. */ >>> struct stp *stp; /* STP or null if disabled. */ >>> struct rstp *rstp; /* RSTP or null if disabled. */ >>> >>> @@ -687,6 +689,7 @@ static void xlate_xbridge_set(struct xbridge *, struct >>> dpif *, >>> const struct dpif_sflow *, >>> const struct dpif_ipfix *, >>> const struct netflow *, >>> + const struct dpif_lsample *, >>> bool forward_bpdu, bool has_in_band, >>> const struct dpif_backer_support *, >>> const struct xbridge_addr *); >>> @@ -1070,6 +1073,7 @@ xlate_xbridge_set(struct xbridge *xbridge, >>> const struct dpif_sflow *sflow, >>> const struct dpif_ipfix *ipfix, >>> const struct netflow *netflow, >>> + const struct dpif_lsample *lsample, >> >> nit: I would move above netflow, as you also do the actual init/unref before >> netflow. > > Ack. > >>> bool forward_bpdu, bool has_in_band, >>> const struct dpif_backer_support *support, >>> const struct xbridge_addr *addr) >>> @@ -1099,6 +1103,11 @@ xlate_xbridge_set(struct xbridge *xbridge, >>> xbridge->ipfix = dpif_ipfix_ref(ipfix); >>> } >>> >>> + if (xbridge->lsample != lsample) { >>> + dpif_lsample_unref(xbridge->lsample); >>> + xbridge->lsample = dpif_lsample_ref(lsample); >>> + } >>> + >>> if (xbridge->stp != stp) { >>> stp_unref(xbridge->stp); >>> xbridge->stp = stp_ref(stp); >>> @@ -1214,8 +1223,9 @@ xlate_xbridge_copy(struct xbridge *xbridge) >>> xbridge->dpif, xbridge->ml, xbridge->stp, >>> xbridge->rstp, xbridge->ms, xbridge->mbridge, >>> xbridge->sflow, xbridge->ipfix, xbridge->netflow, >>> - xbridge->forward_bpdu, xbridge->has_in_band, >>> - &xbridge->support, xbridge->addr); >>> + xbridge->lsample, xbridge->forward_bpdu, >>> + xbridge->has_in_band, &xbridge->support, >>> + xbridge->addr); >>> LIST_FOR_EACH (xbundle, list_node, &xbridge->xbundles) { >>> xlate_xbundle_copy(new_xbridge, xbundle); >>> } >>> @@ -1373,6 +1383,7 @@ xlate_ofproto_set(struct ofproto_dpif *ofproto, const >>> char *name, >>> const struct dpif_sflow *sflow, >>> const struct dpif_ipfix *ipfix, >>> const struct netflow *netflow, >>> + const struct dpif_lsample *lsample, >> >> nit: move before netflow. >> > > Ack. > >>> bool forward_bpdu, bool has_in_band, >>> const struct dpif_backer_support *support) >>> { >>> @@ -1396,7 +1407,7 @@ xlate_ofproto_set(struct ofproto_dpif *ofproto, const >>> char *name, >>> old_addr = xbridge->addr; >>> >>> xlate_xbridge_set(xbridge, dpif, ml, stp, rstp, ms, mbridge, sflow, >>> ipfix, >>> - netflow, forward_bpdu, has_in_band, support, >>> + netflow, lsample, forward_bpdu, has_in_band, support, >>> xbridge_addr); >>> >>> if (xbridge_addr != old_addr) { >>> @@ -1428,6 +1439,7 @@ xlate_xbridge_remove(struct xlate_cfg *xcfg, struct >>> xbridge *xbridge) >>> mbridge_unref(xbridge->mbridge); >>> dpif_sflow_unref(xbridge->sflow); >>> dpif_ipfix_unref(xbridge->ipfix); >>> + dpif_lsample_unref(xbridge->lsample); >>> netflow_unref(xbridge->netflow); >>> stp_unref(xbridge->stp); >>> rstp_unref(xbridge->rstp); >>> @@ -3357,6 +3369,11 @@ xlate_normal(struct xlate_ctx *ctx) >>> } >>> } >>> >>> +struct emit_sample_args { >>> + uint32_t group_id; >>> + struct ofpbuf cookie; >>> +}; >> >> nit: I like the structs to be defined at the top of the file. Not sure what >> the preferred place is. >> > > Given this struct is only used to pass parameters to the function > inmediately below, it seems kind of self-contained. But I agree at the > top might also be OK. > >>> /* Appends a "sample" action for sFlow or IPFIX to 'ctx->odp_actions'. The >>> * 'probability' is the number of packets out of UINT32_MAX to sample. The >>> * 'cookie' is passed back in the callback for each sampled packet. >>> @@ -3370,7 +3387,8 @@ xlate_normal(struct xlate_ctx *ctx) >>> static size_t >>> compose_sample_action(struct xlate_ctx *ctx, >>> const uint32_t probability, >>> - const struct user_action_cookie *cookie, >>> + const struct user_action_cookie *upcall, >> >> Guess the parameter is still a cookie, so it makes not sense to rename it to >> upcall. If you want to add more meaning you could call it user_cookie. If you >> do you need to update the help text above. >> > > I've refactored this part in the next version to reduce the amount of > arguments and have a more readable argument generation. > >>> + const struct emit_sample_args *emit, >>> const odp_port_t tunnel_out_port, >>> bool include_actions) >>> { >>> @@ -3379,14 +3397,20 @@ compose_sample_action(struct xlate_ctx *ctx, >>> return 0; >>> } >>> >>> + /* At least one of upcall or emit_sample config must be provided. */ >>> + ovs_assert(upcall || emit); >>> + >>> /* If the slow path meter is configured by the controller, >>> * insert a meter action before the user space action. */ >>> struct ofproto *ofproto = &ctx->xin->ofproto->up; >>> uint32_t meter_id = ofproto->slowpath_meter_id; >>> + size_t cookie_offset = 0; >>> >>> /* When meter action is not required, avoid generate sample action >>> * for 100% sampling rate. */ >>> - bool is_sample = probability < UINT32_MAX || meter_id != UINT32_MAX; >>> + bool is_sample = (probability < UINT32_MAX || >>> + (upcall && meter_id != UINT32_MAX)); >> >> Maybe update the help message a bit to be clear the meter is only for the >> slow patch (userspace) action, and we also omit if sample for 100% >> probability. >> > > Ack. > >>> size_t sample_offset = 0, actions_offset = 0; >>> if (is_sample) { >>> sample_offset = nl_msg_start_nested(ctx->odp_actions, >>> @@ -3397,19 +3421,26 @@ compose_sample_action(struct xlate_ctx *ctx, >>> OVS_SAMPLE_ATTR_ACTIONS); >>> } >>> >>> - if (meter_id != UINT32_MAX) { >>> - nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_METER, meter_id); >>> + if (emit) { >>> + odp_put_emit_sample_action(ctx->odp_actions, emit->group_id, >>> + emit->cookie.data, emit->cookie.size); >>> } >>> >>> - odp_port_t odp_port = ofp_port_to_odp_port( >>> - ctx->xbridge, ctx->xin->flow.in_port.ofp_port); >>> - uint32_t pid = dpif_port_get_pid(ctx->xbridge->dpif, odp_port); >>> - size_t cookie_offset; >>> - int res = odp_put_userspace_action(pid, cookie, sizeof *cookie, >>> - tunnel_out_port, include_actions, >>> - ctx->odp_actions, &cookie_offset); >>> - ovs_assert(res == 0); >>> - if (is_sample) { >>> + if (upcall) { >>> + if (meter_id != UINT32_MAX) { >>> + nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_METER, >>> meter_id); >>> + } >>> + >>> + odp_port_t odp_port = ofp_port_to_odp_port( >>> + ctx->xbridge, ctx->xin->flow.in_port.ofp_port); >>> + uint32_t pid = dpif_port_get_pid(ctx->xbridge->dpif, odp_port); >>> + int res = odp_put_userspace_action(pid, upcall, sizeof *upcall, >>> + tunnel_out_port, >>> include_actions, >>> + ctx->odp_actions, >>> &cookie_offset); >>> + ovs_assert(res == 0); >>> + } >>> + >>> + if (actions_offset) { >> >> Why is if (sample) no longer used, it makes more sense. >> > > Sure, we can change this for "if (is_sample) {" > >>> nl_msg_end_nested(ctx->odp_actions, actions_offset); >>> nl_msg_end_nested(ctx->odp_actions, sample_offset); >>> } >>> @@ -3440,7 +3471,7 @@ compose_sflow_action(struct xlate_ctx *ctx) >>> cookie.ofproto_uuid = ctx->xbridge->ofproto->uuid; >>> >>> return compose_sample_action(ctx, dpif_sflow_get_probability(sflow), >>> - &cookie, ODPP_NONE, true); >>> + &cookie, NULL, ODPP_NONE, true); >>> } >>> >>> /* If flow IPFIX is enabled, make sure IPFIX flow sample action >>> @@ -3490,7 +3521,7 @@ compose_ipfix_action(struct xlate_ctx *ctx, >>> odp_port_t output_odp_port) >>> >>> compose_sample_action(ctx, >>> >>> dpif_ipfix_get_bridge_exporter_probability(ipfix), >>> - &cookie, tunnel_out_port, false); >>> + &cookie, NULL, tunnel_out_port, false); >>> } >>> >>> /* Fix "sample" action according to data collected while composing ODP >>> actions, >>> @@ -5847,23 +5878,15 @@ xlate_fin_timeout(struct xlate_ctx *ctx, >>> } >>> >>> static void >>> -xlate_sample_action(struct xlate_ctx *ctx, >>> - const struct ofpact_sample *os) >>> +xlate_fill_ipfix_sample(struct xlate_ctx *ctx, >>> + const struct ofpact_sample *os, >>> + const struct dpif_ipfix *ipfix, >>> + struct user_action_cookie *cookie, >>> + odp_port_t *tunnel_out_port) >>> { >>> odp_port_t output_odp_port = ODPP_NONE; >>> - odp_port_t tunnel_out_port = ODPP_NONE; >>> - struct dpif_ipfix *ipfix = ctx->xbridge->ipfix; >>> bool emit_set_tunnel = false; >>> >>> - if (!ipfix) { >>> - return; >>> - } >>> - >>> - /* Scale the probability from 16-bit to 32-bit while representing >>> - * the same percentage. */ >>> - uint32_t probability = >>> - ((uint32_t) os->probability << 16) | os->probability; >>> - >>> /* If ofp_port in flow sample action is equel to ofp_port, >>> * this sample action is a input port action. */ >>> if (os->sampling_port != OFPP_NONE && >>> @@ -5879,7 +5902,7 @@ xlate_sample_action(struct xlate_ctx *ctx, >>> if (dpif_ipfix_get_flow_exporter_tunnel_sampling(ipfix, >>> >>> os->collector_set_id) >>> && dpif_ipfix_is_tunnel_port(ipfix, output_odp_port)) { >>> - tunnel_out_port = output_odp_port; >>> + *tunnel_out_port = output_odp_port; >>> emit_set_tunnel = true; >>> } >>> } >>> @@ -5913,20 +5936,70 @@ xlate_sample_action(struct xlate_ctx *ctx, >>> } >>> } >>> >>> - struct user_action_cookie cookie; >>> + cookie->type = USER_ACTION_COOKIE_FLOW_SAMPLE; >>> + cookie->ofp_in_port = ctx->xin->flow.in_port.ofp_port; >>> + cookie->ofproto_uuid = ctx->xbridge->ofproto->uuid; >>> + cookie->flow_sample.probability = os->probability; >>> + cookie->flow_sample.collector_set_id = os->collector_set_id; >>> + cookie->flow_sample.obs_domain_id = os->obs_domain_id; >>> + cookie->flow_sample.obs_point_id = os->obs_point_id; >>> + cookie->flow_sample.output_odp_port = output_odp_port; >>> + cookie->flow_sample.direction = os->direction; >>> +} >>> >>> - memset(&cookie, 0, sizeof cookie); >> >> Why does is the memset() removed from the new code? Are we sure we are >> setting all the fields? >> >>> - cookie.type = USER_ACTION_COOKIE_FLOW_SAMPLE; >>> - cookie.ofp_in_port = ctx->xin->flow.in_port.ofp_port; >>> - cookie.ofproto_uuid = ctx->xbridge->ofproto->uuid; >>> - cookie.flow_sample.probability = os->probability; >>> - cookie.flow_sample.collector_set_id = os->collector_set_id; >>> - cookie.flow_sample.obs_domain_id = os->obs_domain_id; >>> - cookie.flow_sample.obs_point_id = os->obs_point_id; >>> - cookie.flow_sample.output_odp_port = output_odp_port; >>> - cookie.flow_sample.direction = os->direction; >>> - >>> - compose_sample_action(ctx, probability, &cookie, tunnel_out_port, >>> false); >>> +static void >>> +xlate_sample_action(struct xlate_ctx *ctx, >>> + const struct ofpact_sample *os) >>> +{ >>> + uint8_t cookie_buf[sizeof(os->obs_domain_id) + >>> sizeof(os->obs_point_id)]; >>> + struct dpif_lsample *lsample = ctx->xbridge->lsample; >>> + struct dpif_ipfix *ipfix = ctx->xbridge->ipfix; >>> + struct emit_sample_args emit_sample_args; >>> + struct user_action_cookie upcall_cookie; >> >> As the action is called userspace we might just want to call the cookie as >> such for consistency, i.e. user_cookie/userspace_cookie. >> > > This will change in next version and I think it will have better > names... I said "I think" :-). > >>> + odp_port_t tunnel_out_port = ODPP_NONE; >>> + bool emit_sample = false; >>> + uint32_t group_id; >>> + >>> + if (!ipfix && !lsample) { >>> + return; >>> + } >>> + >>> + /* Scale the probability from 16-bit to 32-bit while representing >>> + * the same percentage. */ >>> + uint32_t probability = >>> + ((uint32_t) os->probability << 16) | os->probability; >>> + >>> + if (ipfix) { >>> + xlate_fill_ipfix_sample(ctx, os, ipfix, &upcall_cookie, >>> + &tunnel_out_port); >>> + } >> >> New line here. >> > > Ack. > >>> + if (lsample) { >>> + if (dpif_lsample_get_group_id(lsample, >>> + os->collector_set_id, >>> + &group_id)) { >> >> Maybe just do &emit_sample_args.group_id, it saves the variable and setting >> it >> below. Also all the ofbuf_xx() function are in order ;) >> >>> + emit_sample = true; >>> + ofpbuf_use_stub(&emit_sample_args.cookie, cookie_buf, >>> + sizeof cookie_buf); >>> + >>> + emit_sample_args.group_id = group_id; >>> + ofpbuf_put(&emit_sample_args.cookie, &os->obs_domain_id, >>> + sizeof(os->obs_domain_id)); >>> + ofpbuf_put(&emit_sample_args.cookie, &os->obs_point_id, >>> + sizeof(os->obs_point_id)); >> >> Guess the endianness discussion needs to be fixed here. >> > > Yes. > >>> + } >> >> Is the dpif_lsample_get_group_id() a common case? Do we need a log message or >> coverage counter? >> > > You mean for samples for which we cannot find a group_id? Yes, the corner case. >>> + } >>> + >>> + if (!ipfix && !emit_sample) { >>> + return; >>> + } >>> + >>> + compose_sample_action(ctx, probability, ipfix ? &upcall_cookie : NULL, >>> + emit_sample ? &emit_sample_args : NULL, >>> + tunnel_out_port, false); >>> + >>> + if (emit_sample) { >>> + ofpbuf_uninit(&emit_sample_args.cookie); >>> + } >>> } >>> >>> /* Determine if an datapath action translated from the openflow action >>> diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h >>> index 05b46fb26..164ff3713 100644 >>> --- a/ofproto/ofproto-dpif-xlate.h >>> +++ b/ofproto/ofproto-dpif-xlate.h >>> @@ -177,7 +177,8 @@ void xlate_ofproto_set(struct ofproto_dpif *, const >>> char *name, struct dpif *, >>> struct rstp *, const struct mcast_snooping *, >>> const struct mbridge *, const struct dpif_sflow *, >>> const struct dpif_ipfix *, const struct netflow *, >>> - bool forward_bpdu, bool has_in_band, >>> + const struct dpif_lsample *, bool forward_bpdu, >> >> Maybe move it after dpif_sflow to be consistent. >> > > Ack. > >>> + bool has_in_band, >>> const struct dpif_backer_support *support); >>> void xlate_remove_ofproto(struct ofproto_dpif *); >>> struct ofproto_dpif *xlate_ofproto_lookup(const struct uuid *uuid); >>> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c >>> index 067f60df3..48167751f 100644 >>> --- a/ofproto/ofproto-dpif.c >>> +++ b/ofproto/ofproto-dpif.c >>> @@ -485,7 +485,7 @@ type_run(const char *type) >>> ofproto->backer->dpif, ofproto->ml, >>> ofproto->stp, ofproto->rstp, ofproto->ms, >>> ofproto->mbridge, ofproto->sflow, >>> ofproto->ipfix, >>> - ofproto->netflow, >>> + ofproto->netflow, ofproto->lsample, >>> ofproto->up.forward_bpdu, >>> connmgr_has_in_band(ofproto->up.connmgr), >>> &ofproto->backer->rt_support); >>> -- >>> 2.45.1 >> _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev