X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=ofproto%2Fofproto.c;h=cf491395c2d1d2eccb4078bcb7b73b19b8463648;hb=aae51f53358dc7946f7f09a88b1e0dd40306a99a;hp=050b4df1a961be4b6865bde485a3ec4a0008c647;hpb=eb15cdbbea5d8193af63bd2de948b99af30e648f;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 050b4df1..cf491395 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -36,6 +36,7 @@ #include "netflow.h" #include "odp-util.h" #include "ofp-print.h" +#include "ofp-util.h" #include "ofproto-sflow.h" #include "ofpbuf.h" #include "openflow/nicira-ext.h" @@ -410,15 +411,11 @@ ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id) uint64_t old_dpid = p->datapath_id; p->datapath_id = datapath_id ? datapath_id : pick_datapath_id(p); if (p->datapath_id != old_dpid) { - struct ofconn *ofconn; - VLOG_INFO("datapath ID changed to %016"PRIx64, p->datapath_id); /* Force all active connections to reconnect, since there is no way to * notify a controller that the datapath ID has changed. */ - LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) { - rconn_reconnect(ofconn->rconn); - } + ofproto_reconnect_controllers(p); } } @@ -663,6 +660,18 @@ ofproto_set_controllers(struct ofproto *p, } } +/* Drops the connections between 'ofproto' and all of its controllers, forcing + * them to reconnect. */ +void +ofproto_reconnect_controllers(struct ofproto *ofproto) +{ + struct ofconn *ofconn; + + LIST_FOR_EACH (ofconn, struct ofconn, node, &ofproto->all_conns) { + rconn_reconnect(ofconn->rconn); + } +} + static bool any_extras_changed(const struct ofproto *ofproto, const struct sockaddr_in *extras, size_t n) @@ -1477,7 +1486,7 @@ ofport_remove(struct ofproto *p, struct ofport *ofport) uint16_t odp_port = ofp_port_to_odp_port(ofport->opp.port_no); netdev_monitor_remove(p->netdev_monitor, ofport->netdev); - port_array_set(&p->ports, odp_port, NULL); + port_array_delete(&p->ports, odp_port); shash_delete(&p->port_by_name, shash_find(&p->port_by_name, (char *) ofport->opp.name)); if (p->sflow) { @@ -1797,7 +1806,7 @@ rule_has_out_port(const struct rule *rule, uint16_t out_port) } for (oa = actions_first(&i, rule->actions, rule->n_actions); oa; oa = actions_next(&i)) { - if (oa->type == htons(OFPAT_OUTPUT) && oa->output.port == out_port) { + if (action_outputs_to_port(oa, out_port)) { return true; } } @@ -2069,15 +2078,11 @@ is_controller_rule(struct rule *rule) * NetFlow expiration messages since it is just part of the control * logic for the network and not real traffic. */ - if (rule && rule->super) { - struct rule *super = rule->super; - - return super->n_actions == 1 && - super->actions[0].type == htons(OFPAT_OUTPUT) && - super->actions[0].output.port == htons(OFPP_CONTROLLER); - } - - return false; + return (rule + && rule->super + && rule->super->n_actions == 1 + && action_outputs_to_port(&rule->super->actions[0], + htons(OFPP_CONTROLLER))); } static void @@ -2194,7 +2199,8 @@ handle_features_request(struct ofproto *p, struct ofconn *ofconn, (1u << OFPAT_SET_NW_DST) | (1u << OFPAT_SET_NW_TOS) | (1u << OFPAT_SET_TP_SRC) | - (1u << OFPAT_SET_TP_DST)); + (1u << OFPAT_SET_TP_DST) | + (1u << OFPAT_ENQUEUE)); PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) { hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp)); @@ -2271,11 +2277,10 @@ add_output_group_action(struct odp_actions *actions, uint16_t group, } static void -add_controller_action(struct odp_actions *actions, - const struct ofp_action_output *oao) +add_controller_action(struct odp_actions *actions, uint16_t max_len) { union odp_action *a = odp_actions_add(actions, ODPAT_CONTROLLER); - a->controller.arg = ntohs(oao->max_len); + a->controller.arg = max_len; } struct action_xlate_ctx { @@ -2367,15 +2372,15 @@ xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port) } static void -xlate_output_action(struct action_xlate_ctx *ctx, - const struct ofp_action_output *oao) +xlate_output_action__(struct action_xlate_ctx *ctx, + uint16_t port, uint16_t max_len) { uint16_t odp_port; uint16_t prev_nf_output_iface = ctx->nf_output_iface; ctx->nf_output_iface = NF_OUT_DROP; - switch (ntohs(oao->port)) { + switch (port) { case OFPP_IN_PORT: add_output_action(ctx, ctx->flow.in_port); break; @@ -2399,13 +2404,13 @@ xlate_output_action(struct action_xlate_ctx *ctx, add_output_group_action(ctx->out, DP_GROUP_ALL, &ctx->nf_output_iface); break; case OFPP_CONTROLLER: - add_controller_action(ctx->out, oao); + add_controller_action(ctx->out, max_len); break; case OFPP_LOCAL: add_output_action(ctx, ODPP_LOCAL); break; default: - odp_port = ofp_port_to_odp_port(ntohs(oao->port)); + odp_port = ofp_port_to_odp_port(port); if (odp_port != ctx->flow.in_port) { add_output_action(ctx, odp_port); } @@ -2422,6 +2427,65 @@ xlate_output_action(struct action_xlate_ctx *ctx, } } +static void +xlate_output_action(struct action_xlate_ctx *ctx, + const struct ofp_action_output *oao) +{ + 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) +{ + size_t n = ctx->out->n_actions; + if (n > 0 && ctx->out->actions[n - 1].type == ODPAT_POP_PRIORITY) { + ctx->out->n_actions--; + } +} + +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; + int error; + + error = dpif_queue_to_priority(ctx->ofproto->dpif, ntohl(oae->queue_id), + &priority); + if (error) { + /* Fall back to ordinary output action. */ + xlate_output_action__(ctx, ntohs(oae->port), 0); + return; + } + + /* Figure out ODP output port. */ + ofp_port = ntohs(oae->port); + if (ofp_port != OFPP_IN_PORT) { + odp_port = ofp_port_to_odp_port(ofp_port); + } else { + odp_port = ctx->flow.in_port; + } + + /* Add ODP actions. */ + remove_pop_action(ctx); + odp_actions_add(ctx->out, ODPAT_SET_PRIORITY)->priority.priority + = priority; + add_output_action(ctx, odp_port); + odp_actions_add(ctx->out, ODPAT_POP_PRIORITY); + + /* Update NetFlow output port. */ + if (ctx->nf_output_iface == NF_OUT_DROP) { + ctx->nf_output_iface = odp_port; + } else if (ctx->nf_output_iface != NF_OUT_FLOOD) { + ctx->nf_output_iface = NF_OUT_MULTI; + } +} + static void xlate_nicira_action(struct action_xlate_ctx *ctx, const struct nx_action_header *nah) @@ -2445,7 +2509,7 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, break; /* If you add a new action here that modifies flow data, don't forget to - * update the flow key in ctx->flow in the same key. */ + * update the flow key in ctx->flow at the same time. */ default: VLOG_DBG_RL(&rl, "unknown Nicira action type %"PRIu16, subtype); @@ -2490,7 +2554,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, case OFPAT_STRIP_VLAN: odp_actions_add(ctx->out, ODPAT_STRIP_VLAN); - ctx->flow.dl_vlan = OFP_VLAN_NONE; + ctx->flow.dl_vlan = htons(OFP_VLAN_NONE); ctx->flow.dl_vlan_pcp = 0; break; @@ -2539,6 +2603,10 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, xlate_nicira_action(ctx, (const struct nx_action_header *) ia); break; + case OFPAT_ENQUEUE: + xlate_enqueue_action(ctx, (const struct ofp_action_enqueue *) ia); + break; + default: VLOG_DBG_RL(&rl, "unknown action type %"PRIu16, type); break; @@ -2566,6 +2634,7 @@ xlate_actions(const union ofp_action *in, size_t n_in, ctx.may_set_up_flow = true; ctx.nf_output_iface = NF_OUT_DROP; 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. */ @@ -3143,6 +3212,95 @@ handle_aggregate_stats_request(struct ofproto *p, struct ofconn *ofconn, return 0; } +struct queue_stats_cbdata { + struct ofconn *ofconn; + struct ofpbuf *msg; + uint16_t port_no; +}; + +static void +put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id, + const struct netdev_queue_stats *stats) +{ + struct ofp_queue_stats *reply; + + reply = append_stats_reply(sizeof *reply, cbdata->ofconn, &cbdata->msg); + reply->port_no = htons(cbdata->port_no); + memset(reply->pad, 0, sizeof reply->pad); + reply->queue_id = htonl(queue_id); + reply->tx_bytes = htonll(stats->tx_bytes); + reply->tx_packets = htonll(stats->tx_packets); + reply->tx_errors = htonll(stats->tx_errors); +} + +static void +handle_queue_stats_dump_cb(uint32_t queue_id, + struct netdev_queue_stats *stats, + void *cbdata_) +{ + struct queue_stats_cbdata *cbdata = cbdata_; + + put_queue_stats(cbdata, queue_id, stats); +} + +static void +handle_queue_stats_for_port(struct ofport *port, uint16_t port_no, + uint32_t queue_id, + struct queue_stats_cbdata *cbdata) +{ + cbdata->port_no = port_no; + if (queue_id == OFPQ_ALL) { + netdev_dump_queue_stats(port->netdev, + handle_queue_stats_dump_cb, cbdata); + } else { + struct netdev_queue_stats stats; + + netdev_get_queue_stats(port->netdev, queue_id, &stats); + put_queue_stats(cbdata, queue_id, &stats); + } +} + +static int +handle_queue_stats_request(struct ofproto *ofproto, struct ofconn *ofconn, + const struct ofp_stats_request *osr, + size_t arg_size) +{ + struct ofp_queue_stats_request *qsr; + struct queue_stats_cbdata cbdata; + struct ofport *port; + unsigned int port_no; + uint32_t queue_id; + + if (arg_size != sizeof *qsr) { + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + qsr = (struct ofp_queue_stats_request *) osr->body; + + COVERAGE_INC(ofproto_queue_req); + + cbdata.ofconn = ofconn; + cbdata.msg = start_stats_reply(osr, 128); + + port_no = ntohs(qsr->port_no); + queue_id = ntohl(qsr->queue_id); + if (port_no == OFPP_ALL) { + PORT_ARRAY_FOR_EACH (port, &ofproto->ports, port_no) { + handle_queue_stats_for_port(port, port_no, queue_id, &cbdata); + } + } else if (port_no < ofproto->max_ports) { + port = port_array_get(&ofproto->ports, port_no); + if (port) { + handle_queue_stats_for_port(port, port_no, queue_id, &cbdata); + } + } else { + ofpbuf_delete(cbdata.msg); + return ofp_mkerr(OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT); + } + queue_tx(cbdata.msg, ofconn, ofconn->reply_counter); + + return 0; +} + static int handle_stats_request(struct ofproto *p, struct ofconn *ofconn, struct ofp_header *oh) @@ -3174,6 +3332,9 @@ handle_stats_request(struct ofproto *p, struct ofconn *ofconn, case OFPST_PORT: return handle_port_stats_request(p, ofconn, osr, arg_size); + case OFPST_QUEUE: + return handle_queue_stats_request(p, ofconn, osr, arg_size); + case OFPST_VENDOR: return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR); @@ -3491,6 +3652,7 @@ static int handle_flow_mod(struct ofproto *p, struct ofconn *ofconn, struct ofp_flow_mod *ofm) { + struct ofp_match orig_match; size_t n_actions; int error; @@ -3512,7 +3674,25 @@ handle_flow_mod(struct ofproto *p, struct ofconn *ofconn, return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL); } + /* Normalize ofp->match. If normalization actually changes anything, then + * log the differences. */ + ofm->match.pad1[0] = ofm->match.pad2[0] = 0; + orig_match = ofm->match; normalize_match(&ofm->match); + if (memcmp(&ofm->match, &orig_match, sizeof orig_match)) { + static struct vlog_rate_limit normal_rl = VLOG_RATE_LIMIT_INIT(1, 1); + if (!VLOG_DROP_INFO(&normal_rl)) { + char *old = ofp_match_to_literal_string(&orig_match); + char *new = ofp_match_to_literal_string(&ofm->match); + VLOG_INFO("%s: normalization changed ofp_match, details:", + rconn_get_name(ofconn->rconn)); + VLOG_INFO(" pre: %s", old); + VLOG_INFO("post: %s", new); + free(old); + free(new); + } + } + if (!ofm->match.wildcards) { ofm->priority = htons(UINT16_MAX); }