X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=secchan%2Fofproto.c;h=72adbc4c563fc888bd9c6853711b02f2351bbbda;hb=372179d4f4a1dc6113bc4ea60cee76cb354e22f4;hp=9f3a8496365cfab3037b84b62ce1442ecf71d19f;hpb=4f2cad2c3b1079ede2d3eed0dd25423552105255;p=openvswitch diff --git a/secchan/ofproto.c b/secchan/ofproto.c index 9f3a8496..72adbc4c 100644 --- a/secchan/ofproto.c +++ b/secchan/ofproto.c @@ -433,8 +433,8 @@ ofproto_set_in_band(struct ofproto *p, bool in_band) { if (in_band != (p->in_band != NULL)) { if (in_band) { - in_band_create(p, p->switch_status, p->controller->rconn, - &p->in_band); + in_band_create(p, &p->dpif, p->switch_status, + p->controller->rconn, &p->in_band); return 0; } else { ofproto_set_discovery(p, false, NULL, true); @@ -1213,53 +1213,71 @@ static void update_port(struct ofproto *p, const char *devname) { struct odp_port odp_port; - struct ofport *ofport; + struct ofport *old_ofport; + struct ofport *new_ofport; int error; COVERAGE_INC(ofproto_update_port); - ofport = shash_find_data(&p->port_by_name, devname); + + /* Query the datapath for port information. */ error = dpif_port_query_by_name(&p->dpif, devname, &odp_port); - if (!error) { - if (!ofport) { - /* New port. */ - if (!ofport_conflicts(p, &odp_port)) { - ofport = make_ofport(&odp_port); - if (ofport) { - ofport_install(p, ofport); - send_port_status(p, ofport, OFPPR_ADD); - } - } - } else { - /* Modified port. */ - struct ofport *new_ofport = make_ofport(&odp_port); - if (!new_ofport) { - return; - } - new_ofport->opp.config &= OFPPC_PORT_DOWN; - new_ofport->opp.config |= ofport->opp.config & ~OFPPC_PORT_DOWN; - if (ofport_equal(ofport, new_ofport)) { - /* False alarm--no change. */ - ofport_free(new_ofport); - } else { - ofport_remove(p, ofport); - ofport_install(p, new_ofport); - ofport_free(ofport); - send_port_status(p, new_ofport, OFPPR_MODIFY); - } - } - } else if (error == ENOENT || error == ENODEV) { - /* Deleted port. */ - if (ofport) { - send_port_status(p, ofport, OFPPR_DELETE); - ofport_remove(p, ofport); - ofport_free(ofport); + /* Find the old ofport. */ + old_ofport = shash_find_data(&p->port_by_name, devname); + if (!error) { + if (!old_ofport) { + /* There's no port named 'devname' but there might be a port with + * the same port number. This could happen if a port is deleted + * and then a new one added in its place very quickly, or if a port + * is renamed. In the former case we want to send an OFPPR_DELETE + * and an OFPPR_ADD, and in the latter case we want to send a + * single OFPPR_MODIFY. We can distinguish the cases by comparing + * the old port's ifindex against the new port, or perhaps less + * reliably but more portably by comparing the old port's MAC + * against the new port's MAC. However, this code isn't that smart + * and always sends an OFPPR_MODIFY (XXX). */ + old_ofport = port_array_get(&p->ports, odp_port.port); } - } else { + } else if (error != ENOENT && error != ENODEV) { VLOG_WARN_RL(&rl, "dpif_port_query_by_name returned unexpected error " "%s", strerror(error)); return; } + + /* Create a new ofport. */ + new_ofport = !error ? make_ofport(&odp_port) : NULL; + + /* Eliminate a few pathological cases. */ + if (!old_ofport && !new_ofport) { + return; + } else if (old_ofport && new_ofport) { + /* Most of the 'config' bits are OpenFlow soft state, but + * OFPPC_PORT_DOWN is maintained the kernel. So transfer the OpenFlow + * bits from old_ofport. (make_ofport() only sets OFPPC_PORT_DOWN and + * leaves the other bits 0.) */ + new_ofport->opp.config |= old_ofport->opp.config & ~OFPPC_PORT_DOWN; + + if (ofport_equal(old_ofport, new_ofport)) { + /* False alarm--no change. */ + ofport_free(new_ofport); + return; + } + } + + /* Now deal with the normal cases. */ + if (old_ofport) { + ofport_remove(p, old_ofport); + } + if (new_ofport) { + ofport_install(p, new_ofport); + } + send_port_status(p, new_ofport ? new_ofport : old_ofport, + (!old_ofport ? OFPPR_ADD + : !new_ofport ? OFPPR_DELETE + : OFPPR_MODIFY)); + ofport_free(old_ofport); + + /* Update port groups. */ refresh_port_groups(p); } @@ -1678,7 +1696,7 @@ rule_post_uninstall(struct ofproto *ofproto, struct rule *rule) struct rule *super = rule->super; rule_account(ofproto, rule, 0); - if (ofproto->netflow) { + if (ofproto->netflow && rule->byte_count) { struct ofexpired expired; expired.flow = rule->cr.flow; expired.packet_count = rule->packet_count; @@ -2105,6 +2123,13 @@ xlate_actions(const union ofp_action *in, size_t n_in, ctx.tags = tags ? tags : &no_tags; ctx.may_setup_flow = true; do_xlate_actions(in, n_in, &ctx); + + /* Check with in-band control to see if we're allowed to setup this + * flow. */ + if (!in_band_rule_check(ofproto->in_band, flow, out)) { + ctx.may_setup_flow = false; + } + if (may_setup_flow) { *may_setup_flow = ctx.may_setup_flow; } @@ -2494,11 +2519,11 @@ flow_stats_ds_cb(struct cls_rule *rule_, void *cbdata_) } query_stats(cbdata->ofproto, rule, &packet_count, &byte_count); - flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &match); + flow_to_ovs_match(&rule->cr.flow, rule->cr.wc.wildcards, &match); ds_put_format(results, "duration=%llds, ", (time_msec() - rule->created) / 1000); - ds_put_format(results, "priority=%u", rule->cr.priority); + ds_put_format(results, "priority=%u, ", rule->cr.priority); ds_put_format(results, "n_packets=%"PRIu64", ", packet_count); ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count); ofp_print_match(results, &match, true); @@ -3006,6 +3031,17 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet) payload.size = msg->length - sizeof *msg; flow_extract(&payload, msg->port, &flow); + /* Check with in-band control to see if this packet should be sent + * to the local port regardless of the flow table. */ + if (in_band_msg_in_hook(p->in_band, &flow, &payload)) { + union odp_action action; + + memset(&action, 0, sizeof(action)); + action.output.type = ODPAT_OUTPUT; + action.output.port = ODPP_LOCAL; + dpif_execute(&p->dpif, flow.in_port, &action, 1, &payload); + } + rule = lookup_valid_rule(p, &flow); if (!rule) { /* Don't send a packet-in if OFPPC_NO_PACKET_IN asserted. */ @@ -3121,7 +3157,7 @@ send_flow_exp(struct ofproto *p, struct rule *rule, LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) { if (ofconn->send_flow_exp && rconn_is_connected(ofconn->rconn)) { if (prev) { - queue_tx(ofpbuf_clone(buf), prev, ofconn->reply_counter); + queue_tx(ofpbuf_clone(buf), prev, prev->reply_counter); } else { buf = compose_flow_exp(rule, now, reason); } @@ -3129,7 +3165,7 @@ send_flow_exp(struct ofproto *p, struct rule *rule, } } if (prev) { - queue_tx(buf, prev, ofconn->reply_counter); + queue_tx(buf, prev, prev->reply_counter); } } @@ -3228,25 +3264,22 @@ static void do_send_packet_in(struct ofconn *ofconn, uint32_t buffer_id, const struct ofpbuf *packet, int send_len) { - struct ofp_packet_in *opi; - struct ofpbuf payload, *buf; - struct odp_msg *msg; + struct odp_msg *msg = packet->data; + struct ofpbuf payload; + struct ofpbuf *opi; + uint8_t reason; - msg = packet->data; + /* Extract packet payload from 'msg'. */ payload.data = msg + 1; payload.size = msg->length - sizeof *msg; - send_len = MIN(send_len, payload.size); - buf = ofpbuf_new(sizeof *opi + send_len); - opi = put_openflow_xid(offsetof(struct ofp_packet_in, data), - OFPT_PACKET_IN, 0, buf); - opi->buffer_id = htonl(buffer_id); - opi->total_len = htons(payload.size); - opi->in_port = htons(odp_port_to_ofp_port(msg->port)); - opi->reason = msg->type == _ODPL_ACTION_NR ? OFPR_ACTION : OFPR_NO_MATCH; - ofpbuf_put(buf, payload.data, MIN(send_len, payload.size)); - update_openflow_length(buf); - rconn_send_with_limit(ofconn->rconn, buf, ofconn->packet_in_counter, 100); + /* Construct ofp_packet_in message. */ + reason = msg->type == _ODPL_ACTION_NR ? OFPR_ACTION : OFPR_NO_MATCH; + opi = make_packet_in(buffer_id, odp_port_to_ofp_port(msg->port), reason, + &payload, send_len); + + /* Send. */ + rconn_send_with_limit(ofconn->rconn, opi, ofconn->packet_in_counter, 100); } static void