X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto-dpif.c;h=c062ec3d3d5711a00a60eded25a62a5ae2ac25c4;hb=22bcc0e70becd88bf895c44885d63704affe4284;hp=419e824044ce56a4eb1d0f9a0382e535942e728c;hpb=c0a2e71d110ad2af474232e03ea9ad94cbbae46f;p=openvswitch diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 419e8240..c062ec3d 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -40,7 +40,7 @@ #include "ofp-util.h" #include "ofpbuf.h" #include "ofp-print.h" -#include "ofproto-sflow.h" +#include "ofproto-dpif-sflow.h" #include "poll-loop.h" #include "timer.h" #include "unaligned.h" @@ -184,8 +184,9 @@ struct action_xlate_ctx { * reason to look at them. */ int recurse; /* Recursion level, via xlate_table_action. */ - int last_pop_priority; /* Offset in 'odp_actions' just past most - * recent ODP_ACTION_ATTR_SET_PRIORITY. */ + uint32_t priority; /* Current flow priority. 0 if none. */ + struct flow base_flow; /* Flow at the last commit. */ + uint32_t base_priority; /* Priority at the last commit. */ }; static void action_xlate_ctx_init(struct action_xlate_ctx *, @@ -266,6 +267,7 @@ static void facet_update_time(struct ofproto_dpif *, struct facet *, long long int used); static void facet_update_stats(struct ofproto_dpif *, struct facet *, const struct dpif_flow_stats *); +static void facet_reset_dp_stats(struct facet *, struct dpif_flow_stats *); static void facet_push_stats(struct facet *); static void facet_account(struct ofproto_dpif *, struct facet *, uint64_t extra_bytes); @@ -298,6 +300,11 @@ static void port_run(struct ofport_dpif *); static void port_wait(struct ofport_dpif *); static int set_cfm(struct ofport *, const struct cfm_settings *); +struct dpif_completion { + struct list list_node; + struct ofoperation *op; +}; + struct ofproto_dpif { struct ofproto up; struct dpif *dpif; @@ -308,7 +315,7 @@ struct ofproto_dpif { /* Bridging. */ struct netflow *netflow; - struct ofproto_sflow *sflow; + struct dpif_sflow *sflow; struct hmap bundles; /* Contains "struct ofbundle"s. */ struct mac_learning *ml; struct ofmirror *mirrors[MAX_MIRRORS]; @@ -321,8 +328,15 @@ struct ofproto_dpif { struct hmap facets; bool need_revalidate; struct tag_set revalidate_set; + + /* Support for debugging async flow mods. */ + struct list completions; }; +/* Defer flow mod completion until "ovs-appctl ofproto/unclog"? (Useful only + * for debugging the asynchronous flow_mod implementation.) */ +static bool clogged; + static void ofproto_dpif_unixctl_init(void); static struct ofproto_dpif * @@ -444,6 +458,8 @@ construct(struct ofproto *ofproto_) ofproto->need_revalidate = false; tag_set_init(&ofproto->revalidate_set); + list_init(&ofproto->completions); + ofproto->up.tables = xmalloc(sizeof *ofproto->up.tables); classifier_init(&ofproto->up.tables[0]); ofproto->up.n_tables = 1; @@ -453,18 +469,39 @@ construct(struct ofproto *ofproto_) return 0; } +static void +complete_operations(struct ofproto_dpif *ofproto) +{ + struct dpif_completion *c, *next; + + LIST_FOR_EACH_SAFE (c, next, list_node, &ofproto->completions) { + ofoperation_complete(c->op, 0); + list_remove(&c->list_node); + free(c); + } +} + static void destruct(struct ofproto *ofproto_) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); + struct rule_dpif *rule, *next_rule; + struct cls_cursor cursor; int i; + complete_operations(ofproto); + + cls_cursor_init(&cursor, &ofproto->up.tables[0], NULL); + CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) { + ofproto_rule_destroy(&rule->up); + } + for (i = 0; i < MAX_MIRRORS; i++) { mirror_destroy(ofproto->mirrors[i]); } netflow_destroy(ofproto->netflow); - ofproto_sflow_destroy(ofproto->sflow); + dpif_sflow_destroy(ofproto->sflow); hmap_destroy(&ofproto->bundles); mac_learning_destroy(ofproto->ml); @@ -481,6 +518,9 @@ run(struct ofproto *ofproto_) struct ofbundle *bundle; int i; + if (!clogged) { + complete_operations(ofproto); + } dpif_run(ofproto->dpif); for (i = 0; i < 50; i++) { @@ -508,7 +548,7 @@ run(struct ofproto *ofproto_) netflow_run(ofproto->netflow); } if (ofproto->sflow) { - ofproto_sflow_run(ofproto->sflow); + dpif_sflow_run(ofproto->sflow); } HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) { @@ -547,10 +587,14 @@ wait(struct ofproto *ofproto_) struct ofport_dpif *ofport; struct ofbundle *bundle; + if (!clogged && !list_is_empty(&ofproto->completions)) { + poll_immediate_wake(); + } + dpif_wait(ofproto->dpif); dpif_recv_wait(ofproto->dpif); if (ofproto->sflow) { - ofproto_sflow_wait(ofproto->sflow); + dpif_sflow_wait(ofproto->sflow); } if (!tag_set_is_empty(&ofproto->revalidate_set)) { poll_immediate_wake(); @@ -666,8 +710,8 @@ port_construct(struct ofport *port_) port->tag = tag_create_random(); if (ofproto->sflow) { - ofproto_sflow_add_port(ofproto->sflow, port->odp_port, - netdev_get_name(port->up.netdev)); + dpif_sflow_add_port(ofproto->sflow, port->odp_port, + netdev_get_name(port->up.netdev)); } return 0; @@ -682,7 +726,7 @@ port_destruct(struct ofport *port_) bundle_remove(port_); set_cfm(port_, NULL); if (ofproto->sflow) { - ofproto_sflow_del_port(ofproto->sflow, port->odp_port); + dpif_sflow_del_port(ofproto->sflow, port->odp_port); } } @@ -714,20 +758,20 @@ set_sflow(struct ofproto *ofproto_, const struct ofproto_sflow_options *sflow_options) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); - struct ofproto_sflow *os = ofproto->sflow; + struct dpif_sflow *ds = ofproto->sflow; if (sflow_options) { - if (!os) { + if (!ds) { struct ofport_dpif *ofport; - os = ofproto->sflow = ofproto_sflow_create(ofproto->dpif); + ds = ofproto->sflow = dpif_sflow_create(ofproto->dpif); HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) { - ofproto_sflow_add_port(os, ofport->odp_port, - netdev_get_name(ofport->up.netdev)); + dpif_sflow_add_port(ds, ofport->odp_port, + netdev_get_name(ofport->up.netdev)); } } - ofproto_sflow_set_options(os, sflow_options); + dpif_sflow_set_options(ds, sflow_options); } else { - ofproto_sflow_destroy(os); + dpif_sflow_destroy(ds); ofproto->sflow = NULL; } return 0; @@ -743,7 +787,7 @@ set_cfm(struct ofport *ofport_, const struct cfm_settings *s) error = 0; } else { if (!ofport->cfm) { - ofport->cfm = cfm_create(); + ofport->cfm = cfm_create(netdev_get_name(ofport->up.netdev)); } if (cfm_configure(ofport->cfm, s)) { @@ -1133,7 +1177,11 @@ bundle_run(struct ofbundle *bundle) LIST_FOR_EACH (port, bundle_node, &bundle->ports) { bool may_enable = lacp_slave_may_enable(bundle->lacp, port); - bond_slave_set_lacp_may_enable(bundle->bond, port, may_enable); + + if (may_enable && port->cfm) { + may_enable = !cfm_get_fault(port->cfm); + } + bond_slave_set_may_enable(bundle->bond, port, may_enable); } bond_run(bundle->bond, &bundle->ofproto->revalidate_set, @@ -1540,19 +1588,19 @@ process_special(struct ofproto_dpif *ofproto, const struct flow *flow, { if (cfm_should_process_flow(flow)) { struct ofport_dpif *ofport = get_ofp_port(ofproto, flow->in_port); - if (ofport && ofport->cfm) { + if (packet && ofport && ofport->cfm) { cfm_process_heartbeat(ofport->cfm, packet); } return true; } else if (flow->dl_type == htons(ETH_TYPE_LACP)) { struct ofport_dpif *port = get_ofp_port(ofproto, flow->in_port); - if (port && port->bundle && port->bundle->lacp) { + if (packet && port && port->bundle && port->bundle->lacp) { const struct lacp_pdu *pdu = parse_lacp_packet(packet); if (pdu) { lacp_process_pdu(port->bundle->lacp, port, pdu); } - return true; } + return true; } return false; } @@ -1645,7 +1693,7 @@ handle_upcall(struct ofproto_dpif *ofproto, struct dpif_upcall *upcall) case DPIF_UC_SAMPLE: if (ofproto->sflow) { odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow); - ofproto_sflow_received(ofproto->sflow, upcall, &flow); + dpif_sflow_received(ofproto->sflow, upcall, &flow); } ofpbuf_delete(upcall->packet); break; @@ -2002,9 +2050,16 @@ execute_odp_actions(struct ofproto_dpif *ofproto, const struct flow *flow, return true; } else { + struct odputil_keybuf keybuf; + struct ofpbuf key; int error; - error = dpif_execute(ofproto->dpif, odp_actions, actions_len, packet); + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, flow); + + error = dpif_execute(ofproto->dpif, key.data, key.size, + odp_actions, actions_len, packet); + ofpbuf_delete(packet); return !error; } @@ -2080,6 +2135,12 @@ facet_make_actions(struct ofproto_dpif *p, struct facet *facet, ofpbuf_delete(odp_actions); } +/* Updates 'facet''s flow in the datapath 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 + * since 'facet' was last updated. + * + * Returns 0 if successful, otherwise a positive errno value.*/ static int facet_put__(struct ofproto_dpif *ofproto, struct facet *facet, const struct nlattr *actions, size_t actions_len, @@ -2088,19 +2149,24 @@ facet_put__(struct ofproto_dpif *ofproto, struct facet *facet, struct odputil_keybuf keybuf; enum dpif_flow_put_flags flags; struct ofpbuf key; + int ret; flags = DPIF_FP_CREATE | DPIF_FP_MODIFY; if (stats) { flags |= DPIF_FP_ZERO_STATS; - facet->dp_packet_count = 0; - facet->dp_byte_count = 0; } ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, &facet->flow); - return dpif_flow_put(ofproto->dpif, flags, key.data, key.size, - actions, actions_len, stats); + ret = dpif_flow_put(ofproto->dpif, flags, key.data, key.size, + actions, actions_len, stats); + + if (stats) { + facet_reset_dp_stats(facet, stats); + } + + return ret; } /* If 'facet' is installable, inserts or re-inserts it into 'p''s datapath. If @@ -2199,16 +2265,17 @@ facet_uninstall(struct ofproto_dpif *p, struct facet *facet) struct odputil_keybuf keybuf; struct dpif_flow_stats stats; struct ofpbuf key; + int error; ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, &facet->flow); - if (!dpif_flow_del(p->dpif, key.data, key.size, &stats)) { + error = dpif_flow_del(p->dpif, key.data, key.size, &stats); + facet_reset_dp_stats(facet, &stats); + if (!error) { facet_update_stats(p, facet, &stats); } facet->installed = false; - facet->dp_packet_count = 0; - facet->dp_byte_count = 0; } else { assert(facet->dp_packet_count == 0); assert(facet->dp_byte_count == 0); @@ -2227,6 +2294,24 @@ facet_is_controller_flow(struct facet *facet) htons(OFPP_CONTROLLER))); } +/* Resets 'facet''s datapath statistics counters. This should be called when + * 'facet''s statistics are cleared in the datapath. If 'stats' is non-null, + * it should contain the statistics returned by dpif when 'facet' was reset in + * the datapath. 'stats' will be modified to only included statistics new + * since 'facet' was last updated. */ +static void +facet_reset_dp_stats(struct facet *facet, struct dpif_flow_stats *stats) +{ + if (stats && facet->dp_packet_count <= stats->n_packets + && facet->dp_byte_count <= stats->n_bytes) { + stats->n_packets -= facet->dp_packet_count; + stats->n_bytes -= facet->dp_byte_count; + } + + facet->dp_packet_count = 0; + facet->dp_byte_count = 0; +} + /* Folds all of 'facet''s statistics into its rule. Also updates the * accounting ofhook and emits a NetFlow expiration if appropriate. All of * 'facet''s statistics in the datapath should have been zeroed and folded into @@ -2491,6 +2576,21 @@ rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow) flow))); } +static void +complete_operation(struct rule_dpif *rule) +{ + struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); + + ofproto->need_revalidate = true; + if (clogged) { + struct dpif_completion *c = xmalloc(sizeof *c); + c->op = rule->up.pending; + list_push_back(&ofproto->completions, &c->list_node); + } else { + ofoperation_complete(rule->up.pending, 0); + } +} + static struct rule * rule_alloc(void) { @@ -2510,7 +2610,7 @@ rule_construct(struct rule *rule_) { struct rule_dpif *rule = rule_dpif_cast(rule_); struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); - struct rule_dpif *old_rule; + struct rule_dpif *victim; int error; error = validate_actions(rule->up.actions, rule->up.n_actions, @@ -2519,21 +2619,25 @@ rule_construct(struct rule *rule_) return error; } - old_rule = rule_dpif_cast(rule_from_cls_rule(classifier_find_rule_exactly( - &ofproto->up.tables[0], - &rule->up.cr))); - if (old_rule) { - ofproto_rule_destroy(&old_rule->up); - } - rule->used = rule->up.created; rule->packet_count = 0; rule->byte_count = 0; - list_init(&rule->facets); - classifier_insert(&ofproto->up.tables[0], &rule->up.cr); - ofproto->need_revalidate = true; + victim = rule_dpif_cast(ofoperation_get_victim(rule->up.pending)); + if (victim && !list_is_empty(&victim->facets)) { + struct facet *facet; + + rule->facets = victim->facets; + list_moved(&rule->facets); + LIST_FOR_EACH (facet, list_node, &rule->facets) { + facet->rule = rule; + } + } else { + /* Must avoid list_moved() in this case. */ + list_init(&rule->facets); + } + complete_operation(rule); return 0; } @@ -2544,11 +2648,11 @@ rule_destruct(struct rule *rule_) struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); struct facet *facet, *next_facet; - classifier_remove(&ofproto->up.tables[0], &rule->up.cr); LIST_FOR_EACH_SAFE (facet, next_facet, list_node, &rule->facets) { facet_revalidate(ofproto, facet); } - ofproto->need_revalidate = true; + + complete_operation(rule); } static void @@ -2614,20 +2718,21 @@ rule_execute(struct rule *rule_, struct flow *flow, struct ofpbuf *packet) return 0; } -static int -rule_modify_actions(struct rule *rule_, - const union ofp_action *actions, size_t n_actions) +static void +rule_modify_actions(struct rule *rule_) { struct rule_dpif *rule = rule_dpif_cast(rule_); struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); int error; - error = validate_actions(actions, n_actions, &rule->up.cr.flow, - ofproto->max_ports); - if (!error) { - ofproto->need_revalidate = true; + error = validate_actions(rule->up.actions, rule->up.n_actions, + &rule->up.cr.flow, ofproto->max_ports); + if (error) { + ofoperation_complete(rule->up.pending, error); + return; } - return error; + + complete_operation(rule); } /* Sends 'packet' out of port 'odp_port' within 'p'. @@ -2636,12 +2741,20 @@ static int send_packet(struct ofproto_dpif *ofproto, uint32_t odp_port, const struct ofpbuf *packet) { - struct ofpbuf odp_actions; + struct ofpbuf key, odp_actions; + struct odputil_keybuf keybuf; + struct flow flow; int error; + flow_extract((struct ofpbuf *) packet, 0, 0, &flow); + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, &flow); + ofpbuf_init(&odp_actions, 32); nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_OUTPUT, odp_port); - error = dpif_execute(ofproto->dpif, odp_actions.data, odp_actions.size, + error = dpif_execute(ofproto->dpif, + key.data, key.size, + odp_actions.data, odp_actions.size, packet); ofpbuf_uninit(&odp_actions); @@ -2658,6 +2771,71 @@ static void do_xlate_actions(const union ofp_action *in, size_t n_in, struct action_xlate_ctx *ctx); static bool xlate_normal(struct action_xlate_ctx *); +static void +commit_odp_actions(struct action_xlate_ctx *ctx) +{ + const struct flow *flow = &ctx->flow; + struct flow *base = &ctx->base_flow; + struct ofpbuf *odp_actions = ctx->odp_actions; + + if (base->tun_id != flow->tun_id) { + nl_msg_put_be64(odp_actions, ODP_ACTION_ATTR_SET_TUNNEL, flow->tun_id); + base->tun_id = flow->tun_id; + } + + if (base->nw_src != flow->nw_src) { + nl_msg_put_be32(odp_actions, ODP_ACTION_ATTR_SET_NW_SRC, flow->nw_src); + base->nw_src = flow->nw_src; + } + + if (base->nw_dst != flow->nw_dst) { + nl_msg_put_be32(odp_actions, ODP_ACTION_ATTR_SET_NW_DST, flow->nw_dst); + base->nw_dst = flow->nw_dst; + } + + if (base->vlan_tci != flow->vlan_tci) { + if (!(flow->vlan_tci & htons(VLAN_CFI))) { + nl_msg_put_flag(odp_actions, ODP_ACTION_ATTR_STRIP_VLAN); + } else { + nl_msg_put_be16(odp_actions, ODP_ACTION_ATTR_SET_DL_TCI, + flow->vlan_tci & ~htons(VLAN_CFI)); + } + base->vlan_tci = flow->vlan_tci; + } + + if (base->tp_src != flow->tp_src) { + nl_msg_put_be16(odp_actions, ODP_ACTION_ATTR_SET_TP_SRC, flow->tp_src); + base->tp_src = flow->tp_src; + } + + if (base->tp_dst != flow->tp_dst) { + nl_msg_put_be16(odp_actions, ODP_ACTION_ATTR_SET_TP_DST, flow->tp_dst); + base->tp_dst = flow->tp_dst; + } + + if (!eth_addr_equals(base->dl_src, flow->dl_src)) { + nl_msg_put_unspec(odp_actions, ODP_ACTION_ATTR_SET_DL_SRC, + flow->dl_src, ETH_ADDR_LEN); + memcpy(base->dl_src, flow->dl_src, ETH_ADDR_LEN); + } + + if (!eth_addr_equals(base->dl_dst, flow->dl_dst)) { + nl_msg_put_unspec(odp_actions, ODP_ACTION_ATTR_SET_DL_DST, + flow->dl_dst, ETH_ADDR_LEN); + memcpy(base->dl_dst, flow->dl_dst, ETH_ADDR_LEN); + } + + if (ctx->base_priority != ctx->priority) { + if (ctx->priority) { + nl_msg_put_u32(odp_actions, ODP_ACTION_ATTR_SET_PRIORITY, + ctx->priority); + } else { + nl_msg_put_flag(odp_actions, ODP_ACTION_ATTR_POP_PRIORITY); + } + ctx->base_priority = ctx->priority; + } +} + static void add_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port) { @@ -2677,6 +2855,7 @@ add_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port) */ } + commit_odp_actions(ctx); nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_OUTPUT, odp_port); ctx->nf_output_iface = ofp_port; } @@ -2714,20 +2893,20 @@ xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port) } static void -flood_packets(struct ofproto_dpif *ofproto, - uint16_t ofp_in_port, ovs_be32 mask, - uint16_t *nf_output_iface, struct ofpbuf *odp_actions) +flood_packets(struct action_xlate_ctx *ctx, ovs_be32 mask) { struct ofport_dpif *ofport; - HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) { + commit_odp_actions(ctx); + HMAP_FOR_EACH (ofport, up.hmap_node, &ctx->ofproto->up.ports) { uint16_t ofp_port = ofport->up.ofp_port; - if (ofp_port != ofp_in_port && !(ofport->up.opp.config & mask)) { - nl_msg_put_u32(odp_actions, ODP_ACTION_ATTR_OUTPUT, + if (ofp_port != ctx->flow.in_port && !(ofport->up.opp.config & mask)) { + nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_OUTPUT, ofport->odp_port); } } - *nf_output_iface = NF_OUT_FLOOD; + + ctx->nf_output_iface = NF_OUT_FLOOD; } static void @@ -2749,14 +2928,13 @@ xlate_output_action__(struct action_xlate_ctx *ctx, xlate_normal(ctx); break; case OFPP_FLOOD: - flood_packets(ctx->ofproto, ctx->flow.in_port, htonl(OFPPC_NO_FLOOD), - &ctx->nf_output_iface, ctx->odp_actions); + flood_packets(ctx, htonl(OFPPC_NO_FLOOD)); break; case OFPP_ALL: - flood_packets(ctx->ofproto, ctx->flow.in_port, htonl(0), - &ctx->nf_output_iface, ctx->odp_actions); + flood_packets(ctx, htonl(0)); break; case OFPP_CONTROLLER: + commit_odp_actions(ctx); nl_msg_put_u64(ctx->odp_actions, ODP_ACTION_ATTR_CONTROLLER, max_len); break; case OFPP_LOCAL: @@ -2786,34 +2964,12 @@ xlate_output_action(struct action_xlate_ctx *ctx, xlate_output_action__(ctx, ntohs(oao->port), ntohs(oao->max_len)); } -/* If the final ODP action in 'ctx' is "pop priority", drop it, as an - * optimization, because we're going to add another action that sets the - * priority immediately after, or because there are no actions following the - * pop. */ -static void -remove_pop_action(struct action_xlate_ctx *ctx) -{ - if (ctx->odp_actions->size == ctx->last_pop_priority) { - ctx->odp_actions->size -= NLA_ALIGN(NLA_HDRLEN); - ctx->last_pop_priority = -1; - } -} - -static void -add_pop_action(struct action_xlate_ctx *ctx) -{ - if (ctx->odp_actions->size != ctx->last_pop_priority) { - nl_msg_put_flag(ctx->odp_actions, ODP_ACTION_ATTR_POP_PRIORITY); - ctx->last_pop_priority = ctx->odp_actions->size; - } -} - static void xlate_enqueue_action(struct action_xlate_ctx *ctx, const struct ofp_action_enqueue *oae) { uint16_t ofp_port, odp_port; - uint32_t priority; + uint32_t ctx_priority, priority; int error; error = dpif_queue_to_priority(ctx->ofproto->dpif, ntohl(oae->queue_id), @@ -2832,10 +2988,10 @@ xlate_enqueue_action(struct action_xlate_ctx *ctx, odp_port = ofp_port_to_odp_port(ofp_port); /* Add ODP actions. */ - remove_pop_action(ctx); - nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_SET_PRIORITY, priority); + ctx_priority = ctx->priority; + ctx->priority = priority; add_output_action(ctx, odp_port); - add_pop_action(ctx); + ctx->priority = ctx_priority; /* Update NetFlow output port. */ if (ctx->nf_output_iface == NF_OUT_DROP) { @@ -2860,20 +3016,7 @@ xlate_set_queue_action(struct action_xlate_ctx *ctx, return; } - remove_pop_action(ctx); - nl_msg_put_u32(ctx->odp_actions, ODP_ACTION_ATTR_SET_PRIORITY, priority); -} - -static void -xlate_set_dl_tci(struct action_xlate_ctx *ctx) -{ - ovs_be16 tci = ctx->flow.vlan_tci; - if (!(tci & htons(VLAN_CFI))) { - nl_msg_put_flag(ctx->odp_actions, ODP_ACTION_ATTR_STRIP_VLAN); - } else { - nl_msg_put_be16(ctx->odp_actions, ODP_ACTION_ATTR_SET_DL_TCI, - tci & ~htons(VLAN_CFI)); - } + ctx->priority = priority; } struct xlate_reg_state { @@ -2881,27 +3024,6 @@ struct xlate_reg_state { ovs_be64 tun_id; }; -static void -save_reg_state(const struct action_xlate_ctx *ctx, - struct xlate_reg_state *state) -{ - state->vlan_tci = ctx->flow.vlan_tci; - state->tun_id = ctx->flow.tun_id; -} - -static void -update_reg_state(struct action_xlate_ctx *ctx, - const struct xlate_reg_state *state) -{ - if (ctx->flow.vlan_tci != state->vlan_tci) { - xlate_set_dl_tci(ctx); - } - if (ctx->flow.tun_id != state->tun_id) { - nl_msg_put_be64(ctx->odp_actions, - ODP_ACTION_ATTR_SET_TUNNEL, ctx->flow.tun_id); - } -} - static void xlate_autopath(struct action_xlate_ctx *ctx, const struct nx_action_autopath *naa) @@ -2932,7 +3054,6 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, const struct nx_action_multipath *nam; const struct nx_action_autopath *naa; enum nx_action_subtype subtype = ntohs(nah->subtype); - struct xlate_reg_state state; ovs_be64 tun_id; assert(nah->vendor == htonl(NX_VENDOR_ID)); @@ -2945,38 +3066,26 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, case NXAST_SET_TUNNEL: nast = (const struct nx_action_set_tunnel *) nah; tun_id = htonll(ntohl(nast->tun_id)); - nl_msg_put_be64(ctx->odp_actions, ODP_ACTION_ATTR_SET_TUNNEL, tun_id); ctx->flow.tun_id = tun_id; break; - case NXAST_DROP_SPOOFED_ARP: - if (ctx->flow.dl_type == htons(ETH_TYPE_ARP)) { - nl_msg_put_flag(ctx->odp_actions, - ODP_ACTION_ATTR_DROP_SPOOFED_ARP); - } - break; - case NXAST_SET_QUEUE: nasq = (const struct nx_action_set_queue *) nah; xlate_set_queue_action(ctx, nasq); break; case NXAST_POP_QUEUE: - add_pop_action(ctx); + ctx->priority = 0; break; case NXAST_REG_MOVE: - save_reg_state(ctx, &state); nxm_execute_reg_move((const struct nx_action_reg_move *) nah, &ctx->flow); - update_reg_state(ctx, &state); break; case NXAST_REG_LOAD: - save_reg_state(ctx, &state); nxm_execute_reg_load((const struct nx_action_reg_load *) nah, &ctx->flow); - update_reg_state(ctx, &state); break; case NXAST_NOTE: @@ -2985,7 +3094,6 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, case NXAST_SET_TUNNEL64: tun_id = ((const struct nx_action_set_tunnel64 *) nah)->tun_id; - nl_msg_put_be64(ctx->odp_actions, ODP_ACTION_ATTR_SET_TUNNEL, tun_id); ctx->flow.tun_id = tun_id; break; @@ -2999,10 +3107,8 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, xlate_autopath(ctx, naa); break; - /* If you add a new action here that modifies flow data, don't forget to - * update the flow key in ctx->flow at the same time. */ - case NXAST_SNAT__OBSOLETE: + case NXAST_DROP_SPOOFED_ARP__OBSOLETE: default: VLOG_DBG_RL(&rl, "unknown Nicira action type %d", (int) subtype); break; @@ -3039,62 +3145,45 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, case OFPAT_SET_VLAN_VID: ctx->flow.vlan_tci &= ~htons(VLAN_VID_MASK); ctx->flow.vlan_tci |= ia->vlan_vid.vlan_vid | htons(VLAN_CFI); - xlate_set_dl_tci(ctx); break; case OFPAT_SET_VLAN_PCP: ctx->flow.vlan_tci &= ~htons(VLAN_PCP_MASK); ctx->flow.vlan_tci |= htons( (ia->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT) | VLAN_CFI); - xlate_set_dl_tci(ctx); break; case OFPAT_STRIP_VLAN: ctx->flow.vlan_tci = htons(0); - xlate_set_dl_tci(ctx); break; case OFPAT_SET_DL_SRC: oada = ((struct ofp_action_dl_addr *) ia); - nl_msg_put_unspec(ctx->odp_actions, ODP_ACTION_ATTR_SET_DL_SRC, - oada->dl_addr, ETH_ADDR_LEN); memcpy(ctx->flow.dl_src, oada->dl_addr, ETH_ADDR_LEN); break; case OFPAT_SET_DL_DST: oada = ((struct ofp_action_dl_addr *) ia); - nl_msg_put_unspec(ctx->odp_actions, ODP_ACTION_ATTR_SET_DL_DST, - oada->dl_addr, ETH_ADDR_LEN); memcpy(ctx->flow.dl_dst, oada->dl_addr, ETH_ADDR_LEN); break; case OFPAT_SET_NW_SRC: - nl_msg_put_be32(ctx->odp_actions, ODP_ACTION_ATTR_SET_NW_SRC, - ia->nw_addr.nw_addr); ctx->flow.nw_src = ia->nw_addr.nw_addr; break; case OFPAT_SET_NW_DST: - nl_msg_put_be32(ctx->odp_actions, ODP_ACTION_ATTR_SET_NW_DST, - ia->nw_addr.nw_addr); ctx->flow.nw_dst = ia->nw_addr.nw_addr; break; case OFPAT_SET_NW_TOS: - nl_msg_put_u8(ctx->odp_actions, ODP_ACTION_ATTR_SET_NW_TOS, - ia->nw_tos.nw_tos); ctx->flow.nw_tos = ia->nw_tos.nw_tos; break; case OFPAT_SET_TP_SRC: - nl_msg_put_be16(ctx->odp_actions, ODP_ACTION_ATTR_SET_TP_SRC, - ia->tp_port.tp_port); ctx->flow.tp_src = ia->tp_port.tp_port; break; case OFPAT_SET_TP_DST: - nl_msg_put_be16(ctx->odp_actions, ODP_ACTION_ATTR_SET_TP_DST, - ia->tp_port.tp_port); ctx->flow.tp_dst = ia->tp_port.tp_port; break; @@ -3135,7 +3224,9 @@ xlate_actions(struct action_xlate_ctx *ctx, ctx->may_set_up_flow = true; ctx->nf_output_iface = NF_OUT_DROP; ctx->recurse = 0; - ctx->last_pop_priority = -1; + ctx->priority = 0; + ctx->base_priority = 0; + ctx->base_flow = ctx->flow; if (process_special(ctx->ofproto, &ctx->flow, ctx->packet)) { ctx->may_set_up_flow = false; @@ -3143,8 +3234,6 @@ xlate_actions(struct action_xlate_ctx *ctx, do_xlate_actions(in, n_in, ctx); } - remove_pop_action(ctx); - /* Check with in-band control to see if we're allowed to set up this * flow. */ if (!connmgr_may_set_up_flow(ctx->ofproto->up.connmgr, &ctx->flow, @@ -3686,13 +3775,18 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet, error = validate_actions(ofp_actions, n_ofp_actions, flow, ofproto->max_ports); if (!error) { + struct odputil_keybuf keybuf; struct action_xlate_ctx ctx; struct ofpbuf *odp_actions; + struct ofpbuf key; + + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, flow); action_xlate_ctx_init(&ctx, ofproto, flow, packet); odp_actions = xlate_actions(&ctx, ofp_actions, n_ofp_actions); - dpif_execute(ofproto->dpif, odp_actions->data, odp_actions->size, - packet); + dpif_execute(ofproto->dpif, key.data, key.size, + odp_actions->data, odp_actions->size, packet); ofpbuf_delete(odp_actions); } return error; @@ -3881,6 +3975,22 @@ exit: free(args); } +static void +ofproto_dpif_clog(struct unixctl_conn *conn OVS_UNUSED, + const char *args_ OVS_UNUSED, void *aux OVS_UNUSED) +{ + clogged = true; + unixctl_command_reply(conn, 200, NULL); +} + +static void +ofproto_dpif_unclog(struct unixctl_conn *conn OVS_UNUSED, + const char *args_ OVS_UNUSED, void *aux OVS_UNUSED) +{ + clogged = false; + unixctl_command_reply(conn, 200, NULL); +} + static void ofproto_dpif_unixctl_init(void) { @@ -3892,6 +4002,9 @@ ofproto_dpif_unixctl_init(void) unixctl_command_register("ofproto/trace", ofproto_unixctl_trace, NULL); unixctl_command_register("fdb/show", ofproto_unixctl_fdb_show, NULL); + + unixctl_command_register("ofproto/clog", ofproto_dpif_clog, NULL); + unixctl_command_register("ofproto/unclog", ofproto_dpif_unclog, NULL); } const struct ofproto_class ofproto_dpif_class = { @@ -3922,6 +4035,7 @@ const struct ofproto_class ofproto_dpif_class = { port_poll, port_poll_wait, port_is_lacp_current, + NULL, /* rule_choose_table */ rule_alloc, rule_construct, rule_destruct,