Signed-off-by: Romain Lenglet <rleng...@vmware.com> --- lib/odp-util.c | 19 ++++++++++++ lib/odp-util.h | 9 +++++- ofproto/ofproto-dpif.c | 84 +++++++++++++++++++++++++++++++++++++++++--------- tests/odp.at | 1 + 4 files changed, 98 insertions(+), 15 deletions(-)
diff --git a/lib/odp-util.c b/lib/odp-util.c index 96a9523..c626e44 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -279,6 +279,13 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr) ds_put_format(ds, ")"); break; + case USER_ACTION_COOKIE_IPFIX: + ds_put_format(ds, ",IPFIX(probability=%"PRIu16 + ",obs_point_id=%"PRIu32")", + cookie.ipfix.probability, + cookie.ipfix.obs_point_id); + break; + case USER_ACTION_COOKIE_UNSPEC: default: ds_put_format(ds, ",userdata=0x%"PRIx64, userdata); @@ -419,6 +426,8 @@ parse_odp_action(const char *s, const struct simap *port_names, { unsigned long long int pid; unsigned long long int output; + unsigned long long int probability; + unsigned long long int obs_point_id; char userdata_s[32]; int vid, pcp; int n = -1; @@ -464,6 +473,16 @@ parse_odp_action(const char *s, const struct simap *port_names, odp_put_userspace_action(pid, &cookie, actions); return n; + } else if (sscanf(s, "userspace(pid=%lli,IPFIX(probability=%lli," + "obs_point_id=%lli))%n", + &pid, &probability, &obs_point_id, &n) > 0 && n > 0) { + union user_action_cookie cookie; + + cookie.type = USER_ACTION_COOKIE_IPFIX; + cookie.ipfix.probability = probability; + cookie.ipfix.obs_point_id = obs_point_id; + odp_put_userspace_action(pid, &cookie, actions); + return n; } else if (sscanf(s, "userspace(pid=%lli,userdata=" "%31[x0123456789abcdefABCDEF])%n", &pid, userdata_s, &n) > 0 && n > 0) { diff --git a/lib/odp-util.h b/lib/odp-util.h index 9d38f33..bcf4d0e 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -119,7 +119,8 @@ void commit_odp_actions(const struct flow *, struct flow *base, enum user_action_cookie_type { USER_ACTION_COOKIE_UNSPEC, USER_ACTION_COOKIE_SFLOW, /* Packet for sFlow sampling. */ - USER_ACTION_COOKIE_SLOW_PATH /* Userspace must process this flow. */ + USER_ACTION_COOKIE_SLOW_PATH, /* Userspace must process this flow. */ + USER_ACTION_COOKIE_IPFIX /* Packet for IPFIX sampling. */ }; /* user_action_cookie is passed as argument to OVS_ACTION_ATTR_USERSPACE. @@ -138,6 +139,12 @@ union user_action_cookie { uint16_t unused; uint32_t reason; /* enum slow_path_reason. */ } slow_path; + + struct { + uint16_t type; /* USER_ACTION_COOKIE_IPFIX. */ + uint16_t probability; /* Sampling probability. */ + uint32_t obs_point_id; /* Observation Point ID. */ + } ipfix; }; BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 8); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 6acce4f..3d9e769 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -3595,7 +3595,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls, hmap_destroy(&todo); } -static enum { SFLOW_UPCALL, MISS_UPCALL, BAD_UPCALL } +static enum { SFLOW_UPCALL, MISS_UPCALL, BAD_UPCALL, IPFIX_UPCALL } classify_upcall(const struct dpif_upcall *upcall) { union user_action_cookie cookie; @@ -3623,6 +3623,9 @@ classify_upcall(const struct dpif_upcall *upcall) case USER_ACTION_COOKIE_SLOW_PATH: return MISS_UPCALL; + case USER_ACTION_COOKIE_IPFIX: + return IPFIX_UPCALL; + case USER_ACTION_COOKIE_UNSPEC: default: VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64, upcall->userdata); @@ -3650,6 +3653,13 @@ handle_sflow_upcall(struct dpif_backer *backer, odp_in_port, &cookie); } +static void +handle_ipfix_upcall(struct dpif_backer *backer OVS_UNUSED, + const struct dpif_upcall *upcall OVS_UNUSED) +{ + /* TODO: Send an IPFIX sample. */ +} + static int handle_upcalls(struct dpif_backer *backer, unsigned int max_batch) { @@ -3687,6 +3697,11 @@ handle_upcalls(struct dpif_backer *backer, unsigned int max_batch) ofpbuf_uninit(buf); break; + case IPFIX_UPCALL: + handle_ipfix_upcall(backer, upcall); + ofpbuf_uninit(buf); + break; + case BAD_UPCALL: ofpbuf_uninit(buf); break; @@ -5294,6 +5309,32 @@ put_userspace_action(const struct ofproto_dpif *ofproto, return odp_put_userspace_action(pid, cookie, odp_actions); } +/* Compose SAMPLE action for sFlow or IPFIX. The given probability is + * the number of packets out of UINT32_MAX to sample. The given + * cookie is passed back in the callback for each sampled packet. + */ +static size_t +compose_sample_action(const struct ofproto_dpif *ofproto, + struct ofpbuf *odp_actions, + const struct flow *flow, + const uint32_t probability, + const union user_action_cookie *cookie) +{ + size_t sample_offset, actions_offset; + int cookie_offset; + + sample_offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SAMPLE); + + nl_msg_put_u32(odp_actions, OVS_SAMPLE_ATTR_PROBABILITY, probability); + + actions_offset = nl_msg_start_nested(odp_actions, OVS_SAMPLE_ATTR_ACTIONS); + cookie_offset = put_userspace_action(ofproto, odp_actions, flow, cookie); + + nl_msg_end_nested(odp_actions, actions_offset); + nl_msg_end_nested(odp_actions, sample_offset); + return cookie_offset; +} + static void compose_sflow_cookie(const struct ofproto_dpif *ofproto, ovs_be16 vlan_tci, uint32_t odp_port, @@ -5335,27 +5376,26 @@ compose_sflow_action(const struct ofproto_dpif *ofproto, { uint32_t probability; union user_action_cookie cookie; - size_t sample_offset, actions_offset; - int cookie_offset; if (!ofproto->sflow || flow->in_port == OFPP_NONE) { return 0; } - sample_offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SAMPLE); - - /* Number of packets out of UINT_MAX to sample. */ probability = dpif_sflow_get_probability(ofproto->sflow); - nl_msg_put_u32(odp_actions, OVS_SAMPLE_ATTR_PROBABILITY, probability); - - actions_offset = nl_msg_start_nested(odp_actions, OVS_SAMPLE_ATTR_ACTIONS); compose_sflow_cookie(ofproto, htons(0), odp_port, odp_port == OVSP_NONE ? 0 : 1, &cookie); - cookie_offset = put_userspace_action(ofproto, odp_actions, flow, &cookie); - nl_msg_end_nested(odp_actions, actions_offset); - nl_msg_end_nested(odp_actions, sample_offset); - return cookie_offset; + return compose_sample_action(ofproto, odp_actions, flow, probability, + &cookie); +} + +static void +compose_ipfix_cookie(uint16_t probability, uint32_t obs_point_id, + union user_action_cookie *cookie) +{ + cookie->type = USER_ACTION_COOKIE_IPFIX; + cookie->ipfix.probability = probability; + cookie->ipfix.obs_point_id = obs_point_id; } /* SAMPLE action must be first action in any given list of actions. @@ -5863,6 +5903,22 @@ xlate_fin_timeout(struct action_xlate_ctx *ctx, } } +static void +xlate_sample_ipfix_action(struct action_xlate_ctx *ctx, + const struct ofpact_sample_ipfix *osi) +{ + union user_action_cookie cookie; + /* Scale the probability from 16-bit to 32-bit while representing + * the exact same percentage. */ + uint32_t probability = (osi->probability << 16) | osi->probability; + + commit_odp_actions(&ctx->flow, &ctx->base_flow, ctx->odp_actions); + + compose_ipfix_cookie(osi->probability, osi->obs_point_id, &cookie); + compose_sample_action(ctx->ofproto, ctx->odp_actions, &ctx->flow, + probability, &cookie); +} + static bool may_receive(const struct ofport_dpif *port, struct action_xlate_ctx *ctx) { @@ -6075,7 +6131,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, } case OFPACT_SAMPLE_IPFIX: - /* TODO: Actually implement the translation here. */ + xlate_sample_ipfix_action(ctx, ofpact_get_SAMPLE_IPFIX(a)); break; } } diff --git a/tests/odp.at b/tests/odp.at index 687f9c9..85823c0 100644 --- a/tests/odp.at +++ b/tests/odp.at @@ -76,6 +76,7 @@ userspace(pid=9765,slow_path()) userspace(pid=9765,slow_path(cfm)) userspace(pid=9765,slow_path(cfm,match)) userspace(pid=9123,userdata=0x815309) +userspace(pid=6633,IPFIX(probability=123,obs_point_id=12345)) set(tun_id(0x7f10354)) set(in_port(2)) set(eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15)) -- 1.8.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev