--- lib/odp-util.c | 14 ++++++++ lib/odp-util.h | 9 +++++- ofproto/ofproto-dpif.c | 86 ++++++++++++++++++++++++++++++++++++++++---------- tests/odp.at | 1 + 4 files changed, 93 insertions(+), 17 deletions(-)
diff --git a/lib/odp-util.c b/lib/odp-util.c index de97fd2..50feeb5 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -279,6 +279,11 @@ 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(obs_point_id=%"PRIu32")", + cookie.ipfix.obs_point_id); + break; + case USER_ACTION_COOKIE_UNSPEC: default: ds_put_format(ds, ",userdata=0x%"PRIx64, userdata); @@ -419,6 +424,7 @@ 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 obs_point_id; char userdata_s[32]; int vid, pcp; int n = -1; @@ -464,6 +470,14 @@ 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(obs_point_id=%lli))%n", + &pid, &obs_point_id, &n) > 0 && n > 0) { + union user_action_cookie cookie; + + cookie.type = USER_ACTION_COOKIE_IPFIX; + 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..44cde1d 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 unused; + 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 854ad29..c585038 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -3552,7 +3552,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; @@ -3580,6 +3580,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); @@ -3624,6 +3627,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) { @@ -3661,6 +3671,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; @@ -5268,6 +5283,30 @@ put_userspace_action(const struct ofproto_dpif *ofproto, return odp_put_userspace_action(pid, cookie, odp_actions); } +/* Compose SAMPLE action for sFlow or IPFIX. */ +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); + + /* Number of packets out of UINT_MAX to 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, @@ -5309,27 +5348,24 @@ 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(uint32_t obs_point_id, union user_action_cookie *cookie) +{ + cookie->type = USER_ACTION_COOKIE_IPFIX; + cookie->ipfix.obs_point_id = obs_point_id; } /* SAMPLE action must be first action in any given list of actions. @@ -5841,6 +5877,16 @@ xlate_fin_timeout(struct action_xlate_ctx *ctx, } } +static void +xlate_sample_action(struct action_xlate_ctx *ctx, + const struct ofpact_sample *os) +{ + union user_action_cookie cookie; + compose_ipfix_cookie(os->obs_point_id, &cookie); + compose_sample_action(ctx->ofproto, ctx->odp_actions, &ctx->flow, + os->probability, &cookie); +} + static bool may_receive(const struct ofport_dpif *port, struct action_xlate_ctx *ctx) { @@ -5869,6 +5915,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, const struct ofport_dpif *port; bool was_evictable = true; const struct ofpact *a; + int non_sample_actions_count = 0; port = get_ofp_port(ctx->ofproto, ctx->flow.in_port); if (port && !may_receive(port, ctx)) { @@ -6053,11 +6100,18 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, } case OFPACT_SAMPLE: - /* TODO: Check that SAMPLE actions are always the first - * actions in a flow. */ - /* TODO: Actually implement the translation here. */ + /* SAMPLE actions should be the first in a flow's actions. */ + if (non_sample_actions_count > 0) { + VLOG_WARN_RL(&rl, + "sample action not at beginning of action list"); + } + xlate_sample_action(ctx, ofpact_get_SAMPLE(a)); break; } + + if (a->type != OFPACT_SAMPLE) { + non_sample_actions_count++; + } } out: diff --git a/tests/odp.at b/tests/odp.at index a5f6dbe..bcc32bf 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(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.0.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev