X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=7650068e88c7340e0454204cfe158c8c1b615f0d;hb=bbb18ba723a1d82405961e4dd351a82758d633af;hp=79fe14c4d94f7be5c8fb47e2dc1b50b7904e19df;hpb=8cd4882fd5c3080816a070ad582ef06842f7c482;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 79fe14c4..7650068e 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -26,6 +26,7 @@ #include "coverage.h" #include "discovery.h" #include "dpif.h" +#include "dynamic-string.h" #include "executer.h" #include "fail-open.h" #include "in-band.h" @@ -51,6 +52,7 @@ #include "svec.h" #include "tag.h" #include "timeval.h" +#include "unixctl.h" #include "vconn.h" #include "vconn-ssl.h" #include "xtoxll.h" @@ -235,7 +237,7 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); static const struct ofhooks default_ofhooks; -static uint64_t pick_datapath_id(struct dpif *, uint64_t fallback_dpid); +static uint64_t pick_datapath_id(const struct ofproto *); static uint64_t pick_fallback_dpid(void); static void send_packet_in_miss(struct ofpbuf *, void *ofproto); static void send_packet_in_action(struct ofpbuf *, void *ofproto); @@ -259,7 +261,6 @@ int ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux, struct ofproto **ofprotop) { - struct netdev_monitor *netdev_monitor; struct odp_stats stats; struct ofproto *p; struct dpif *dpif; @@ -290,20 +291,10 @@ ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux, dpif_flow_flush(dpif); dpif_recv_purge(dpif); - /* Arrange to monitor datapath ports for status changes. */ - error = netdev_monitor_create(&netdev_monitor); - if (error) { - VLOG_ERR("failed to starting monitoring datapath %s: %s", - datapath, strerror(error)); - dpif_close(dpif); - return error; - } - /* Initialize settings. */ p = xcalloc(1, sizeof *p); p->fallback_dpid = pick_fallback_dpid(); - p->datapath_id = pick_datapath_id(dpif, p->fallback_dpid); - VLOG_INFO("using datapath ID %012"PRIx64, p->datapath_id); + p->datapath_id = p->fallback_dpid; p->manufacturer = xstrdup("Nicira Networks, Inc."); p->hardware = xstrdup("Reference Implementation"); p->software = xstrdup(VERSION BUILDNR); @@ -311,7 +302,7 @@ ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux, /* Initialize datapath. */ p->dpif = dpif; - p->netdev_monitor = netdev_monitor; + p->netdev_monitor = netdev_monitor_create(); port_array_init(&p->ports); shash_init(&p->port_by_name); p->max_ports = stats.max_ports; @@ -333,7 +324,7 @@ ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux, /* Initialize OpenFlow connections. */ list_init(&p->all_conns); - p->controller = ofconn_create(p, rconn_create(15, 15)); + p->controller = ofconn_create(p, rconn_create(5, 8)); p->controller->pktbuf = pktbuf_create(); p->controller->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; p->listeners = NULL; @@ -363,6 +354,10 @@ ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux, return error; } + /* Pick final datapath ID. */ + p->datapath_id = pick_datapath_id(p); + VLOG_INFO("using datapath ID %012"PRIx64, p->datapath_id); + *ofprotop = p; return 0; } @@ -371,9 +366,7 @@ void 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->dpif, p->fallback_dpid)); + p->datapath_id = datapath_id ? datapath_id : pick_datapath_id(p); if (p->datapath_id != old_dpid) { VLOG_INFO("datapath ID changed to %012"PRIx64, p->datapath_id); rconn_reconnect(p->controller->rconn); @@ -635,6 +628,12 @@ ofproto_get_datapath_id(const struct ofproto *ofproto) return ofproto->datapath_id; } +uint64_t +ofproto_get_mgmt_id(const struct ofproto *ofproto) +{ + return ofproto->mgmt_id; +} + int ofproto_get_probe_interval(const struct ofproto *ofproto) { @@ -1114,7 +1113,7 @@ make_ofport(const struct odp_port *odp_port) ofport = xmalloc(sizeof *ofport); ofport->netdev = netdev; ofport->opp.port_no = odp_port_to_ofp_port(odp_port->port); - memcpy(ofport->opp.hw_addr, netdev_get_etheraddr(netdev), ETH_ALEN); + netdev_get_etheraddr(netdev, ofport->opp.hw_addr); memcpy(ofport->opp.name, odp_port->devname, MIN(sizeof ofport->opp.name, sizeof odp_port->devname)); ofport->opp.name[sizeof ofport->opp.name - 1] = '\0'; @@ -1217,53 +1216,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); } @@ -1682,7 +1699,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; @@ -2109,6 +2126,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; } @@ -2477,6 +2501,59 @@ handle_flow_stats_request(struct ofproto *p, struct ofconn *ofconn, return 0; } +struct flow_stats_ds_cbdata { + struct ofproto *ofproto; + struct ds *results; +}; + +static void +flow_stats_ds_cb(struct cls_rule *rule_, void *cbdata_) +{ + struct rule *rule = rule_from_cls_rule(rule_); + struct flow_stats_ds_cbdata *cbdata = cbdata_; + struct ds *results = cbdata->results; + struct ofp_match match; + uint64_t packet_count, byte_count; + size_t act_len = sizeof *rule->actions * rule->n_actions; + + /* Don't report on subrules. */ + if (rule->super != NULL) { + return; + } + + query_stats(cbdata->ofproto, rule, &packet_count, &byte_count); + 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, "n_packets=%"PRIu64", ", packet_count); + ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count); + ofp_print_match(results, &match, true); + ofp_print_actions(results, &rule->actions->header, act_len); + ds_put_cstr(results, "\n"); +} + +/* Adds a pretty-printed description of all flows to 'results', including + * those marked hidden by secchan (e.g., by in-band control). */ +void +ofproto_get_all_flows(struct ofproto *p, struct ds *results) +{ + struct ofp_match match; + struct cls_rule target; + struct flow_stats_ds_cbdata cbdata; + + memset(&match, 0, sizeof match); + match.wildcards = htonl(OFPFW_ALL); + + cbdata.ofproto = p; + cbdata.results = results; + + cls_rule_from_match(&target, &match, 0); + classifier_for_each_match(&p->cls, &target, CLS_INC_ALL, + flow_stats_ds_cb, &cbdata); +} + struct aggregate_stats_cbdata { struct ofproto *ofproto; uint16_t out_port; @@ -2957,6 +3034,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. */ @@ -3060,7 +3148,7 @@ send_flow_exp(struct ofproto *p, struct rule *rule, { struct ofconn *ofconn; struct ofconn *prev; - struct ofpbuf *buf; + struct ofpbuf *buf = NULL; /* We limit the maximum number of queued flow expirations it by accounting * them under the counter for replies. That works because preventing @@ -3240,24 +3328,23 @@ send_packet_in_miss(struct ofpbuf *packet, void *p_) } static uint64_t -pick_datapath_id(struct dpif *dpif, uint64_t fallback_dpid) +pick_datapath_id(const struct ofproto *ofproto) { - char local_name[IF_NAMESIZE]; - uint8_t ea[ETH_ADDR_LEN]; - int error; + const struct ofport *port; - error = dpif_port_get_name(dpif, ODPP_LOCAL, - local_name, sizeof local_name); - if (!error) { - error = netdev_nodev_get_etheraddr(local_name, ea); + port = port_array_get(&ofproto->ports, ODPP_LOCAL); + if (port) { + uint8_t ea[ETH_ADDR_LEN]; + int error; + + error = netdev_get_etheraddr(port->netdev, ea); if (!error) { return eth_addr_to_uint64(ea); } VLOG_WARN("could not get MAC address for %s (%s)", - local_name, strerror(error)); + netdev_get_name(port->netdev), strerror(error)); } - - return fallback_dpid; + return ofproto->fallback_dpid; } static uint64_t