X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=4ed29143709fcf80e42b159e49212f9cdd9820bd;hb=0e6644c3880be9684f37f48da84907bb67112514;hp=69639ac942dd14d5ab74ba3c6c8e78d6bbc2c81e;hpb=142e1f5c7e3b607ccf82d3989477e93adc59c8b6;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 69639ac9..4ed29143 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -268,6 +268,7 @@ static void facet_flush_stats(struct ofproto *, struct facet *); static void facet_make_actions(struct ofproto *, struct facet *, const struct ofpbuf *packet); +static void facet_reset_dp_stats(struct facet *, struct dpif_flow_stats *); static void facet_update_stats(struct ofproto *, struct facet *, const struct dpif_flow_stats *); static void facet_push_stats(struct ofproto *, struct facet *); @@ -913,7 +914,7 @@ int ofproto_port_del(struct ofproto *ofproto, uint16_t odp_port) { struct ofport *ofport = get_port(ofproto, odp_port); - const char *name = ofport ? ofport->opp.name : ""; + const char *name = ofport ? netdev_get_name(ofport->netdev) : ""; int error; error = dpif_port_del(ofproto->dpif, odp_port); @@ -921,8 +922,8 @@ ofproto_port_del(struct ofproto *ofproto, uint16_t odp_port) VLOG_ERR("%s: failed to remove port %"PRIu16" (%s) interface (%s)", dpif_name(ofproto->dpif), odp_port, name, strerror(error)); } else if (ofport) { - /* 'name' is ofport->opp.name and update_port() is going to destroy - * 'ofport'. Just in case update_port() refers to 'name' after it + /* 'name' is the netdev's name and update_port() is going to close the + * netdev. Just in case update_port() refers to 'name' after it * destroys 'ofport', make a copy of it around the update_port() * call. */ char *devname = xstrdup(name); @@ -1049,7 +1050,7 @@ reinit_ports(struct ofproto *p) sset_init(&devnames); HMAP_FOR_EACH (ofport, hmap_node, &p->ports) { - sset_add(&devnames, ofport->opp.name); + sset_add(&devnames, netdev_get_name(ofport->netdev)); } DPIF_PORT_FOR_EACH (&dpif_port, &dump, p->dpif) { sset_add(&devnames, dpif_port.name); @@ -1061,12 +1062,13 @@ reinit_ports(struct ofproto *p) sset_destroy(&devnames); } -static struct ofport * -make_ofport(const struct dpif_port *dpif_port) +/* Opens and returns a netdev for 'dpif_port', or a null pointer if the netdev + * cannot be opened. On success, also fills in 'opp', in *HOST* byte order. */ +static struct netdev * +ofport_open(const struct dpif_port *dpif_port, struct ofp_phy_port *opp) { struct netdev_options netdev_options; enum netdev_flags flags; - struct ofport *ofport; struct netdev *netdev; int error; @@ -1084,22 +1086,16 @@ make_ofport(const struct dpif_port *dpif_port) return NULL; } - ofport = xzalloc(sizeof *ofport); - ofport->netdev = netdev; - ofport->odp_port = dpif_port->port_no; - ofport->opp.port_no = odp_port_to_ofp_port(dpif_port->port_no); - netdev_get_etheraddr(netdev, ofport->opp.hw_addr); - ovs_strlcpy(ofport->opp.name, dpif_port->name, sizeof ofport->opp.name); - netdev_get_flags(netdev, &flags); - ofport->opp.config = flags & NETDEV_UP ? 0 : OFPPC_PORT_DOWN; - - ofport->opp.state = netdev_get_carrier(netdev) ? 0 : OFPPS_LINK_DOWN; - netdev_get_features(netdev, - &ofport->opp.curr, &ofport->opp.advertised, - &ofport->opp.supported, &ofport->opp.peer); - return ofport; + opp->port_no = odp_port_to_ofp_port(dpif_port->port_no); + netdev_get_etheraddr(netdev, opp->hw_addr); + ovs_strzcpy(opp->name, dpif_port->name, sizeof opp->name); + opp->config = flags & NETDEV_UP ? 0 : OFPPC_PORT_DOWN; + opp->state = netdev_get_carrier(netdev) ? 0 : OFPPS_LINK_DOWN; + netdev_get_features(netdev, &opp->curr, &opp->advertised, + &opp->supported, &opp->peer); + return netdev; } static bool @@ -1118,29 +1114,42 @@ ofport_conflicts(const struct ofproto *p, const struct dpif_port *dpif_port) } } -static int -ofport_equal(const struct ofport *a_, const struct ofport *b_) +/* Returns true if most fields of 'a' and 'b' are equal. Differences in name, + * port number, and 'config' bits other than OFPPC_PORT_DOWN are + * disregarded. */ +static bool +ofport_equal(const struct ofp_phy_port *a, const struct ofp_phy_port *b) { - const struct ofp_phy_port *a = &a_->opp; - const struct ofp_phy_port *b = &b_->opp; - BUILD_ASSERT_DECL(sizeof *a == 48); /* Detect ofp_phy_port changes. */ - return (a->port_no == b->port_no - && !memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr) - && !strcmp(a->name, b->name) + return (!memcmp(a->hw_addr, b->hw_addr, sizeof a->hw_addr) && a->state == b->state - && a->config == b->config + && !((a->config ^ b->config) & OFPPC_PORT_DOWN) && a->curr == b->curr && a->advertised == b->advertised && a->supported == b->supported && a->peer == b->peer); } +/* Adds an ofport to 'p' initialized based on the given 'netdev' and 'opp'. + * The caller must ensure that 'p' does not have a conflicting ofport (that is, + * one with the same name or port number). */ static void -ofport_install(struct ofproto *p, struct ofport *ofport) +ofport_install(struct ofproto *p, + struct netdev *netdev, const struct ofp_phy_port *opp) { - const char *netdev_name = ofport->opp.name; + const char *netdev_name = netdev_get_name(netdev); + struct ofport *ofport; + + connmgr_send_port_status(p->connmgr, opp, OFPPR_ADD); + /* Create ofport. */ + ofport = xmalloc(sizeof *ofport); + ofport->netdev = netdev; + ofport->opp = *opp; + ofport->odp_port = ofp_port_to_odp_port(opp->port_no); + ofport->cfm = NULL; + + /* Add port to 'p'. */ netdev_monitor_add(p->netdev_monitor, ofport->netdev); hmap_insert(&p->ports, &ofport->hmap_node, hash_int(ofport->odp_port, 0)); shash_add(&p->port_by_name, netdev_name, ofport); @@ -1149,16 +1158,59 @@ ofport_install(struct ofproto *p, struct ofport *ofport) } } +/* Removes 'ofport' from 'p' and destroys it. */ static void ofport_remove(struct ofproto *p, struct ofport *ofport) { + connmgr_send_port_status(p->connmgr, &ofport->opp, OFPPR_DELETE); + netdev_monitor_remove(p->netdev_monitor, ofport->netdev); hmap_remove(&p->ports, &ofport->hmap_node); shash_delete(&p->port_by_name, - shash_find(&p->port_by_name, ofport->opp.name)); + shash_find(&p->port_by_name, + netdev_get_name(ofport->netdev))); if (p->sflow) { ofproto_sflow_del_port(p->sflow, ofport->odp_port); } + + ofport_free(ofport); +} + +/* If 'ofproto' contains an ofport named 'name', removes it from 'ofproto' and + * destroys it. */ +static void +ofport_remove_with_name(struct ofproto *ofproto, const char *name) +{ + struct ofport *port = shash_find_data(&ofproto->port_by_name, name); + if (port) { + ofport_remove(ofproto, port); + } +} + +/* Updates 'port' within 'ofproto' with the new 'netdev' and 'opp'. + * + * Does not handle a name or port number change. The caller must implement + * such a change as a delete followed by an add. */ +static void +ofport_modified(struct ofproto *ofproto, struct ofport *port, + struct netdev *netdev, struct ofp_phy_port *opp) +{ + memcpy(port->opp.hw_addr, opp->hw_addr, ETH_ADDR_LEN); + port->opp.config = ((port->opp.config & ~OFPPC_PORT_DOWN) + | (opp->config & OFPPC_PORT_DOWN)); + port->opp.state = opp->state; + port->opp.curr = opp->curr; + port->opp.advertised = opp->advertised; + port->opp.supported = opp->supported; + port->opp.peer = opp->peer; + + netdev_monitor_remove(ofproto->netdev_monitor, port->netdev); + netdev_monitor_add(ofproto->netdev_monitor, netdev); + + netdev_close(port->netdev); + port->netdev = netdev; + + connmgr_send_port_status(ofproto->connmgr, &port->opp, OFPPR_MODIFY); } static void @@ -1214,75 +1266,42 @@ get_port(const struct ofproto *ofproto, uint16_t odp_port) } static void -update_port(struct ofproto *p, const char *devname) +update_port(struct ofproto *ofproto, const char *name) { struct dpif_port dpif_port; - struct ofport *old_ofport; - struct ofport *new_ofport; - int error; + struct ofp_phy_port opp; + struct netdev *netdev; + struct ofport *port; COVERAGE_INC(ofproto_update_port); - /* Query the datapath for port information. */ - error = dpif_port_query_by_name(p->dpif, devname, &dpif_port); - - /* 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 = get_port(p, dpif_port.port_no); - } - } else if (error != ENOENT && error != ENODEV) { - VLOG_WARN_RL(&rl, "dpif_port_query_by_name returned unexpected error " - "%s", strerror(error)); - goto exit; - } - - /* Create a new ofport. */ - new_ofport = !error ? make_ofport(&dpif_port) : NULL; - - /* Eliminate a few pathological cases. */ - if (!old_ofport && !new_ofport) { - goto exit; - } else if (old_ofport && new_ofport) { - /* Most of the 'config' bits are OpenFlow soft state, but - * OFPPC_PORT_DOWN is maintained by 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); - goto exit; + /* Fetch 'name''s location and properties from the datapath. */ + netdev = (!dpif_port_query_by_name(ofproto->dpif, name, &dpif_port) + ? ofport_open(&dpif_port, &opp) + : NULL); + if (netdev) { + port = get_port(ofproto, dpif_port.port_no); + if (port && !strcmp(netdev_get_name(port->netdev), name)) { + /* 'name' hasn't changed location. Any properties changed? */ + if (!ofport_equal(&port->opp, &opp)) { + ofport_modified(ofproto, port, netdev, &opp); + } else { + netdev_close(netdev); + } + } else { + /* If 'port' is nonnull then its name differs from 'name' and thus + * we should delete it. If we think there's a port named 'name' + * then its port number must be wrong now so delete it too. */ + if (port) { + ofport_remove(ofproto, port); + } + ofport_remove_with_name(ofproto, name); + ofport_install(ofproto, netdev, &opp); } + } else { + /* Any port named 'name' is gone now. */ + ofport_remove_with_name(ofproto, name); } - - /* Now deal with the normal cases. */ - if (old_ofport) { - ofport_remove(p, old_ofport); - } - if (new_ofport) { - ofport_install(p, new_ofport); - } - connmgr_send_port_status(p->connmgr, - new_ofport ? &new_ofport->opp : &old_ofport->opp, - (!old_ofport ? OFPPR_ADD - : !new_ofport ? OFPPR_DELETE - : OFPPR_MODIFY)); - ofport_free(old_ofport); - -exit: dpif_port_destroy(&dpif_port); } @@ -1294,9 +1313,12 @@ init_ports(struct ofproto *p) DPIF_PORT_FOR_EACH (&dpif_port, &dump, p->dpif) { if (!ofport_conflicts(p, &dpif_port)) { - struct ofport *ofport = make_ofport(&dpif_port); - if (ofport) { - ofport_install(p, ofport); + struct ofp_phy_port opp; + struct netdev *netdev; + + netdev = ofport_open(&dpif_port, &opp); + if (netdev) { + ofport_install(p, netdev, &opp); } } } @@ -1611,6 +1633,12 @@ facet_make_actions(struct ofproto *p, struct facet *facet, ofpbuf_delete(odp_actions); } +/* Updates 'facet''s flow in the datapath setting its actions to 'actions_len' + * bytes of actions in 'actions'. If 'stats' is non-null, statistics counters + * in the datapath will be zeroed and 'stats' will be updated with traffic new + * since 'facet' was last updated. + * + * Returns 0 if successful, otherwise a positive errno value.*/ static int facet_put__(struct ofproto *ofproto, struct facet *facet, const struct nlattr *actions, size_t actions_len, @@ -1619,19 +1647,24 @@ facet_put__(struct ofproto *ofproto, struct facet *facet, struct odputil_keybuf keybuf; enum dpif_flow_put_flags flags; struct ofpbuf key; + int ret; flags = DPIF_FP_CREATE | DPIF_FP_MODIFY; if (stats) { flags |= DPIF_FP_ZERO_STATS; - facet->dp_packet_count = 0; - facet->dp_byte_count = 0; } ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, &facet->flow); - return dpif_flow_put(ofproto->dpif, flags, key.data, key.size, - actions, actions_len, stats); + ret = dpif_flow_put(ofproto->dpif, flags, key.data, key.size, + actions, actions_len, stats); + + if (stats) { + facet_reset_dp_stats(facet, stats); + } + + return ret; } /* If 'facet' is installable, inserts or re-inserts it into 'p''s datapath. If @@ -1675,16 +1708,18 @@ facet_uninstall(struct ofproto *p, struct facet *facet) struct odputil_keybuf keybuf; struct dpif_flow_stats stats; struct ofpbuf key; + int error; ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); odp_flow_key_from_flow(&key, &facet->flow); - if (!dpif_flow_del(p->dpif, key.data, key.size, &stats)) { + error = dpif_flow_del(p->dpif, key.data, key.size, &stats); + facet_reset_dp_stats(facet, &stats); + if (!error) { facet_update_stats(p, facet, &stats); } + facet->installed = false; - facet->dp_packet_count = 0; - facet->dp_byte_count = 0; } else { assert(facet->dp_packet_count == 0); assert(facet->dp_byte_count == 0); @@ -1703,6 +1738,24 @@ facet_is_controller_flow(struct facet *facet) htons(OFPP_CONTROLLER))); } +/* Resets 'facet''s datapath statistics counters. This should be called when + * 'facet''s statistics are cleared in the datapath. If 'stats' is non-null, + * it should contain the statistics returned by dpif when 'facet' was reset in + * the datapath. 'stats' will be modified to only included statistics new + * since 'facet' was last updated. */ +static void +facet_reset_dp_stats(struct facet *facet, struct dpif_flow_stats *stats) +{ + if (stats && facet->dp_packet_count < stats->n_packets + && facet->dp_byte_count < stats->n_bytes) { + stats->n_packets -= facet->dp_packet_count; + stats->n_bytes -= facet->dp_byte_count; + } + + facet->dp_packet_count = 0; + facet->dp_byte_count = 0; +} + /* Folds all of 'facet''s statistics into its rule. Also updates the * accounting ofhook and emits a NetFlow expiration if appropriate. All of * 'facet''s statistics in the datapath should have been zeroed and folded into @@ -2725,8 +2778,7 @@ handle_table_stats_request(struct ofconn *ofconn, ots = append_ofp_stats_reply(sizeof *ots, ofconn, &msg); memset(ots, 0, sizeof *ots); strcpy(ots->name, "classifier"); - ots->wildcards = (ofconn_get_flow_format(ofconn) == NXFF_OPENFLOW10 - ? htonl(OFPFW_ALL) : htonl(OVSFW_ALL)); + ots->wildcards = htonl(OFPFW_ALL); ots->max_entries = htonl(1024 * 1024); /* An arbitrary big number. */ ots->active_count = htonl(classifier_count(&p->cls)); put_32aligned_be64(&ots->lookup_count, htonll(0)); /* XXX */ @@ -2814,7 +2866,6 @@ put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule, { struct ofp_flow_stats *ofs; uint64_t packet_count, byte_count; - ovs_be64 cookie; size_t act_len, len; if (rule_is_hidden(rule) || !rule_has_out_port(rule, out_port)) { @@ -2830,9 +2881,8 @@ put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule, ofs->length = htons(len); ofs->table_id = 0; ofs->pad = 0; - ofputil_cls_rule_to_match(&rule->cr, ofconn_get_flow_format(ofconn), - &ofs->match, rule->flow_cookie, &cookie); - put_32aligned_be64(&ofs->cookie, cookie); + ofputil_cls_rule_to_match(&rule->cr, &ofs->match); + put_32aligned_be64(&ofs->cookie, rule->flow_cookie); calc_flow_duration(rule->created, &ofs->duration_sec, &ofs->duration_nsec); ofs->priority = htons(rule->cr.priority); ofs->idle_timeout = htons(rule->idle_timeout); @@ -2874,8 +2924,7 @@ handle_flow_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) struct cls_rule target; struct rule *rule; - ofputil_cls_rule_from_match(&fsr->match, 0, NXFF_OPENFLOW10, 0, - &target); + ofputil_cls_rule_from_match(&fsr->match, 0, &target); cls_cursor_init(&cursor, &ofproto->cls, &target); CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { put_ofp_flow_stats(ofconn, rule, fsr->out_port, &reply); @@ -3047,8 +3096,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn, struct cls_rule target; struct ofpbuf *msg; - ofputil_cls_rule_from_match(&request->match, 0, NXFF_OPENFLOW10, 0, - &target); + ofputil_cls_rule_from_match(&request->match, 0, &target); msg = start_ofp_stats_reply(oh, sizeof *reply); reply = append_ofp_stats_reply(sizeof *reply, ofconn, &msg); @@ -3495,7 +3543,7 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh) return error; } - error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_flow_format(ofconn)); + error = ofputil_decode_flow_mod(&fm, oh); if (error) { return error; } @@ -3537,19 +3585,6 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh) } } -static int -handle_tun_id_from_cookie(struct ofconn *ofconn, const struct ofp_header *oh) -{ - const struct nxt_tun_id_cookie *msg - = (const struct nxt_tun_id_cookie *) oh; - enum nx_flow_format flow_format; - - flow_format = msg->set ? NXFF_TUN_ID_FROM_COOKIE : NXFF_OPENFLOW10; - ofconn_set_flow_format(ofconn, flow_format); - - return 0; -} - static int handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh) { @@ -3590,7 +3625,6 @@ handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh) format = ntohl(msg->format); if (format == NXFF_OPENFLOW10 - || format == NXFF_TUN_ID_FROM_COOKIE || format == NXFF_NXM) { ofconn_set_flow_format(ofconn, format); return 0; @@ -3655,9 +3689,6 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) return 0; /* Nicira extension requests. */ - case OFPUTIL_NXT_TUN_ID_FROM_COOKIE: - return handle_tun_id_from_cookie(ofconn, oh); - case OFPUTIL_NXT_ROLE_REQUEST: return handle_role_request(ofconn, oh); @@ -4174,13 +4205,6 @@ static void send_packet_in(struct ofproto *ofproto, struct dpif_upcall *upcall, const struct flow *flow, bool clone) { - struct ofputil_packet_in pin; - - pin.packet = upcall->packet; - pin.in_port = odp_port_to_ofp_port(flow->in_port); - pin.reason = upcall->type == DPIF_UC_MISS ? OFPR_NO_MATCH : OFPR_ACTION; - pin.buffer_id = 0; /* not yet known */ - pin.send_len = upcall->userdata; connmgr_send_packet_in(ofproto->connmgr, upcall, flow, clone ? NULL : upcall->packet); }