[ovs-dev] [VLAN splinters 14/16] ofproto-dpif: Move ODP actions from facets to subfacets.
Ethan Jackson
ethan at nicira.com
Wed Nov 23 20:00:33 UTC 2011
Looks good to me.
It's too bad we have to do this. ofproto-dpif is getting pretty complicated.
Ethan
On Tue, Nov 15, 2011 at 17:17, Ben Pfaff <blp at nicira.com> wrote:
> This is a prerequisite for the upcoming VLAN splinter patch, because
> splinters and non-splintered subfacets might need slightly different
> actions due to the VLAN tag being initially different (present vs. absent).
>
> This is only desirable for use with VLAN splinters and should be reverted
> when this feature is no longer needed. I'm breaking it out here only to
> make the series easier to review.
> ---
> ofproto/ofproto-dpif.c | 204 +++++++++++++++++++++++++++++-------------------
> 1 files changed, 124 insertions(+), 80 deletions(-)
>
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index e8c12b1..167ec07 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -232,15 +232,14 @@ static struct ofpbuf *xlate_actions(struct action_xlate_ctx *,
> /* An exact-match instantiation of an OpenFlow flow.
> *
> * A facet associates a "struct flow", which represents the Open vSwitch
> - * userspace idea of an exact-match flow, with a set of datapath actions.
> - *
> - * A facet contains one or more subfacets. Each subfacet tracks the datapath's
> - * idea of the exact-match flow equivalent to the facet. When the kernel
> - * module (or other dpif implementation) and Open vSwitch userspace agree on
> - * the definition of a flow key, there is exactly one subfacet per facet. If
> - * the dpif implementation supports more-specific flow matching than userspace,
> - * however, a facet can have more than one subfacet, each of which corresponds
> - * to some distinction in flow that userspace simply doesn't understand.
> + * userspace idea of an exact-match flow, with one or more subfacets. Each
> + * subfacet tracks the datapath's idea of the exact-match flow equivalent to
> + * the facet. When the kernel module (or other dpif implementation) and Open
> + * vSwitch userspace agree on the definition of a flow key, there is exactly
> + * one subfacet per facet. If the dpif implementation supports more-specific
> + * flow matching than userspace, however, a facet can have more than one
> + * subfacet, each of which corresponds to some distinction in flow that
> + * userspace simply doesn't understand.
> *
> * Flow expiration works in terms of subfacets, so a facet must have at least
> * one subfacet or it will never expire, leaking memory. */
> @@ -281,12 +280,15 @@ struct facet {
> uint64_t accounted_bytes; /* Bytes processed by facet_account(). */
> struct netflow_flow nf_flow; /* Per-flow NetFlow tracking data. */
>
> - /* Datapath actions. */
> + /* Properties of datapath actions.
> + *
> + * Every subfacet has its own actions because actions can differ slightly
> + * between splintered and non-splintered subfacets due to the VLAN tag
> + * being initially different (present vs. absent). All of them have these
> + * properties in common so we just store one copy of them here. */
> bool may_install; /* Reassess actions for every packet? */
> bool has_learn; /* Actions include NXAST_LEARN? */
> bool has_normal; /* Actions output to OFPP_NORMAL? */
> - size_t actions_len; /* Number of bytes in actions[]. */
> - struct nlattr *actions; /* Datapath actions. */
> tag_type tags; /* Tags that would require revalidation. */
> };
>
> @@ -307,8 +309,6 @@ static bool execute_controller_action(struct ofproto_dpif *,
>
> static void facet_flush_stats(struct ofproto_dpif *, struct facet *);
>
> -static void facet_make_actions(struct ofproto_dpif *, struct facet *,
> - const struct ofpbuf *packet);
> static void facet_update_time(struct ofproto_dpif *, struct facet *,
> long long int used);
> static void facet_reset_counters(struct facet *);
> @@ -317,7 +317,7 @@ static void facet_account(struct ofproto_dpif *, struct facet *);
>
> static bool facet_is_controller_flow(struct facet *);
>
> -/* A dpif flow associated with a facet.
> +/* A dpif flow and actions associated with a facet.
> *
> * See also the large comment on struct subfacet. */
> struct subfacet {
> @@ -340,6 +340,13 @@ struct subfacet {
> uint64_t dp_packet_count; /* Last known packet count in the datapath. */
> uint64_t dp_byte_count; /* Last known byte count in the datapath. */
>
> + /* Datapath actions.
> + *
> + * These should be essentially identical for every subfacet in a facet, but
> + * may differ in trivial ways due to VLAN splinters. */
> + size_t actions_len; /* Number of bytes in actions[]. */
> + struct nlattr *actions; /* Datapath actions. */
> +
> bool installed; /* Installed in datapath? */
> };
>
> @@ -358,6 +365,8 @@ static void subfacet_update_time(struct ofproto_dpif *, struct subfacet *,
> long long int used);
> static void subfacet_update_stats(struct ofproto_dpif *, struct subfacet *,
> const struct dpif_flow_stats *);
> +static void subfacet_make_actions(struct ofproto_dpif *, struct subfacet *,
> + const struct ofpbuf *packet);
> static int subfacet_install(struct ofproto_dpif *, struct subfacet *,
> const struct nlattr *actions, size_t actions_len,
> struct dpif_flow_stats *);
> @@ -2248,12 +2257,12 @@ handle_flow_miss(struct ofproto_dpif *ofproto, struct flow_miss *miss,
> send_packet_in_miss(ofproto, packet, flow, true);
> }
>
> - if (!facet->may_install) {
> - facet_make_actions(ofproto, facet, packet);
> + if (!facet->may_install || !subfacet->actions) {
> + subfacet_make_actions(ofproto, subfacet, packet);
> }
> if (!execute_controller_action(ofproto, &facet->flow,
> - facet->actions, facet->actions_len,
> - packet)) {
> + subfacet->actions,
> + subfacet->actions_len, packet)) {
> struct flow_miss_op *op = &ops[(*n_ops)++];
> struct dpif_execute *execute = &op->dpif_op.execute;
>
> @@ -2263,9 +2272,9 @@ handle_flow_miss(struct ofproto_dpif *ofproto, struct flow_miss *miss,
> execute->key_len = miss->key_len;
> execute->actions
> = (facet->may_install
> - ? facet->actions
> - : xmemdup(facet->actions, facet->actions_len));
> - execute->actions_len = facet->actions_len;
> + ? subfacet->actions
> + : xmemdup(subfacet->actions, subfacet->actions_len));
> + execute->actions_len = subfacet->actions_len;
> execute->packet = packet;
> }
> }
> @@ -2279,8 +2288,8 @@ handle_flow_miss(struct ofproto_dpif *ofproto, struct flow_miss *miss,
> put->flags = DPIF_FP_CREATE | DPIF_FP_MODIFY;
> put->key = miss->key;
> put->key_len = miss->key_len;
> - put->actions = facet->actions;
> - put->actions_len = facet->actions_len;
> + put->actions = subfacet->actions;
> + put->actions_len = subfacet->actions_len;
> put->stats = NULL;
> }
> }
> @@ -2361,7 +2370,7 @@ handle_miss_upcalls(struct ofproto_dpif *ofproto, struct dpif_upcall *upcalls,
> switch (op->dpif_op.type) {
> case DPIF_OP_EXECUTE:
> execute = &op->dpif_op.execute;
> - if (op->subfacet->facet->actions != execute->actions) {
> + if (op->subfacet->actions != execute->actions) {
> free((struct nlattr *) execute->actions);
> }
> ofpbuf_delete((struct ofpbuf *) execute->packet);
> @@ -2681,9 +2690,6 @@ rule_expire(struct rule_dpif *rule)
> * 'flow' exists in 'ofproto' and that 'flow' is the best match for 'rule' in
> * the ofproto's classifier table.
> *
> - * The facet will initially have no ODP actions. The caller should fix that
> - * by calling facet_make_actions().
> - *
> * The facet will initially have no subfacets. The caller should create (at
> * least) one subfacet with subfacet_create(). */
> static struct facet *
> @@ -2708,7 +2714,6 @@ facet_create(struct rule_dpif *rule, const struct flow *flow)
> static void
> facet_free(struct facet *facet)
> {
> - free(facet->actions);
> free(facet);
> }
>
> @@ -2790,37 +2795,11 @@ facet_remove(struct ofproto_dpif *ofproto, struct facet *facet)
> facet_free(facet);
> }
>
> -/* Composes the datapath actions for 'facet' based on its rule's actions. */
> -static void
> -facet_make_actions(struct ofproto_dpif *p, struct facet *facet,
> - const struct ofpbuf *packet)
> -{
> - const struct rule_dpif *rule = facet->rule;
> - struct ofpbuf *odp_actions;
> - struct action_xlate_ctx ctx;
> -
> - action_xlate_ctx_init(&ctx, p, &facet->flow, packet);
> - odp_actions = xlate_actions(&ctx, rule->up.actions, rule->up.n_actions);
> - facet->tags = ctx.tags;
> - facet->may_install = ctx.may_set_up_flow;
> - facet->has_learn = ctx.has_learn;
> - facet->has_normal = ctx.has_normal;
> - facet->nf_flow.output_iface = ctx.nf_output_iface;
> -
> - if (facet->actions_len != odp_actions->size
> - || memcmp(facet->actions, odp_actions->data, odp_actions->size)) {
> - free(facet->actions);
> - facet->actions_len = odp_actions->size;
> - facet->actions = xmemdup(odp_actions->data, odp_actions->size);
> - }
> -
> - ofpbuf_delete(odp_actions);
> -}
> -
> static void
> facet_account(struct ofproto_dpif *ofproto, struct facet *facet)
> {
> uint64_t n_bytes;
> + struct subfacet *subfacet;
> const struct nlattr *a;
> unsigned int left;
> ovs_be16 vlan_tci;
> @@ -2851,9 +2830,15 @@ facet_account(struct ofproto_dpif *ofproto, struct facet *facet)
> * as a basis. We also need to track the actual VLAN on which the packet
> * is going to be sent to ensure that it matches the one passed to
> * bond_choose_output_slave(). (Otherwise, we will account to the wrong
> - * hash bucket.) */
> + * hash bucket.)
> + *
> + * We use the actions from an arbitrary subfacet because they should all
> + * be equally valid for our purpose. */
> + subfacet = CONTAINER_OF(list_front(&facet->subfacets),
> + struct subfacet, list_node);
> vlan_tci = facet->flow.vlan_tci;
> - NL_ATTR_FOR_EACH_UNSAFE (a, left, facet->actions, facet->actions_len) {
> + NL_ATTR_FOR_EACH_UNSAFE (a, left,
> + subfacet->actions, subfacet->actions_len) {
> const struct ovs_action_push_vlan *vlan;
> struct ofport_dpif *port;
>
> @@ -2982,12 +2967,17 @@ facet_lookup_valid(struct ofproto_dpif *ofproto, const struct flow *flow)
> static bool
> facet_revalidate(struct ofproto_dpif *ofproto, struct facet *facet)
> {
> + struct actions {
> + struct nlattr *odp_actions;
> + size_t actions_len;
> + };
> + struct actions *new_actions;
> +
> struct action_xlate_ctx ctx;
> - struct ofpbuf *odp_actions;
> struct rule_dpif *new_rule;
> struct subfacet *subfacet;
> bool actions_changed;
> - bool flush_stats;
> + int i;
>
> COVERAGE_INC(facet_revalidate);
>
> @@ -3004,19 +2994,25 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct facet *facet)
> * We do not modify any 'facet' state yet, because we might need to, e.g.,
> * emit a NetFlow expiration and, if so, we need to have the old state
> * around to properly compose it. */
> - action_xlate_ctx_init(&ctx, ofproto, &facet->flow, NULL);
> - odp_actions = xlate_actions(&ctx,
> - new_rule->up.actions, new_rule->up.n_actions);
> - actions_changed = (facet->actions_len != odp_actions->size
> - || memcmp(facet->actions, odp_actions->data,
> - facet->actions_len));
>
> /* If the datapath actions changed or the installability changed,
> * then we need to talk to the datapath. */
> - flush_stats = false;
> + i = 0;
> + new_actions = NULL;
> + memset(&ctx, 0, sizeof ctx);
> LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) {
> - bool should_install = (ctx.may_set_up_flow
> - && subfacet->key_fitness != ODP_FIT_TOO_LITTLE);
> + struct ofpbuf *odp_actions;
> + bool should_install;
> +
> + action_xlate_ctx_init(&ctx, ofproto, &facet->flow, NULL);
> + odp_actions = xlate_actions(&ctx, new_rule->up.actions,
> + new_rule->up.n_actions);
> + actions_changed = (subfacet->actions_len != odp_actions->size
> + || memcmp(subfacet->actions, odp_actions->data,
> + subfacet->actions_len));
> +
> + should_install = (ctx.may_set_up_flow
> + && subfacet->key_fitness != ODP_FIT_TOO_LITTLE);
> if (actions_changed || should_install != subfacet->installed) {
> if (should_install) {
> struct dpif_flow_stats stats;
> @@ -3027,10 +3023,20 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct facet *facet)
> } else {
> subfacet_uninstall(ofproto, subfacet);
> }
> - flush_stats = true;
> +
> + if (!new_actions) {
> + new_actions = xcalloc(list_size(&facet->subfacets),
> + sizeof *new_actions);
> + }
> + new_actions[i].odp_actions = xmemdup(odp_actions->data,
> + odp_actions->size);
> + new_actions[i].actions_len = odp_actions->size;
> }
> +
> + ofpbuf_delete(odp_actions);
> + i++;
> }
> - if (flush_stats) {
> + if (new_actions) {
> facet_flush_stats(ofproto, facet);
> }
>
> @@ -3040,10 +3046,17 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct facet *facet)
> facet->may_install = ctx.may_set_up_flow;
> facet->has_learn = ctx.has_learn;
> facet->has_normal = ctx.has_normal;
> - if (actions_changed) {
> - free(facet->actions);
> - facet->actions_len = odp_actions->size;
> - facet->actions = xmemdup(odp_actions->data, odp_actions->size);
> + if (new_actions) {
> + i = 0;
> + LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) {
> + if (new_actions[i].odp_actions) {
> + free(subfacet->actions);
> + subfacet->actions = new_actions[i].odp_actions;
> + subfacet->actions_len = new_actions[i].actions_len;
> + }
> + i++;
> + }
> + free(new_actions);
> }
> if (facet->rule != new_rule) {
> COVERAGE_INC(facet_changed_rule);
> @@ -3054,8 +3067,6 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct facet *facet)
> facet->rs_used = facet->used;
> }
>
> - ofpbuf_delete(odp_actions);
> -
> return true;
> }
>
> @@ -3169,7 +3180,11 @@ subfacet_find__(struct ofproto_dpif *ofproto,
>
> /* Searches 'facet' (within 'ofproto') for a subfacet with the specified
> * 'key_fitness', 'key', and 'key_len'. Returns the existing subfacet if
> - * there is one, otherwise creates and returns a new subfacet. */
> + * there is one, otherwise creates and returns a new subfacet.
> + *
> + * If the returned subfacet is new, then subfacet->actions will be NULL, in
> + * which case the caller must populate the actions with
> + * subfacet_make_actions(). */
> static struct subfacet *
> subfacet_create(struct ofproto_dpif *ofproto, struct facet *facet,
> enum odp_key_fitness key_fitness,
> @@ -3225,6 +3240,7 @@ subfacet_destroy__(struct ofproto_dpif *ofproto, struct subfacet *subfacet)
> hmap_remove(&ofproto->subfacets, &subfacet->hmap_node);
> list_remove(&subfacet->list_node);
> free(subfacet->key);
> + free(subfacet->actions);
> free(subfacet);
> }
>
> @@ -3256,6 +3272,34 @@ subfacet_get_key(struct subfacet *subfacet, struct odputil_keybuf *keybuf,
> }
> }
>
> +/* Composes the datapath actions for 'subfacet' based on its rule's actions. */
> +static void
> +subfacet_make_actions(struct ofproto_dpif *p, struct subfacet *subfacet,
> + const struct ofpbuf *packet)
> +{
> + struct facet *facet = subfacet->facet;
> + const struct rule_dpif *rule = facet->rule;
> + struct ofpbuf *odp_actions;
> + struct action_xlate_ctx ctx;
> +
> + action_xlate_ctx_init(&ctx, p, &facet->flow, packet);
> + odp_actions = xlate_actions(&ctx, rule->up.actions, rule->up.n_actions);
> + facet->tags = ctx.tags;
> + facet->may_install = ctx.may_set_up_flow;
> + facet->has_learn = ctx.has_learn;
> + facet->has_normal = ctx.has_normal;
> + facet->nf_flow.output_iface = ctx.nf_output_iface;
> +
> + if (subfacet->actions_len != odp_actions->size
> + || memcmp(subfacet->actions, odp_actions->data, odp_actions->size)) {
> + free(subfacet->actions);
> + subfacet->actions_len = odp_actions->size;
> + subfacet->actions = xmemdup(odp_actions->data, odp_actions->size);
> + }
> +
> + ofpbuf_delete(odp_actions);
> +}
> +
> /* Updates 'subfacet''s datapath flow, setting its actions to 'actions_len'
> * bytes of actions in 'actions'. If 'stats' is non-null, statistics counters
> * in the datapath will be zeroed and 'stats' will be updated with traffic new
> @@ -5254,8 +5298,8 @@ send_active_timeout(struct ofproto_dpif *ofproto, struct facet *facet)
> if (subfacet->installed) {
> struct dpif_flow_stats stats;
>
> - subfacet_install(ofproto, subfacet, facet->actions,
> - facet->actions_len, &stats);
> + subfacet_install(ofproto, subfacet, subfacet->actions,
> + subfacet->actions_len, &stats);
> subfacet_update_stats(ofproto, subfacet, &stats);
> }
> }
> --
> 1.7.4.4
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>
More information about the dev
mailing list