X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto-dpif.c;h=3aa29a8308983bf57de8ecc11a1f8f09b305f3e4;hb=5d9499c4dc43bb40f49bf7a819821750a43039d2;hp=2451d44d7d8c3ad3cb6e329b5e803e9733e43301;hpb=f25d0cf3c366d92042269a4f787f19c741c2530c;p=openvswitch diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 2451d44d..3aa29a83 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -66,7 +66,7 @@ COVERAGE_DEFINE(facet_suppress); /* Maximum depth of flow table recursion (due to resubmit actions) in a * flow translation. */ -#define MAX_RESUBMIT_RECURSION 32 +#define MAX_RESUBMIT_RECURSION 64 /* Number of implemented OpenFlow tables. */ enum { N_TABLES = 255 }; @@ -110,6 +110,8 @@ static struct rule_dpif *rule_dpif_lookup(struct ofproto_dpif *, static struct rule_dpif *rule_dpif_lookup__(struct ofproto_dpif *, const struct flow *, uint8_t table); +static struct rule_dpif *rule_dpif_miss_rule(struct ofproto_dpif *ofproto, + const struct flow *flow); static void rule_credit_stats(struct rule_dpif *, const struct dpif_flow_stats *); @@ -243,6 +245,11 @@ struct action_xlate_ctx { * calling action_xlate_ctx_init(). */ void (*resubmit_hook)(struct action_xlate_ctx *, struct rule_dpif *rule); + /* If nonnull, flow translation calls this function to report some + * significant decision, e.g. to explain why OFPP_NORMAL translation + * dropped a packet. */ + void (*report_hook)(struct action_xlate_ctx *, const char *s); + /* If nonnull, flow translation credits the specified statistics to each * rule reached through a resubmit or OFPP_TABLE action. * @@ -299,6 +306,8 @@ static void compose_slow_path(const struct ofproto_dpif *, const struct flow *, const struct nlattr **actionsp, size_t *actions_lenp); +static void xlate_report(struct action_xlate_ctx *ctx, const char *s); + /* A subfacet (see "struct subfacet" below) has three possible installation * states: * @@ -361,7 +370,8 @@ struct subfacet { static struct subfacet *subfacet_create(struct facet *, enum odp_key_fitness, const struct nlattr *key, - size_t key_len, ovs_be16 initial_tci); + size_t key_len, ovs_be16 initial_tci, + long long int now); static struct subfacet *subfacet_find(struct ofproto_dpif *, const struct nlattr *key, size_t key_len); static void subfacet_destroy(struct subfacet *); @@ -588,7 +598,6 @@ struct ofproto_dpif { struct hmap_node all_ofproto_dpifs_node; /* In 'all_ofproto_dpifs'. */ struct ofproto up; struct dpif *dpif; - int max_ports; /* Special OpenFlow rules. */ struct rule_dpif *miss_rule; /* Sends flow table misses to controller. */ @@ -734,6 +743,7 @@ construct(struct ofproto *ofproto_) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); const char *name = ofproto->up.name; + int max_ports; int error; int i; @@ -743,7 +753,9 @@ construct(struct ofproto *ofproto_) return error; } - ofproto->max_ports = dpif_get_max_ports(ofproto->dpif); + max_ports = dpif_get_max_ports(ofproto->dpif); + ofproto_init_max_ports(ofproto_, MIN(max_ports, OFPP_MAX)); + ofproto->n_matches = 0; dpif_flow_flush(ofproto->dpif); @@ -1146,7 +1158,7 @@ get_features(struct ofproto *ofproto_ OVS_UNUSED, } static void -get_tables(struct ofproto *ofproto_, struct ofp_table_stats *ots) +get_tables(struct ofproto *ofproto_, struct ofp10_table_stats *ots) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); struct dpif_dp_stats s; @@ -1308,6 +1320,14 @@ get_cfm_fault(const struct ofport *ofport_) return ofport->cfm ? cfm_get_fault(ofport->cfm) : -1; } +static int +get_cfm_opup(const struct ofport *ofport_) +{ + struct ofport_dpif *ofport = ofport_dpif_cast(ofport_); + + return ofport->cfm ? cfm_get_opup(ofport->cfm) : -1; +} + static int get_cfm_remote_mpids(const struct ofport *ofport_, const uint64_t **rmps, size_t *n_rmps) @@ -1957,7 +1977,7 @@ bundle_set(struct ofproto *ofproto_, void *aux, break; case PORT_VLAN_TRUNK: - trunks = (unsigned long *) s->trunks; + trunks = CONST_CAST(unsigned long *, s->trunks); break; case PORT_VLAN_NATIVE_UNTAGGED: @@ -1974,7 +1994,7 @@ bundle_set(struct ofproto *ofproto_, void *aux, bitmap_set1(trunks, vlan); bitmap_set0(trunks, 0); } else { - trunks = (unsigned long *) s->trunks; + trunks = CONST_CAST(unsigned long *, s->trunks); } break; @@ -2457,9 +2477,14 @@ port_run(struct ofport_dpif *ofport) port_run_fast(ofport); if (ofport->cfm) { + int cfm_opup = cfm_get_opup(ofport->cfm); + cfm_run(ofport->cfm); - enable = enable && !cfm_get_fault(ofport->cfm) - && cfm_get_opup(ofport->cfm); + enable = enable && !cfm_get_fault(ofport->cfm); + + if (cfm_opup >= 0) { + enable = enable && cfm_opup; + } } if (ofport->bundle) { @@ -2507,7 +2532,7 @@ static int port_add(struct ofproto *ofproto_, struct netdev *netdev, uint16_t *ofp_portp) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); - uint16_t odp_port; + uint16_t odp_port = UINT16_MAX; int error; error = dpif_port_add(ofproto->dpif, netdev, &odp_port); @@ -2563,7 +2588,7 @@ port_get_stats(const struct ofport *ofport_, struct netdev_stats *stats) /* ofproto->stats.rx_packets represents packets that were received on * some port and we processed internally and dropped (e.g. STP). - * Account fro them as if they had been forwarded to OFPP_LOCAL. */ + * Account for them as if they had been forwarded to OFPP_LOCAL. */ if (stats->tx_packets != UINT64_MAX) { stats->tx_packets += ofproto->stats.rx_packets; @@ -2713,9 +2738,6 @@ send_packet_in_miss(struct ofproto_dpif *ofproto, const struct ofpbuf *packet, flow_get_metadata(flow, &pin.fmd); - /* Registers aren't meaningful on a miss. */ - memset(pin.fmd.reg_masks, 0, sizeof pin.fmd.reg_masks); - connmgr_send_packet_in(ofproto->up.connmgr, &pin); } @@ -2849,6 +2871,7 @@ handle_flow_miss_without_facet(struct flow_miss *miss, struct flow_miss_op *ops, size_t *n_ops) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); + long long int now = time_msec(); struct action_xlate_ctx ctx; struct ofpbuf *packet; @@ -2861,7 +2884,7 @@ handle_flow_miss_without_facet(struct flow_miss *miss, ofpbuf_use_stub(&odp_actions, op->stub, sizeof op->stub); - dpif_flow_stats_extract(&miss->flow, packet, &stats); + dpif_flow_stats_extract(&miss->flow, packet, now, &stats); rule_credit_stats(rule, &stats); action_xlate_ctx_init(&ctx, ofproto, &miss->flow, miss->initial_tci, @@ -2886,9 +2909,17 @@ handle_flow_miss_without_facet(struct flow_miss *miss, } /* Handles 'miss', which matches 'facet'. May add any required datapath - * operations to 'ops', incrementing '*n_ops' for each new op. */ + * operations to 'ops', incrementing '*n_ops' for each new op. + * + * All of the packets in 'miss' are considered to have arrived at time 'now'. + * This is really important only for new facets: if we just called time_msec() + * here, then the new subfacet or its packets could look (occasionally) as + * though it was used some time after the facet was used. That can make a + * one-packet flow look like it has a nonzero duration, which looks odd in + * e.g. NetFlow statistics. */ static void handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet, + long long int now, struct flow_miss_op *ops, size_t *n_ops) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto); @@ -2898,7 +2929,7 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet, subfacet = subfacet_create(facet, miss->key_fitness, miss->key, miss->key_len, - miss->initial_tci); + miss->initial_tci, now); LIST_FOR_EACH (packet, list_node, &miss->packets) { struct flow_miss_op *op = &ops[*n_ops]; @@ -2912,7 +2943,7 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet, subfacet_make_actions(subfacet, packet, &odp_actions); } - dpif_flow_stats_extract(&facet->flow, packet, &stats); + dpif_flow_stats_extract(&facet->flow, packet, now, &stats); subfacet_update_stats(subfacet, &stats); if (subfacet->actions_len) { @@ -2966,6 +2997,7 @@ handle_flow_miss(struct ofproto_dpif *ofproto, struct flow_miss *miss, struct flow_miss_op *ops, size_t *n_ops) { struct facet *facet; + long long int now; uint32_t hash; /* The caller must ensure that miss->hmap_node.hash contains @@ -2982,8 +3014,11 @@ handle_flow_miss(struct ofproto_dpif *ofproto, struct flow_miss *miss, } facet = facet_create(rule, &miss->flow, hash); + now = facet->used; + } else { + now = time_msec(); } - handle_flow_miss_with_facet(miss, facet, ops, n_ops); + handle_flow_miss_with_facet(miss, facet, now, ops, n_ops); } /* Like odp_flow_key_to_flow(), this function converts the 'key_len' bytes of @@ -3562,6 +3597,11 @@ rule_expire(struct rule_dpif *rule) long long int now; uint8_t reason; + if (rule->up.pending) { + /* We'll have to expire it later. */ + return; + } + /* Has 'rule' expired? */ now = time_msec(); if (rule->up.hard_timeout @@ -3769,7 +3809,8 @@ facet_is_controller_flow(struct facet *facet) const struct ofpact *ofpacts = rule->ofpacts; size_t ofpacts_len = rule->ofpacts_len; - if (ofpacts->type == OFPACT_CONTROLLER && + if (ofpacts_len > 0 && + ofpacts->type == OFPACT_CONTROLLER && ofpact_next(ofpacts) >= ofpact_end(ofpacts, ofpacts_len)) { return true; } @@ -4224,26 +4265,31 @@ subfacet_find__(struct ofproto_dpif *ofproto, * subfacet_make_actions(). */ static struct subfacet * subfacet_create(struct facet *facet, enum odp_key_fitness key_fitness, - const struct nlattr *key, size_t key_len, ovs_be16 initial_tci) + const struct nlattr *key, size_t key_len, + ovs_be16 initial_tci, long long int now) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto); uint32_t key_hash = odp_flow_key_hash(key, key_len); struct subfacet *subfacet; - subfacet = subfacet_find__(ofproto, key, key_len, key_hash, &facet->flow); - if (subfacet) { - if (subfacet->facet == facet) { - return subfacet; + if (list_is_empty(&facet->subfacets)) { + subfacet = &facet->one_subfacet; + } else { + subfacet = subfacet_find__(ofproto, key, key_len, key_hash, + &facet->flow); + if (subfacet) { + if (subfacet->facet == facet) { + return subfacet; + } + + /* This shouldn't happen. */ + VLOG_ERR_RL(&rl, "subfacet with wrong facet"); + subfacet_destroy(subfacet); } - /* This shouldn't happen. */ - VLOG_ERR_RL(&rl, "subfacet with wrong facet"); - subfacet_destroy(subfacet); + subfacet = xmalloc(sizeof *subfacet); } - subfacet = (list_is_empty(&facet->subfacets) - ? &facet->one_subfacet - : xmalloc(sizeof *subfacet)); hmap_insert(&ofproto->subfacets, &subfacet->hmap_node, key_hash); list_push_back(&facet->subfacets, &subfacet->list_node); subfacet->facet = facet; @@ -4255,7 +4301,7 @@ subfacet_create(struct facet *facet, enum odp_key_fitness key_fitness, subfacet->key = NULL; subfacet->key_len = 0; } - subfacet->used = time_msec(); + subfacet->used = now; subfacet->dp_packet_count = 0; subfacet->dp_byte_count = 0; subfacet->actions_len = 0; @@ -4503,7 +4549,6 @@ subfacet_update_stats(struct subfacet *subfacet, static struct rule_dpif * rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow) { - struct ofport_dpif *port; struct rule_dpif *rule; rule = rule_dpif_lookup__(ofproto, flow, 0); @@ -4511,16 +4556,7 @@ rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow) return rule; } - port = get_ofp_port(ofproto, flow->in_port); - if (!port) { - VLOG_WARN_RL(&rl, "packet-in on unknown port %"PRIu16, flow->in_port); - return ofproto->miss_rule; - } - - if (port->up.pp.config & OFPUTIL_PC_NO_PACKET_IN) { - return ofproto->no_packet_in_rule; - } - return ofproto->miss_rule; + return rule_dpif_miss_rule(ofproto, flow); } static struct rule_dpif * @@ -4549,6 +4585,23 @@ rule_dpif_lookup__(struct ofproto_dpif *ofproto, const struct flow *flow, return rule_dpif_cast(rule_from_cls_rule(cls_rule)); } +static struct rule_dpif * +rule_dpif_miss_rule(struct ofproto_dpif *ofproto, const struct flow *flow) +{ + struct ofport_dpif *port; + + port = get_ofp_port(ofproto, flow->in_port); + if (!port) { + VLOG_WARN_RL(&rl, "packet-in on unknown port %"PRIu16, flow->in_port); + return ofproto->miss_rule; + } + + if (port->up.pp.config & OFPUTIL_PC_NO_PACKET_IN) { + return ofproto->no_packet_in_rule; + } + return ofproto->miss_rule; +} + static void complete_operation(struct rule_dpif *rule) { @@ -4585,13 +4638,6 @@ rule_construct(struct rule *rule_) struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto); struct rule_dpif *victim; uint8_t table_id; - enum ofperr error; - - error = ofpacts_check(rule->up.ofpacts, rule->up.ofpacts_len, - &rule->up.cr.flow, ofproto->max_ports); - if (error) { - return error; - } rule->packet_count = 0; rule->byte_count = 0; @@ -4673,7 +4719,7 @@ rule_execute(struct rule *rule_, const struct flow *flow, uint64_t odp_actions_stub[1024 / 8]; struct ofpbuf odp_actions; - dpif_flow_stats_extract(flow, packet, &stats); + dpif_flow_stats_extract(flow, packet, time_msec(), &stats); rule_credit_stats(rule, &stats); ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub); @@ -4694,15 +4740,6 @@ 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); - enum ofperr error; - - error = ofpacts_check(rule->up.ofpacts, rule->up.ofpacts_len, - &rule->up.cr.flow, ofproto->max_ports); - if (error) { - ofoperation_complete(rule->up.pending, error); - return; - } complete_operation(rule); } @@ -4720,7 +4757,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet) struct flow flow; int error; - flow_extract((struct ofpbuf *) packet, 0, 0, 0, &flow); + flow_extract(packet, 0, 0, 0, &flow); odp_port = vsp_realdev_to_vlandev(ofproto, ofport->odp_port, flow.vlan_tci); if (odp_port != ofport->odp_port) { @@ -4953,7 +4990,7 @@ compose_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port) static void xlate_table_action(struct action_xlate_ctx *ctx, - uint16_t in_port, uint8_t table_id) + uint16_t in_port, uint8_t table_id, bool may_packet_in) { if (ctx->recurse < MAX_RESUBMIT_RECURSION) { struct ofproto_dpif *ofproto = ctx->ofproto; @@ -4989,6 +5026,17 @@ xlate_table_action(struct action_xlate_ctx *ctx, ctx->resubmit_hook(ctx, rule); } + if (rule == NULL && may_packet_in) { + /* TODO:XXX + * check if table configuration flags + * OFPTC_TABLE_MISS_CONTROLLER, default. + * OFPTC_TABLE_MISS_CONTINUE, + * OFPTC_TABLE_MISS_DROP + * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do? + */ + rule = rule_dpif_miss_rule(ofproto, &ctx->flow); + } + if (rule) { struct rule_dpif *old_rule = ctx->rule; @@ -5030,7 +5078,7 @@ xlate_ofpact_resubmit(struct action_xlate_ctx *ctx, table_id = ctx->table_id; } - xlate_table_action(ctx, in_port, table_id); + xlate_table_action(ctx, in_port, table_id, false); } static void @@ -5122,7 +5170,7 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len, } static bool -compose_dec_ttl(struct action_xlate_ctx *ctx) +compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids) { if (ctx->flow.dl_type != htons(ETH_TYPE_IP) && ctx->flow.dl_type != htons(ETH_TYPE_IPV6)) { @@ -5133,7 +5181,12 @@ compose_dec_ttl(struct action_xlate_ctx *ctx) ctx->flow.nw_ttl--; return false; } else { - execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0); + size_t i; + + for (i = 0; i < ids->n_controllers; i++) { + execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, + ids->cnt_ids[i]); + } /* Stop processing for current table. */ return true; @@ -5142,7 +5195,7 @@ compose_dec_ttl(struct action_xlate_ctx *ctx) static void xlate_output_action(struct action_xlate_ctx *ctx, - uint16_t port, uint16_t max_len) + uint16_t port, uint16_t max_len, bool may_packet_in) { uint16_t prev_nf_output_iface = ctx->nf_output_iface; @@ -5153,7 +5206,7 @@ xlate_output_action(struct action_xlate_ctx *ctx, compose_output_action(ctx, ctx->flow.in_port); break; case OFPP_TABLE: - xlate_table_action(ctx, ctx->flow.in_port, ctx->table_id); + xlate_table_action(ctx, ctx->flow.in_port, 0, may_packet_in); break; case OFPP_NORMAL: xlate_normal(ctx); @@ -5193,7 +5246,7 @@ xlate_output_reg_action(struct action_xlate_ctx *ctx, { uint64_t port = mf_get_subfield(&or->src, &ctx->flow); if (port <= UINT16_MAX) { - xlate_output_action(ctx, port, or->max_len); + xlate_output_action(ctx, port, or->max_len, false); } } @@ -5210,7 +5263,7 @@ xlate_enqueue_action(struct action_xlate_ctx *ctx, error = dpif_queue_to_priority(ctx->ofproto->dpif, queue_id, &priority); if (error) { /* Fall back to ordinary output action. */ - xlate_output_action(ctx, enqueue->port, 0); + xlate_output_action(ctx, enqueue->port, 0, false); return; } @@ -5305,7 +5358,7 @@ xlate_bundle_action(struct action_xlate_ctx *ctx, if (bundle->dst.field) { nxm_reg_load(&bundle->dst, port, &ctx->flow); } else { - xlate_output_action(ctx, port, 0); + xlate_output_action(ctx, port, 0, false); } } @@ -5403,7 +5456,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, switch (a->type) { case OFPACT_OUTPUT: xlate_output_action(ctx, ofpact_get_OUTPUT(a)->port, - ofpact_get_OUTPUT(a)->max_len); + ofpact_get_OUTPUT(a)->max_len, true); break; case OFPACT_CONTROLLER: @@ -5493,7 +5546,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_DEC_TTL: - if (compose_dec_ttl(ctx)) { + if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) { goto out; } break; @@ -5565,6 +5618,7 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx, ctx->may_learn = packet != NULL; ctx->tcp_flags = tcp_flags; ctx->resubmit_hook = NULL; + ctx->report_hook = NULL; ctx->resubmit_stats = NULL; } @@ -5691,6 +5745,14 @@ xlate_actions_for_side_effects(struct action_xlate_ctx *ctx, xlate_actions(ctx, ofpacts, ofpacts_len, &odp_actions); ofpbuf_uninit(&odp_actions); } + +static void +xlate_report(struct action_xlate_ctx *ctx, const char *s) +{ + if (ctx->report_hook) { + ctx->report_hook(ctx, s); + } +} /* OFPP_NORMAL implementation. */ @@ -6102,14 +6164,17 @@ lookup_input_bundle(const struct ofproto_dpif *ofproto, uint16_t in_port, * so in one special case. */ static bool -is_admissible(struct ofproto_dpif *ofproto, const struct flow *flow, - struct ofport_dpif *in_port, uint16_t vlan, tag_type *tags) +is_admissible(struct action_xlate_ctx *ctx, struct ofport_dpif *in_port, + uint16_t vlan) { + struct ofproto_dpif *ofproto = ctx->ofproto; + struct flow *flow = &ctx->flow; struct ofbundle *in_bundle = in_port->bundle; /* Drop frames for reserved multicast addresses * only if forward_bpdu option is absent. */ if (!ofproto->up.forward_bpdu && eth_addr_is_reserved(flow->dl_dst)) { + xlate_report(ctx, "packet has reserved destination MAC, dropping"); return false; } @@ -6117,11 +6182,12 @@ is_admissible(struct ofproto_dpif *ofproto, const struct flow *flow, struct mac_entry *mac; switch (bond_check_admissibility(in_bundle->bond, in_port, - flow->dl_dst, tags)) { + flow->dl_dst, &ctx->tags)) { case BV_ACCEPT: break; case BV_DROP: + xlate_report(ctx, "bonding refused admissibility, dropping"); return false; case BV_DROP_IF_MOVED: @@ -6129,6 +6195,8 @@ is_admissible(struct ofproto_dpif *ofproto, const struct flow *flow, if (mac && mac->port.p != in_bundle && (!is_gratuitous_arp(flow) || mac_entry_is_grat_arp_locked(mac))) { + xlate_report(ctx, "SLB bond thinks this packet looped back, " + "dropping"); return false; } break; @@ -6152,6 +6220,7 @@ xlate_normal(struct action_xlate_ctx *ctx) in_bundle = lookup_input_bundle(ctx->ofproto, ctx->flow.in_port, ctx->packet != NULL, &in_port); if (!in_bundle) { + xlate_report(ctx, "no input bundle, dropping"); return; } @@ -6164,6 +6233,7 @@ xlate_normal(struct action_xlate_ctx *ctx) "VLAN tag received on port %s", ctx->ofproto->up.name, in_bundle->name); } + xlate_report(ctx, "partial VLAN tag, dropping"); return; } @@ -6175,19 +6245,20 @@ xlate_normal(struct action_xlate_ctx *ctx) "%s, which is reserved exclusively for mirroring", ctx->ofproto->up.name, in_bundle->name); } + xlate_report(ctx, "input port is mirror output port, dropping"); return; } /* Check VLAN. */ vid = vlan_tci_to_vid(ctx->flow.vlan_tci); if (!input_vid_is_valid(vid, in_bundle, ctx->packet != NULL)) { + xlate_report(ctx, "disallowed VLAN VID for this input port, dropping"); return; } vlan = input_vid_to_vlan(in_bundle, vid); /* Check other admissibility requirements. */ - if (in_port && - !is_admissible(ctx->ofproto, &ctx->flow, in_port, vlan, &ctx->tags)) { + if (in_port && !is_admissible(ctx, in_port, vlan)) { return; } @@ -6201,11 +6272,15 @@ xlate_normal(struct action_xlate_ctx *ctx) &ctx->tags); if (mac) { if (mac->port.p != in_bundle) { + xlate_report(ctx, "forwarding to learned port"); output_normal(ctx, mac->port.p, vlan); + } else { + xlate_report(ctx, "learned port is input port, dropping"); } } else { struct ofbundle *bundle; + xlate_report(ctx, "no learned MAC for destination, flooding"); HMAP_FOR_EACH (bundle, hmap_node, &ctx->ofproto->bundles) { if (bundle != in_bundle && ofbundle_includes_vlan(bundle, vlan) @@ -6352,40 +6427,32 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet, const struct ofpact *ofpacts, size_t ofpacts_len) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); - enum ofperr error; - - if (flow->in_port >= ofproto->max_ports && flow->in_port < OFPP_MAX) { - return OFPERR_NXBRC_BAD_IN_PORT; - } + struct odputil_keybuf keybuf; + struct dpif_flow_stats stats; - error = ofpacts_check(ofpacts, ofpacts_len, flow, ofproto->max_ports); - if (!error) { - struct odputil_keybuf keybuf; - struct dpif_flow_stats stats; + struct ofpbuf key; - struct ofpbuf key; + struct action_xlate_ctx ctx; + uint64_t odp_actions_stub[1024 / 8]; + struct ofpbuf odp_actions; - struct action_xlate_ctx ctx; - uint64_t odp_actions_stub[1024 / 8]; - struct ofpbuf odp_actions; + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, flow); - ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); - odp_flow_key_from_flow(&key, flow); + dpif_flow_stats_extract(flow, packet, time_msec(), &stats); - dpif_flow_stats_extract(flow, packet, &stats); + action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, NULL, + packet_get_tcp_flags(packet, flow), packet); + ctx.resubmit_stats = &stats; - action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, NULL, - packet_get_tcp_flags(packet, flow), packet); - ctx.resubmit_stats = &stats; + ofpbuf_use_stub(&odp_actions, + odp_actions_stub, sizeof odp_actions_stub); + xlate_actions(&ctx, ofpacts, ofpacts_len, &odp_actions); + dpif_execute(ofproto->dpif, key.data, key.size, + odp_actions.data, odp_actions.size, packet); + ofpbuf_uninit(&odp_actions); - ofpbuf_use_stub(&odp_actions, - odp_actions_stub, sizeof odp_actions_stub); - xlate_actions(&ctx, ofpacts, ofpacts_len, &odp_actions); - dpif_execute(ofproto->dpif, key.data, key.size, - odp_actions.data, odp_actions.size, packet); - ofpbuf_uninit(&odp_actions); - } - return error; + return 0; } /* NetFlow. */ @@ -6595,6 +6662,17 @@ trace_resubmit(struct action_xlate_ctx *ctx, struct rule_dpif *rule) trace_format_rule(result, ctx->table_id, ctx->recurse + 1, rule); } +static void +trace_report(struct action_xlate_ctx *ctx, const char *s) +{ + struct trace_ctx *trace = CONTAINER_OF(ctx, struct trace_ctx, ctx); + struct ds *result = trace->result; + + ds_put_char_multiple(result, '\t', ctx->recurse); + ds_put_cstr(result, s); + ds_put_char(result, '\n'); +} + static void ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[], void *aux OVS_UNUSED) @@ -6745,6 +6823,7 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow, action_xlate_ctx_init(&trace.ctx, ofproto, flow, initial_tci, rule, tcp_flags, packet); trace.ctx.resubmit_hook = trace_resubmit; + trace.ctx.report_hook = trace_report; xlate_actions(&trace.ctx, rule->up.ofpacts, rule->up.ofpacts_len, &odp_actions); @@ -7122,6 +7201,7 @@ const struct ofproto_class ofproto_dpif_class = { set_sflow, set_cfm, get_cfm_fault, + get_cfm_opup, get_cfm_remote_mpids, get_cfm_health, set_stp,