X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif.c;h=cdc21bca65c12516403e52c589a97ec25fb6f2cd;hb=51cb6e0c654e0954e12c8f171b5215ccad6185eb;hp=8088c68d6572d895466ccf79a70305846a834d05;hpb=6c222e55fa4222c6724094e1e7a0a69addf6b030;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 8088c68d6..cdc21bca6 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -16,12 +16,13 @@ #include -#include "ofproto/private.h" +#include "ofproto/ofproto-provider.h" #include #include "autopath.h" #include "bond.h" +#include "bundle.h" #include "byte-order.h" #include "connmgr.h" #include "coverage.h" @@ -40,7 +41,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" @@ -287,6 +288,7 @@ struct ofport_dpif { struct cfm *cfm; /* Connectivity Fault Management, if any. */ tag_type tag; /* Tag associated with this port. */ uint32_t bond_stable_id; /* stable_id to use as bond slave, or 0. */ + bool may_enable; /* May be enabled in bonds. */ }; static struct ofport_dpif * @@ -300,6 +302,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; @@ -310,7 +317,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]; @@ -323,8 +330,17 @@ struct ofproto_dpif { struct hmap facets; bool need_revalidate; struct tag_set revalidate_set; + + /* Support for debugging async flow mods. */ + struct list completions; + + bool has_bundle_action; /* True when the first bundle action appears. */ }; +/* 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 * @@ -446,27 +462,52 @@ 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; ofproto_dpif_unixctl_init(); + ofproto->has_bundle_action = false; + 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); @@ -483,6 +524,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++) { @@ -510,7 +554,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) { @@ -549,10 +593,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,10 +714,11 @@ port_construct(struct ofport *port_) port->bundle = NULL; port->cfm = NULL; port->tag = tag_create_random(); + port->may_enable = true; 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; @@ -684,7 +733,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); } } @@ -716,20 +765,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; @@ -1134,12 +1183,7 @@ bundle_run(struct ofbundle *bundle) struct ofport_dpif *port; LIST_FOR_EACH (port, bundle_node, &bundle->ports) { - bool may_enable = lacp_slave_may_enable(bundle->lacp, port); - - if (may_enable && port->cfm) { - may_enable = !cfm_get_fault(port->cfm); - } - bond_slave_set_may_enable(bundle->bond, port, may_enable); + bond_slave_set_may_enable(bundle->bond, port, port->may_enable); } bond_run(bundle->bond, &bundle->ofproto->revalidate_set, @@ -1223,6 +1267,7 @@ mirror_set(struct ofproto *ofproto_, void *aux, mirror = ofproto->mirrors[idx] = xzalloc(sizeof *mirror); mirror->ofproto = ofproto; mirror->idx = idx; + mirror->aux = aux; mirror->out_vlan = -1; mirror->name = NULL; } @@ -1376,6 +1421,8 @@ ofproto_port_from_dpif_port(struct ofproto_port *ofproto_port, static void port_run(struct ofport_dpif *ofport) { + bool enable = netdev_get_carrier(ofport->up.netdev); + if (ofport->cfm) { cfm_run(ofport->cfm); @@ -1388,7 +1435,23 @@ port_run(struct ofport_dpif *ofport) ofport->odp_port, &packet); ofpbuf_uninit(&packet); } + + enable = enable && !cfm_get_fault(ofport->cfm); + } + + if (ofport->bundle) { + enable = enable && lacp_slave_may_enable(ofport->bundle->lacp, ofport); + } + + if (ofport->may_enable != enable) { + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto); + + if (ofproto->has_bundle_action) { + ofproto->need_revalidate = true; + } } + + ofport->may_enable = enable; } static void @@ -1651,7 +1714,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; @@ -1808,11 +1871,12 @@ facet_max_idle(const struct ofproto_dpif *ofproto) * N_BUCKETS buckets whose width is BUCKET_WIDTH msecs each. Each facet * that is installed in the kernel gets dropped in the appropriate bucket. * After the histogram has been built, we compute the cutoff so that only - * the most-recently-used 1% of facets (but at least 1000 flows) are kept - * cached. At least the most-recently-used bucket of facets is kept, so - * actually an arbitrary number of facets can be kept in any given - * expiration run (though the next run will delete most of those unless - * they receive additional data). + * the most-recently-used 1% of facets (but at least + * ofproto->up.flow_eviction_threshold flows) are kept cached. At least + * the most-recently-used bucket of facets is kept, so actually an + * arbitrary number of facets can be kept in any given expiration run + * (though the next run will delete most of those unless they receive + * additional data). * * This requires a second pass through the facets, in addition to the pass * made by update_stats(), because the former function never looks @@ -1821,13 +1885,13 @@ facet_max_idle(const struct ofproto_dpif *ofproto) enum { BUCKET_WIDTH = ROUND_UP(100, TIME_UPDATE_INTERVAL) }; enum { N_BUCKETS = 5000 / BUCKET_WIDTH }; int buckets[N_BUCKETS] = { 0 }; + int total, subtotal, bucket; struct facet *facet; - int total, bucket; long long int now; int i; total = hmap_count(&ofproto->facets); - if (total <= 1000) { + if (total <= ofproto->up.flow_eviction_threshold) { return N_BUCKETS * BUCKET_WIDTH; } @@ -1842,15 +1906,11 @@ facet_max_idle(const struct ofproto_dpif *ofproto) } /* Find the first bucket whose flows should be expired. */ - for (bucket = 0; bucket < N_BUCKETS; bucket++) { - if (buckets[bucket]) { - int subtotal = 0; - do { - subtotal += buckets[bucket++]; - } while (bucket < N_BUCKETS && subtotal < MAX(1000, total / 100)); - break; - } - } + subtotal = bucket = 0; + do { + subtotal += buckets[bucket++]; + } while (bucket < N_BUCKETS && + subtotal < MAX(ofproto->up.flow_eviction_threshold, total / 100)); if (VLOG_IS_DBG_ENABLED()) { struct ds s; @@ -1989,7 +2049,7 @@ execute_odp_actions(struct ofproto_dpif *ofproto, const struct flow *flow, struct ofpbuf *packet) { if (actions_len == NLA_ALIGN(NLA_HDRLEN + sizeof(uint64_t)) - && odp_actions->nla_type == ODP_ACTION_ATTR_CONTROLLER) { + && odp_actions->nla_type == ODP_ACTION_ATTR_USERSPACE) { /* As an optimization, avoid a round-trip from userspace to kernel to * userspace. This also avoids possibly filling up kernel packet * buffers along the way. */ @@ -2534,6 +2594,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) { @@ -2553,7 +2628,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, @@ -2562,21 +2637,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; } @@ -2587,11 +2666,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 @@ -2657,20 +2736,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'. @@ -2707,7 +2787,7 @@ send_packet(struct ofproto_dpif *ofproto, uint32_t odp_port, 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 xlate_normal(struct action_xlate_ctx *); static void commit_odp_actions(struct action_xlate_ctx *ctx) @@ -2731,6 +2811,11 @@ commit_odp_actions(struct action_xlate_ctx *ctx) base->nw_dst = flow->nw_dst; } + if (base->nw_tos != flow->nw_tos) { + nl_msg_put_u8(odp_actions, ODP_ACTION_ATTR_SET_NW_TOS, flow->nw_tos); + base->nw_tos = flow->nw_tos; + } + 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); @@ -2873,11 +2958,13 @@ xlate_output_action__(struct action_xlate_ctx *ctx, break; case OFPP_CONTROLLER: commit_odp_actions(ctx); - nl_msg_put_u64(ctx->odp_actions, ODP_ACTION_ATTR_CONTROLLER, max_len); + nl_msg_put_u64(ctx->odp_actions, ODP_ACTION_ATTR_USERSPACE, max_len); break; case OFPP_LOCAL: add_output_action(ctx, OFPP_LOCAL); break; + case OFPP_NONE: + break; default: if (port != ctx->flow.in_port) { add_output_action(ctx, port); @@ -2982,77 +3069,25 @@ xlate_autopath(struct action_xlate_ctx *ctx, autopath_execute(naa, &ctx->flow, ofp_port); } -static void -xlate_nicira_action(struct action_xlate_ctx *ctx, - const struct nx_action_header *nah) +static bool +slave_enabled_cb(uint16_t ofp_port, void *ofproto_) { - const struct nx_action_resubmit *nar; - const struct nx_action_set_tunnel *nast; - const struct nx_action_set_queue *nasq; - const struct nx_action_multipath *nam; - const struct nx_action_autopath *naa; - enum nx_action_subtype subtype = ntohs(nah->subtype); - ovs_be64 tun_id; - - assert(nah->vendor == htonl(NX_VENDOR_ID)); - switch (subtype) { - case NXAST_RESUBMIT: - nar = (const struct nx_action_resubmit *) nah; - xlate_table_action(ctx, ntohs(nar->in_port)); - break; - - case NXAST_SET_TUNNEL: - nast = (const struct nx_action_set_tunnel *) nah; - tun_id = htonll(ntohl(nast->tun_id)); - ctx->flow.tun_id = tun_id; - break; - - case NXAST_SET_QUEUE: - nasq = (const struct nx_action_set_queue *) nah; - xlate_set_queue_action(ctx, nasq); - break; - - case NXAST_POP_QUEUE: - ctx->priority = 0; - break; - - case NXAST_REG_MOVE: - nxm_execute_reg_move((const struct nx_action_reg_move *) nah, - &ctx->flow); - break; - - case NXAST_REG_LOAD: - nxm_execute_reg_load((const struct nx_action_reg_load *) nah, - &ctx->flow); - break; - - case NXAST_NOTE: - /* Nothing to do. */ - break; - - case NXAST_SET_TUNNEL64: - tun_id = ((const struct nx_action_set_tunnel64 *) nah)->tun_id; - ctx->flow.tun_id = tun_id; - break; - - case NXAST_MULTIPATH: - nam = (const struct nx_action_multipath *) nah; - multipath_execute(nam, &ctx->flow); - break; - - case NXAST_AUTOPATH: - naa = (const struct nx_action_autopath *) nah; - 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. */ + struct ofproto_dpif *ofproto = ofproto_; + struct ofport_dpif *port; - case NXAST_SNAT__OBSOLETE: - case NXAST_DROP_SPOOFED_ARP__OBSOLETE: + switch (ofp_port) { + case OFPP_IN_PORT: + case OFPP_TABLE: + case OFPP_NORMAL: + case OFPP_FLOOD: + case OFPP_ALL: + case OFPP_LOCAL: + return true; + case OFPP_CONTROLLER: /* Not supported by the bundle action. */ + return false; default: - VLOG_DBG_RL(&rl, "unknown Nicira action type %d", (int) subtype); - break; + port = get_ofp_port(ofproto, ofp_port); + return port ? port->may_enable : false; } } @@ -3061,8 +3096,8 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, struct action_xlate_ctx *ctx) { const struct ofport_dpif *port; - struct actions_iterator iter; const union ofp_action *ia; + size_t left; port = get_ofp_port(ctx->ofproto, ctx->flow.in_port); if (port @@ -3074,70 +3109,134 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, return; } - for (ia = actions_first(&iter, in, n_in); ia; ia = actions_next(&iter)) { - enum ofp_action_type type = ntohs(ia->type); + OFPUTIL_ACTION_FOR_EACH_UNSAFE (ia, left, in, n_in) { const struct ofp_action_dl_addr *oada; - - switch (type) { - case OFPAT_OUTPUT: + const struct nx_action_resubmit *nar; + const struct nx_action_set_tunnel *nast; + const struct nx_action_set_queue *nasq; + const struct nx_action_multipath *nam; + const struct nx_action_autopath *naa; + const struct nx_action_bundle *nab; + enum ofputil_action_code code; + ovs_be64 tun_id; + + code = ofputil_decode_action_unsafe(ia); + switch (code) { + case OFPUTIL_OFPAT_OUTPUT: xlate_output_action(ctx, &ia->output); break; - case OFPAT_SET_VLAN_VID: + case OFPUTIL_OFPAT_SET_VLAN_VID: ctx->flow.vlan_tci &= ~htons(VLAN_VID_MASK); ctx->flow.vlan_tci |= ia->vlan_vid.vlan_vid | htons(VLAN_CFI); break; - case OFPAT_SET_VLAN_PCP: + case OFPUTIL_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); break; - case OFPAT_STRIP_VLAN: + case OFPUTIL_OFPAT_STRIP_VLAN: ctx->flow.vlan_tci = htons(0); break; - case OFPAT_SET_DL_SRC: + case OFPUTIL_OFPAT_SET_DL_SRC: oada = ((struct ofp_action_dl_addr *) ia); memcpy(ctx->flow.dl_src, oada->dl_addr, ETH_ADDR_LEN); break; - case OFPAT_SET_DL_DST: + case OFPUTIL_OFPAT_SET_DL_DST: oada = ((struct ofp_action_dl_addr *) ia); memcpy(ctx->flow.dl_dst, oada->dl_addr, ETH_ADDR_LEN); break; - case OFPAT_SET_NW_SRC: + case OFPUTIL_OFPAT_SET_NW_SRC: ctx->flow.nw_src = ia->nw_addr.nw_addr; break; - case OFPAT_SET_NW_DST: + case OFPUTIL_OFPAT_SET_NW_DST: ctx->flow.nw_dst = ia->nw_addr.nw_addr; break; - case OFPAT_SET_NW_TOS: - ctx->flow.nw_tos = ia->nw_tos.nw_tos; + case OFPUTIL_OFPAT_SET_NW_TOS: + ctx->flow.nw_tos = ia->nw_tos.nw_tos & IP_DSCP_MASK; break; - case OFPAT_SET_TP_SRC: + case OFPUTIL_OFPAT_SET_TP_SRC: ctx->flow.tp_src = ia->tp_port.tp_port; break; - case OFPAT_SET_TP_DST: + case OFPUTIL_OFPAT_SET_TP_DST: ctx->flow.tp_dst = ia->tp_port.tp_port; break; - case OFPAT_VENDOR: - xlate_nicira_action(ctx, (const struct nx_action_header *) ia); + case OFPUTIL_OFPAT_ENQUEUE: + xlate_enqueue_action(ctx, (const struct ofp_action_enqueue *) ia); break; - case OFPAT_ENQUEUE: - xlate_enqueue_action(ctx, (const struct ofp_action_enqueue *) ia); + case OFPUTIL_NXAST_RESUBMIT: + nar = (const struct nx_action_resubmit *) ia; + xlate_table_action(ctx, ntohs(nar->in_port)); + break; + + case OFPUTIL_NXAST_SET_TUNNEL: + nast = (const struct nx_action_set_tunnel *) ia; + tun_id = htonll(ntohl(nast->tun_id)); + ctx->flow.tun_id = tun_id; + break; + + case OFPUTIL_NXAST_SET_QUEUE: + nasq = (const struct nx_action_set_queue *) ia; + xlate_set_queue_action(ctx, nasq); + break; + + case OFPUTIL_NXAST_POP_QUEUE: + ctx->priority = 0; + break; + + case OFPUTIL_NXAST_REG_MOVE: + nxm_execute_reg_move((const struct nx_action_reg_move *) ia, + &ctx->flow); break; - default: - VLOG_DBG_RL(&rl, "unknown action type %d", (int) type); + case OFPUTIL_NXAST_REG_LOAD: + nxm_execute_reg_load((const struct nx_action_reg_load *) ia, + &ctx->flow); + break; + + case OFPUTIL_NXAST_NOTE: + /* Nothing to do. */ + break; + + case OFPUTIL_NXAST_SET_TUNNEL64: + tun_id = ((const struct nx_action_set_tunnel64 *) ia)->tun_id; + ctx->flow.tun_id = tun_id; + break; + + case OFPUTIL_NXAST_MULTIPATH: + nam = (const struct nx_action_multipath *) ia; + multipath_execute(nam, &ctx->flow); + break; + + case OFPUTIL_NXAST_AUTOPATH: + naa = (const struct nx_action_autopath *) ia; + xlate_autopath(ctx, naa); + break; + + case OFPUTIL_NXAST_BUNDLE: + ctx->ofproto->has_bundle_action = true; + nab = (const struct nx_action_bundle *) ia; + xlate_output_action__(ctx, bundle_execute(nab, &ctx->flow, + slave_enabled_cb, + ctx->ofproto), 0); + break; + + case OFPUTIL_NXAST_BUNDLE_LOAD: + ctx->ofproto->has_bundle_action = true; + nab = (const struct nx_action_bundle *) ia; + bundle_execute_load(nab, &ctx->flow, slave_enabled_cb, + ctx->ofproto); break; } } @@ -3280,7 +3379,8 @@ dst_is_duplicate(const struct dst_set *set, const struct dst *test) static bool ofbundle_trunks_vlan(const struct ofbundle *bundle, uint16_t vlan) { - return bundle->vlan < 0 && vlan_bitmap_contains(bundle->trunks, vlan); + return (bundle->vlan < 0 + && (!bundle->trunks || bitmap_is_set(bundle->trunks, vlan))); } static bool @@ -3326,7 +3426,48 @@ compose_dsts(struct action_xlate_ctx *ctx, uint16_t vlan, static bool vlan_is_mirrored(const struct ofmirror *m, int vlan) { - return vlan_bitmap_contains(m->vlans, vlan); + return !m->vlans || bitmap_is_set(m->vlans, vlan); +} + +/* Returns true if a packet with Ethernet destination MAC 'dst' may be mirrored + * to a VLAN. In general most packets may be mirrored but we want to drop + * protocols that may confuse switches. */ +static bool +eth_dst_may_rspan(const uint8_t dst[ETH_ADDR_LEN]) +{ + /* If you change this function's behavior, please update corresponding + * documentation in vswitch.xml at the same time. */ + if (dst[0] != 0x01) { + /* All the currently banned MACs happen to start with 01 currently, so + * this is a quick way to eliminate most of the good ones. */ + } else { + if (eth_addr_is_reserved(dst)) { + /* Drop STP, IEEE pause frames, and other reserved protocols + * (01-80-c2-00-00-0x). */ + return false; + } + + if (dst[0] == 0x01 && dst[1] == 0x00 && dst[2] == 0x0c) { + /* Cisco OUI. */ + if ((dst[3] & 0xfe) == 0xcc && + (dst[4] & 0xfe) == 0xcc && + (dst[5] & 0xfe) == 0xcc) { + /* Drop the following protocols plus others following the same + pattern: + + CDP, VTP, DTP, PAgP (01-00-0c-cc-cc-cc) + Spanning Tree PVSTP+ (01-00-0c-cc-cc-cd) + STP Uplink Fast (01-00-0c-cd-cd-cd) */ + return false; + } + + if (!(dst[3] | dst[4] | dst[5])) { + /* Drop Inter Switch Link packets (01-00-0c-00-00-00). */ + return false; + } + } + } + return true; } static void @@ -3363,7 +3504,7 @@ compose_mirror_dsts(struct action_xlate_ctx *ctx, && !dst_is_duplicate(set, &dst)) { dst_set_add(set, &dst); } - } else { + } else if (eth_dst_may_rspan(ctx->flow.dl_dst)) { struct ofbundle *bundle; HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) { @@ -3635,10 +3776,7 @@ is_admissible(struct ofproto_dpif *ofproto, const struct flow *flow, return true; } -/* If the composed actions may be applied to any packet in the given 'flow', - * returns true. Otherwise, the actions should only be applied to 'packet', or - * not at all, if 'packet' was NULL. */ -static bool +static void xlate_normal(struct action_xlate_ctx *ctx) { struct ofbundle *in_bundle; @@ -3669,7 +3807,8 @@ xlate_normal(struct action_xlate_ctx *ctx) * of time where we could learn from a packet reflected on a bond and * blackhole packets before the learning table is updated to reflect * the correct port. */ - return false; + ctx->may_set_up_flow = false; + return; } else { out_bundle = OFBUNDLE_FLOOD; } @@ -3683,8 +3822,6 @@ done: if (in_bundle) { compose_actions(ctx, vlan, in_bundle, out_bundle); } - - return true; } static bool @@ -3798,8 +3935,7 @@ trace_format_rule(struct ds *result, int level, const struct rule *rule) ds_put_char_multiple(result, '\t', level); ds_put_cstr(result, "OpenFlow "); - ofp_print_actions(result, (const struct ofp_action_header *) rule->actions, - rule->n_actions * sizeof *rule->actions); + ofp_print_actions(result, rule->actions, rule->n_actions); ds_put_char(result, '\n'); } @@ -3916,6 +4052,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) { @@ -3927,6 +4079,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 = {