X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=f757b58094019d6aed244014a0c71f4b4be01fe9;hb=1ce0a5fa82f1a0013dd62713d16fde973b029eb7;hp=2efb03afd32a6e4be217c9a51417ad3639471fd7;hpb=a02e5331f6064a7b9dd11f1091ab9fcb1bbdadcc;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 2efb03af..f757b580 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -25,9 +25,9 @@ #include #include #include "byte-order.h" +#include "cfm.h" #include "classifier.h" #include "coverage.h" -#include "discovery.h" #include "dpif.h" #include "dynamic-string.h" #include "fail-open.h" @@ -54,7 +54,6 @@ #include "poll-loop.h" #include "rconn.h" #include "shash.h" -#include "status.h" #include "stream-ssl.h" #include "svec.h" #include "tag.h" @@ -91,8 +90,6 @@ COVERAGE_DEFINE(ofproto_unexpected_rule); COVERAGE_DEFINE(ofproto_uninstallable); COVERAGE_DEFINE(ofproto_update_port); -#include "sflow_api.h" - /* Maximum depth of flow table recursion (due to NXAST_RESUBMIT actions) in a * flow translation. */ #define MAX_RESUBMIT_RECURSION 16 @@ -104,10 +101,12 @@ struct ofport { struct netdev *netdev; struct ofp_phy_port opp; /* In host byte order. */ uint16_t odp_port; + struct cfm *cfm; /* Connectivity Fault Management, if any. */ }; static void ofport_free(struct ofport *); -static void hton_ofp_phy_port(struct ofp_phy_port *); +static void ofport_run(struct ofproto *, struct ofport *); +static void ofport_wait(struct ofport *); struct action_xlate_ctx { /* action_xlate_ctx_init() initializes these members. */ @@ -335,8 +334,6 @@ struct ofconn { /* type == OFCONN_PRIMARY only. */ enum nx_role role; /* Role. */ struct hmap_node hmap_node; /* In struct ofproto's "controllers" map. */ - struct discovery *discovery; /* Controller discovery object, if enabled. */ - struct status_category *ss; /* Switch status category. */ enum ofproto_band band; /* In-band or out-of-band? */ }; @@ -346,10 +343,24 @@ static struct ofconn *ofconn_create(struct ofproto *, struct rconn *, static void ofconn_destroy(struct ofconn *); static void ofconn_run(struct ofconn *); static void ofconn_wait(struct ofconn *); + static bool ofconn_receives_async_msgs(const struct ofconn *); static char *ofconn_make_name(const struct ofproto *, const char *target); static void ofconn_set_rate_limit(struct ofconn *, int rate, int burst); +static struct ofproto *ofconn_get_ofproto(struct ofconn *); + +static enum nx_flow_format ofconn_get_flow_format(struct ofconn *); +static void ofconn_set_flow_format(struct ofconn *, enum nx_flow_format); + +static int ofconn_get_miss_send_len(const struct ofconn *); +static void ofconn_set_miss_send_len(struct ofconn *, int miss_send_len); + +static enum ofconn_type ofconn_get_type(const struct ofconn *); + +static enum nx_role ofconn_get_role(const struct ofconn *); +static void ofconn_set_role(struct ofconn *, enum nx_role); + static void queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn, struct rconn_packet_counter *counter); @@ -375,7 +386,6 @@ struct ofproto { uint32_t max_ports; /* Configuration. */ - struct switch_status *switch_status; struct fail_open *fail_open; struct netflow *netflow; struct ofproto_sflow *sflow; @@ -490,7 +500,6 @@ ofproto_create(const char *datapath, const char *datapath_type, p->max_ports = dpif_get_max_ports(dpif); /* Initialize submodules. */ - p->switch_status = switch_status_create(p); p->fail_open = NULL; p->netflow = NULL; p->sflow = NULL; @@ -550,82 +559,47 @@ ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id) } } -static bool -is_discovery_controller(const struct ofproto_controller *c) -{ - return !strcmp(c->target, "discover"); -} - -static bool -is_in_band_controller(const struct ofproto_controller *c) -{ - return is_discovery_controller(c) || c->band == OFPROTO_IN_BAND; -} - /* Creates a new controller in 'ofproto'. Some of the settings are initially * drawn from 'c', but update_controller() needs to be called later to finish * the new ofconn's configuration. */ static void add_controller(struct ofproto *ofproto, const struct ofproto_controller *c) { - struct discovery *discovery; + char *name = ofconn_make_name(ofproto, c->target); struct ofconn *ofconn; - if (is_discovery_controller(c)) { - int error = discovery_create(c->accept_re, c->update_resolv_conf, - ofproto->dpif, ofproto->switch_status, - &discovery); - if (error) { - return; - } - } else { - discovery = NULL; - } - ofconn = ofconn_create(ofproto, rconn_create(5, 8), OFCONN_PRIMARY); ofconn->pktbuf = pktbuf_create(); ofconn->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; - if (discovery) { - ofconn->discovery = discovery; - } else { - char *name = ofconn_make_name(ofproto, c->target); - rconn_connect(ofconn->rconn, c->target, name); - free(name); - } + rconn_connect(ofconn->rconn, c->target, name); hmap_insert(&ofproto->controllers, &ofconn->hmap_node, hash_string(c->target, 0)); + + free(name); } /* Reconfigures 'ofconn' to match 'c'. This function cannot update an ofconn's - * target or turn discovery on or off (these are done by creating new ofconns - * and deleting old ones), but it can update the rest of an ofconn's - * settings. */ + * target (this is done by creating new ofconns and deleting old ones), but it + * can update the rest of an ofconn's settings. */ static void update_controller(struct ofconn *ofconn, const struct ofproto_controller *c) { int probe_interval; - ofconn->band = (is_in_band_controller(c) - ? OFPROTO_IN_BAND : OFPROTO_OUT_OF_BAND); + ofconn->band = c->band; rconn_set_max_backoff(ofconn->rconn, c->max_backoff); probe_interval = c->probe_interval ? MAX(c->probe_interval, 5) : 0; rconn_set_probe_interval(ofconn->rconn, probe_interval); - if (ofconn->discovery) { - discovery_set_update_resolv_conf(ofconn->discovery, - c->update_resolv_conf); - discovery_set_accept_controller_re(ofconn->discovery, c->accept_re); - } - ofconn_set_rate_limit(ofconn, c->rate_limit, c->burst_limit); } static const char * ofconn_get_target(const struct ofconn *ofconn) { - return ofconn->discovery ? "discover" : rconn_get_target(ofconn->rconn); + return rconn_get_target(ofconn->rconn); } static struct ofconn * @@ -648,7 +622,6 @@ update_in_band_remotes(struct ofproto *ofproto) const struct ofconn *ofconn; struct sockaddr_in *addrs; size_t max_addrs, n_addrs; - bool discovery; size_t i; /* Allocate enough memory for as many remotes as we could possibly have. */ @@ -657,7 +630,6 @@ update_in_band_remotes(struct ofproto *ofproto) n_addrs = 0; /* Add all the remotes. */ - discovery = false; HMAP_FOR_EACH (ofconn, hmap_node, &ofproto->controllers) { struct sockaddr_in *sin = &addrs[n_addrs]; @@ -670,23 +642,15 @@ update_in_band_remotes(struct ofproto *ofproto) sin->sin_port = rconn_get_remote_port(ofconn->rconn); n_addrs++; } - if (ofconn->discovery) { - discovery = true; - } } for (i = 0; i < ofproto->n_extra_remotes; i++) { addrs[n_addrs++] = ofproto->extra_in_band_remotes[i]; } - /* Create or update or destroy in-band. - * - * Ordinarily we only enable in-band if there's at least one remote - * address, but discovery needs the in-band rules for DHCP to be installed - * even before we know any remote addresses. */ - if (n_addrs || discovery) { + /* Create or update or destroy in-band. */ + if (n_addrs) { if (!ofproto->in_band) { - in_band_create(ofproto, ofproto->dpif, ofproto->switch_status, - &ofproto->in_band); + in_band_create(ofproto, ofproto->dpif, &ofproto->in_band); } if (ofproto->in_band) { in_band_set_remotes(ofproto->in_band, addrs, n_addrs); @@ -713,7 +677,7 @@ update_fail_open(struct ofproto *p) size_t n; if (!p->fail_open) { - p->fail_open = fail_open_create(p, p->switch_status); + p->fail_open = fail_open_create(p); } n = 0; @@ -738,7 +702,6 @@ ofproto_set_controllers(struct ofproto *p, struct shash new_controllers; struct ofconn *ofconn, *next_ofconn; struct ofservice *ofservice, *next_ofservice; - bool ss_exists; size_t i; /* Create newly configured controllers and services. @@ -747,7 +710,7 @@ ofproto_set_controllers(struct ofproto *p, for (i = 0; i < n_controllers; i++) { const struct ofproto_controller *c = &controllers[i]; - if (!vconn_verify_name(c->target) || !strcmp(c->target, "discover")) { + if (!vconn_verify_name(c->target)) { if (!find_controller_by_target(p, c->target)) { add_controller(p, c); } @@ -766,7 +729,6 @@ ofproto_set_controllers(struct ofproto *p, /* Delete controllers that are no longer configured. * Update configuration of all now-existing controllers. */ - ss_exists = false; HMAP_FOR_EACH_SAFE (ofconn, next_ofconn, hmap_node, &p->controllers) { struct ofproto_controller *c; @@ -775,9 +737,6 @@ ofproto_set_controllers(struct ofproto *p, ofconn_destroy(ofconn); } else { update_controller(ofconn, c); - if (ofconn->ss) { - ss_exists = true; - } } } @@ -799,13 +758,6 @@ ofproto_set_controllers(struct ofproto *p, update_in_band_remotes(p); update_fail_open(p); - - if (!hmap_is_empty(&p->controllers) && !ss_exists) { - ofconn = CONTAINER_OF(hmap_first(&p->controllers), - struct ofconn, hmap_node); - ofconn->ss = switch_status_register(p->switch_status, "remote", - rconn_status_cb, ofconn->rconn); - } } void @@ -1012,7 +964,70 @@ ofproto_set_sflow(struct ofproto *ofproto, ofproto->sflow = NULL; } } + +/* Connectivity Fault Management configuration. */ +/* Clears the CFM configuration from 'port_no' on 'ofproto'. */ +void +ofproto_iface_clear_cfm(struct ofproto *ofproto, uint32_t port_no) +{ + struct ofport *ofport = get_port(ofproto, port_no); + if (ofport && ofport->cfm){ + cfm_destroy(ofport->cfm); + ofport->cfm = NULL; + } +} + +/* Configures connectivity fault management on 'port_no' in 'ofproto'. Takes + * basic configuration from the configuration members in 'cfm', and the set of + * remote maintenance points from the 'n_remote_mps' elements in 'remote_mps'. + * Ignores the statistics members of 'cfm'. + * + * This function has no effect if 'ofproto' does not have a port 'port_no'. */ +void +ofproto_iface_set_cfm(struct ofproto *ofproto, uint32_t port_no, + const struct cfm *cfm, + const uint16_t *remote_mps, size_t n_remote_mps) +{ + struct ofport *ofport; + + ofport = get_port(ofproto, port_no); + if (!ofport) { + VLOG_WARN("%s: cannot configure CFM on nonexistent port %"PRIu32, + dpif_name(ofproto->dpif), port_no); + return; + } + + if (!ofport->cfm) { + ofport->cfm = cfm_create(); + } + + ofport->cfm->mpid = cfm->mpid; + ofport->cfm->interval = cfm->interval; + memcpy(ofport->cfm->maid, cfm->maid, CCM_MAID_LEN); + + cfm_update_remote_mps(ofport->cfm, remote_mps, n_remote_mps); + + if (!cfm_configure(ofport->cfm)) { + VLOG_WARN("%s: CFM configuration on port %"PRIu32" (%s) failed", + dpif_name(ofproto->dpif), port_no, + netdev_get_name(ofport->netdev)); + cfm_destroy(ofport->cfm); + ofport->cfm = NULL; + } +} + +/* Returns the connectivity fault management object associated with 'port_no' + * within 'ofproto', or a null pointer if 'ofproto' does not have a port + * 'port_no' or if that port does not have CFM configured. The caller must not + * modify or destroy the returned object. */ +const struct cfm * +ofproto_iface_get_cfm(struct ofproto *ofproto, uint32_t port_no) +{ + struct ofport *ofport = get_port(ofproto, port_no); + return ofport ? ofport->cfm : NULL; +} + uint64_t ofproto_get_datapath_id(const struct ofproto *ofproto) { @@ -1080,7 +1095,6 @@ ofproto_destroy(struct ofproto *p) } shash_destroy(&p->port_by_name); - switch_status_destroy(p->switch_status); netflow_destroy(p->netflow); ofproto_sflow_destroy(p->sflow); @@ -1134,7 +1148,7 @@ process_port_change(struct ofproto *ofproto, int error, char *devname) static int snoop_preference(const struct ofconn *ofconn) { - switch (ofconn->role) { + switch (ofconn_get_role(ofconn)) { case NX_ROLE_MASTER: return 3; case NX_ROLE_OTHER: @@ -1157,7 +1171,7 @@ add_snooper(struct ofproto *ofproto, struct vconn *vconn) /* Pick a controller for monitoring. */ best = NULL; LIST_FOR_EACH (ofconn, node, &ofproto->all_conns) { - if (ofconn->type == OFCONN_PRIMARY + if (ofconn_get_type(ofconn) == OFCONN_PRIMARY && (!best || snoop_preference(ofconn) > snoop_preference(best))) { best = ofconn; } @@ -1176,6 +1190,7 @@ ofproto_run1(struct ofproto *p) { struct ofconn *ofconn, *next_ofconn; struct ofservice *ofservice; + struct ofport *ofport; char *devname; int error; int i; @@ -1212,6 +1227,10 @@ ofproto_run1(struct ofproto *p) process_port_change(p, error, devname); } + HMAP_FOR_EACH (ofport, hmap_node, &p->ports) { + ofport_run(p, ofport); + } + if (p->in_band) { if (time_msec() >= p->next_in_band_update) { update_in_band_remotes(p); @@ -1312,11 +1331,15 @@ ofproto_wait(struct ofproto *p) { struct ofservice *ofservice; struct ofconn *ofconn; + struct ofport *ofport; size_t i; dpif_recv_wait(p->dpif); dpif_port_poll_wait(p->dpif); netdev_monitor_poll_wait(p->netdev_monitor); + HMAP_FOR_EACH (ofport, hmap_node, &p->ports) { + ofport_wait(ofport); + } LIST_FOR_EACH (ofconn, node, &p->all_conns) { ofconn_wait(ofconn); } @@ -1367,7 +1390,7 @@ ofproto_is_alive(const struct ofproto *p) } void -ofproto_get_ofproto_controller_info(const struct ofproto * ofproto, +ofproto_get_ofproto_controller_info(const struct ofproto *ofproto, struct shash *info) { const struct ofconn *ofconn; @@ -1376,13 +1399,16 @@ ofproto_get_ofproto_controller_info(const struct ofproto * ofproto, HMAP_FOR_EACH (ofconn, hmap_node, &ofproto->controllers) { const struct rconn *rconn = ofconn->rconn; + time_t now = time_now(); + time_t last_connection = rconn_get_last_connection(rconn); + time_t last_disconnect = rconn_get_last_disconnect(rconn); const int last_error = rconn_get_last_error(rconn); struct ofproto_controller_info *cinfo = xmalloc(sizeof *cinfo); shash_add(info, rconn_get_target(rconn), cinfo); cinfo->is_connected = rconn_is_connected(rconn); - cinfo->role = ofconn->role; + cinfo->role = ofconn_get_role(ofconn); cinfo->pairs.n = 0; @@ -1396,9 +1422,17 @@ ofproto_get_ofproto_controller_info(const struct ofproto * ofproto, cinfo->pairs.values[cinfo->pairs.n++] = xstrdup(rconn_get_state(rconn)); - cinfo->pairs.keys[cinfo->pairs.n] = "time_in_state"; - cinfo->pairs.values[cinfo->pairs.n++] = - xasprintf("%u", rconn_get_state_elapsed(rconn)); + if (last_connection != TIME_MIN) { + cinfo->pairs.keys[cinfo->pairs.n] = "sec_since_connect"; + cinfo->pairs.values[cinfo->pairs.n++] + = xasprintf("%ld", (long int) (now - last_connection)); + } + + if (last_disconnect != TIME_MIN) { + cinfo->pairs.keys[cinfo->pairs.n] = "sec_since_disconnect"; + cinfo->pairs.values[cinfo->pairs.n++] + = xasprintf("%ld", (long int) (now - last_disconnect)); + } } } @@ -1459,26 +1493,34 @@ ofproto_port_is_floodable(struct ofproto *ofproto, uint16_t odp_port) return ofport && !(ofport->opp.config & OFPPC_NO_FLOOD); } +/* Sends 'packet' out of port 'port_no' within 'p'. If 'vlan_tci' is zero the + * packet will not have any 802.1Q hader; if it is nonzero, then the packet + * will be sent with the VLAN TCI specified by 'vlan_tci & ~VLAN_CFI'. + * + * Returns 0 if successful, otherwise a positive errno value. */ int -ofproto_send_packet(struct ofproto *p, const struct flow *flow, - const union ofp_action *actions, size_t n_actions, +ofproto_send_packet(struct ofproto *ofproto, + uint32_t port_no, uint16_t vlan_tci, const struct ofpbuf *packet) { - struct action_xlate_ctx ctx; - struct ofpbuf *odp_actions; - - action_xlate_ctx_init(&ctx, p, flow, packet); - /* Always xlate packets originated in this function. */ - ctx.check_special = false; - odp_actions = xlate_actions(&ctx, actions, n_actions); - - /* XXX Should we translate the dpif_execute() errno value into an OpenFlow - * error code? */ - dpif_execute(p->dpif, odp_actions->data, odp_actions->size, packet); + struct ofpbuf odp_actions; + int error; - ofpbuf_delete(odp_actions); + ofpbuf_init(&odp_actions, 32); + if (vlan_tci != 0) { + nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_SET_DL_TCI, + ntohs(vlan_tci & ~VLAN_CFI)); + } + nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_OUTPUT, port_no); + error = dpif_execute(ofproto->dpif, odp_actions.data, odp_actions.size, + packet); + ofpbuf_uninit(&odp_actions); - return 0; + if (error) { + VLOG_WARN_RL(&rl, "%s: failed to send packet on port %"PRIu32" (%s)", + dpif_name(ofproto->dpif), port_no, strerror(error)); + } + return error; } /* Adds a flow to the OpenFlow flow table in 'p' that matches 'cls_rule' and @@ -1657,7 +1699,7 @@ send_port_status(struct ofproto *p, const struct ofport *ofport, /* Primary controllers, even slaves, should always get port status updates. Otherwise obey ofconn_receives_async_msgs(). */ - if (ofconn->type != OFCONN_PRIMARY + if (ofconn_get_type(ofconn) != OFCONN_PRIMARY && !ofconn_receives_async_msgs(ofconn)) { continue; } @@ -1695,10 +1737,39 @@ ofport_remove(struct ofproto *p, struct ofport *ofport) } } +static void +ofport_run(struct ofproto *ofproto, struct ofport *ofport) +{ + if (ofport->cfm) { + cfm_run(ofport->cfm); + + if (cfm_should_send_ccm(ofport->cfm)) { + struct ofpbuf packet; + struct ccm *ccm; + + ofpbuf_init(&packet, 0); + ccm = compose_packet(&packet, eth_addr_ccm, ofport->opp.hw_addr, + ETH_TYPE_CFM, sizeof *ccm); + cfm_compose_ccm(ofport->cfm, ccm); + ofproto_send_packet(ofproto, ofport->odp_port, 0, &packet); + ofpbuf_uninit(&packet); + } + } +} + +static void +ofport_wait(struct ofport *ofport) +{ + if (ofport->cfm) { + cfm_wait(ofport->cfm); + } +} + static void ofport_free(struct ofport *ofport) { if (ofport) { + cfm_destroy(ofport->cfm); netdev_close(ofport->netdev); free(ofport); } @@ -1828,13 +1899,13 @@ ofconn_create(struct ofproto *p, struct rconn *rconn, enum ofconn_type type) static void ofconn_destroy(struct ofconn *ofconn) { - if (ofconn->type == OFCONN_PRIMARY) { - hmap_remove(&ofconn->ofproto->controllers, &ofconn->hmap_node); + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); + + if (ofconn_get_type(ofconn) == OFCONN_PRIMARY) { + hmap_remove(&ofproto->controllers, &ofconn->hmap_node); } - discovery_destroy(ofconn->discovery); list_remove(&ofconn->node); - switch_status_unregister(ofconn->ss); rconn_destroy(ofconn->rconn); rconn_packet_counter_destroy(ofconn->packet_in_counter); rconn_packet_counter_destroy(ofconn->reply_counter); @@ -1845,27 +1916,10 @@ ofconn_destroy(struct ofconn *ofconn) static void ofconn_run(struct ofconn *ofconn) { - struct ofproto *p = ofconn->ofproto; + struct ofproto *p = ofconn_get_ofproto(ofconn); int iteration; size_t i; - if (ofconn->discovery) { - char *controller_name; - if (rconn_is_connectivity_questionable(ofconn->rconn)) { - discovery_question_connectivity(ofconn->discovery); - } - if (discovery_run(ofconn->discovery, &controller_name)) { - if (controller_name) { - char *ofconn_name = ofconn_make_name(p, controller_name); - rconn_connect(ofconn->rconn, controller_name, ofconn_name); - free(ofconn_name); - free(controller_name); - } else { - rconn_disconnect(ofconn->rconn); - } - } - } - for (i = 0; i < N_SCHEDULERS; i++) { pinsched_run(ofconn->schedulers[i], do_send_packet_in, ofconn); } @@ -1888,7 +1942,7 @@ ofconn_run(struct ofconn *ofconn) } } - if (!ofconn->discovery && !rconn_is_alive(ofconn->rconn)) { + if (!rconn_is_alive(ofconn->rconn)) { ofconn_destroy(ofconn); } } @@ -1898,9 +1952,6 @@ ofconn_wait(struct ofconn *ofconn) { int i; - if (ofconn->discovery) { - discovery_wait(ofconn->discovery); - } for (i = 0; i < N_SCHEDULERS; i++) { pinsched_wait(ofconn->schedulers[i]); } @@ -1916,10 +1967,10 @@ ofconn_wait(struct ofconn *ofconn) static bool ofconn_receives_async_msgs(const struct ofconn *ofconn) { - if (ofconn->type == OFCONN_PRIMARY) { + if (ofconn_get_type(ofconn) == OFCONN_PRIMARY) { /* Primary controllers always get asynchronous messages unless they * have configured themselves as "slaves". */ - return ofconn->role != NX_ROLE_SLAVE; + return ofconn_get_role(ofconn) != NX_ROLE_SLAVE; } else { /* Service connections don't get asynchronous messages unless they have * explicitly asked for them by setting a nonzero miss send length. */ @@ -1949,8 +2000,7 @@ ofconn_set_rate_limit(struct ofconn *ofconn, int rate, int burst) if (rate > 0) { if (!*s) { - *s = pinsched_create(rate, burst, - ofconn->ofproto->switch_status); + *s = pinsched_create(rate, burst); } else { pinsched_set_limits(*s, rate, burst); } @@ -1960,6 +2010,54 @@ ofconn_set_rate_limit(struct ofconn *ofconn, int rate, int burst) } } } + +static struct ofproto * +ofconn_get_ofproto(struct ofconn *ofconn) +{ + return ofconn->ofproto; +} + +static enum nx_flow_format +ofconn_get_flow_format(struct ofconn *ofconn) +{ + return ofconn->flow_format; +} + +static void +ofconn_set_flow_format(struct ofconn *ofconn, enum nx_flow_format flow_format) +{ + ofconn->flow_format = flow_format; +} + +static int +ofconn_get_miss_send_len(const struct ofconn *ofconn) +{ + return ofconn->miss_send_len; +} + +static void +ofconn_set_miss_send_len(struct ofconn *ofconn, int miss_send_len) +{ + ofconn->miss_send_len = miss_send_len; +} + +static enum ofconn_type +ofconn_get_type(const struct ofconn *ofconn) +{ + return ofconn->type; +} + +static enum nx_role +ofconn_get_role(const struct ofconn *ofconn) +{ + return ofconn->role; +} + +static void +ofconn_set_role(struct ofconn *ofconn, enum nx_role role) +{ + ofconn->role = role; +} static void ofservice_reconfigure(struct ofservice *ofservice, @@ -2161,12 +2259,10 @@ facet_execute(struct ofproto *ofproto, struct facet *facet, assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in)); flow_extract_stats(&facet->flow, packet, &stats); + stats.used = time_msec(); if (execute_odp_actions(ofproto, &facet->flow, facet->actions, facet->actions_len, packet)) { - facet->used = time_msec(); facet_update_stats(ofproto, facet, &stats); - netflow_flow_update_time(ofproto->netflow, - &facet->nf_flow, facet->used); } } @@ -2589,6 +2685,12 @@ queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn, } } +static void +ofconn_send_reply(const struct ofconn *ofconn, struct ofpbuf *msg) +{ + queue_tx(msg, ofconn, ofconn->reply_counter); +} + static void send_error_oh(const struct ofconn *ofconn, const struct ofp_header *oh, int error) @@ -2596,38 +2698,27 @@ send_error_oh(const struct ofconn *ofconn, const struct ofp_header *oh, struct ofpbuf *buf = ofputil_encode_error_msg(error, oh); if (buf) { COVERAGE_INC(ofproto_error); - queue_tx(buf, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, buf); } } -static void -hton_ofp_phy_port(struct ofp_phy_port *opp) -{ - opp->port_no = htons(opp->port_no); - opp->config = htonl(opp->config); - opp->state = htonl(opp->state); - opp->curr = htonl(opp->curr); - opp->advertised = htonl(opp->advertised); - opp->supported = htonl(opp->supported); - opp->peer = htonl(opp->peer); -} - static int handle_echo_request(struct ofconn *ofconn, const struct ofp_header *oh) { - queue_tx(make_echo_reply(oh), ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, make_echo_reply(oh)); return 0; } static int handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh) { + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct ofp_switch_features *osf; struct ofpbuf *buf; struct ofport *port; osf = make_openflow_xid(sizeof *osf, OFPT_FEATURES_REPLY, oh->xid, &buf); - osf->datapath_id = htonll(ofconn->ofproto->datapath_id); + osf->datapath_id = htonll(ofproto->datapath_id); osf->n_buffers = htonl(pktbuf_capacity()); osf->n_tables = 2; osf->capabilities = htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS | @@ -2645,31 +2736,32 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh) (1u << OFPAT_SET_TP_DST) | (1u << OFPAT_ENQUEUE)); - HMAP_FOR_EACH (port, hmap_node, &ofconn->ofproto->ports) { + HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) { hton_ofp_phy_port(ofpbuf_put(buf, &port->opp, sizeof port->opp)); } - queue_tx(buf, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, buf); return 0; } static int handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh) { + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct ofpbuf *buf; struct ofp_switch_config *osc; uint16_t flags; bool drop_frags; /* Figure out flags. */ - dpif_get_drop_frags(ofconn->ofproto->dpif, &drop_frags); + dpif_get_drop_frags(ofproto->dpif, &drop_frags); flags = drop_frags ? OFPC_FRAG_DROP : OFPC_FRAG_NORMAL; /* Send reply. */ osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf); osc->flags = htons(flags); - osc->miss_send_len = htons(ofconn->miss_send_len); - queue_tx(buf, ofconn, ofconn->reply_counter); + osc->miss_send_len = htons(ofconn_get_miss_send_len(ofconn)); + ofconn_send_reply(ofconn, buf); return 0; } @@ -2677,15 +2769,17 @@ handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh) static int handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc) { + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); uint16_t flags = ntohs(osc->flags); - if (ofconn->type == OFCONN_PRIMARY && ofconn->role != NX_ROLE_SLAVE) { + if (ofconn_get_type(ofconn) == OFCONN_PRIMARY + && ofconn_get_role(ofconn) != NX_ROLE_SLAVE) { switch (flags & OFPC_FRAG_MASK) { case OFPC_FRAG_NORMAL: - dpif_set_drop_frags(ofconn->ofproto->dpif, false); + dpif_set_drop_frags(ofproto->dpif, false); break; case OFPC_FRAG_DROP: - dpif_set_drop_frags(ofconn->ofproto->dpif, true); + dpif_set_drop_frags(ofproto->dpif, true); break; default: VLOG_WARN_RL(&rl, "requested bad fragment mode (flags=%"PRIx16")", @@ -2694,7 +2788,7 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc) } } - ofconn->miss_send_len = ntohs(osc->miss_send_len); + ofconn_set_miss_send_len(ofconn, ntohs(osc->miss_send_len)); return 0; } @@ -3153,6 +3247,18 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx, ctx->check_special = true; } +static void +ofproto_process_cfm(struct ofproto *ofproto, const struct flow *flow, + const struct ofpbuf *packet) +{ + struct ofport *ofport; + + ofport = get_port(ofproto, flow->in_port); + if (ofport && ofport->cfm) { + cfm_process_heartbeat(ofport->cfm, packet); + } +} + static struct ofpbuf * xlate_actions(struct action_xlate_ctx *ctx, const union ofp_action *in, size_t n_in) @@ -3166,13 +3272,18 @@ xlate_actions(struct action_xlate_ctx *ctx, ctx->recurse = 0; ctx->last_pop_priority = -1; - if (!ctx->check_special - || !ctx->ofproto->ofhooks->special_cb - || ctx->ofproto->ofhooks->special_cb(&ctx->flow, ctx->packet, - ctx->ofproto->aux)) { - do_xlate_actions(in, n_in, ctx); - } else { + if (ctx->check_special && cfm_should_process_flow(&ctx->flow)) { + if (ctx->packet) { + ofproto_process_cfm(ctx->ofproto, &ctx->flow, ctx->packet); + } ctx->may_set_up_flow = false; + } else if (ctx->check_special + && ctx->ofproto->ofhooks->special_cb + && !ctx->ofproto->ofhooks->special_cb(&ctx->flow, ctx->packet, + ctx->ofproto->aux)) { + ctx->may_set_up_flow = false; + } else { + do_xlate_actions(in, n_in, ctx); } remove_pop_action(ctx); @@ -3195,7 +3306,8 @@ xlate_actions(struct action_xlate_ctx *ctx, static int reject_slave_controller(struct ofconn *ofconn, const const char *msg_type) { - if (ofconn->type == OFCONN_PRIMARY && ofconn->role == NX_ROLE_SLAVE) { + if (ofconn_get_type(ofconn) == OFCONN_PRIMARY + && ofconn_get_role(ofconn) == NX_ROLE_SLAVE) { static struct vlog_rate_limit perm_rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&perm_rl, "rejecting %s message from slave controller", msg_type); @@ -3209,7 +3321,7 @@ reject_slave_controller(struct ofconn *ofconn, const const char *msg_type) static int handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh) { - struct ofproto *p = ofconn->ofproto; + struct ofproto *p = ofconn_get_ofproto(ofconn); struct ofp_packet_out *opo; struct ofpbuf payload, *buffer; union ofp_action *ofp_actions; @@ -3299,7 +3411,7 @@ update_port_config(struct ofproto *p, struct ofport *port, static int handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh) { - struct ofproto *p = ofconn->ofproto; + struct ofproto *p = ofconn_get_ofproto(ofconn); const struct ofp_port_mod *opm = (const struct ofp_port_mod *) oh; struct ofport *port; int error; @@ -3354,7 +3466,7 @@ append_ofp_stats_reply(size_t nbytes, struct ofconn *ofconn, struct ofp_stats_reply *reply = msg->data; reply->flags = htons(OFPSF_REPLY_MORE); *msgp = make_ofp_stats_reply(reply->header.xid, reply->type, nbytes); - queue_tx(msg, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, msg); } return ofpbuf_put_uninit(*msgp, nbytes); } @@ -3390,7 +3502,7 @@ append_nxstats_reply(size_t nbytes, struct ofconn *ofconn, struct nicira_stats_msg *reply = msg->data; reply->flags = htons(OFPSF_REPLY_MORE); *msgp = make_nxstats_reply(reply->header.xid, reply->subtype, nbytes); - queue_tx(msg, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, msg); } ofpbuf_prealloc_tailroom(*msgp, nbytes); } @@ -3399,7 +3511,7 @@ static int handle_desc_stats_request(struct ofconn *ofconn, const struct ofp_header *request) { - struct ofproto *p = ofconn->ofproto; + struct ofproto *p = ofconn_get_ofproto(ofconn); struct ofp_desc_stats *ods; struct ofpbuf *msg; @@ -3411,7 +3523,7 @@ handle_desc_stats_request(struct ofconn *ofconn, ovs_strlcpy(ods->sw_desc, p->sw_desc, sizeof ods->sw_desc); ovs_strlcpy(ods->serial_num, p->serial_desc, sizeof ods->serial_num); ovs_strlcpy(ods->dp_desc, p->dp_desc, sizeof ods->dp_desc); - queue_tx(msg, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, msg); return 0; } @@ -3420,7 +3532,7 @@ static int handle_table_stats_request(struct ofconn *ofconn, const struct ofp_header *request) { - struct ofproto *p = ofconn->ofproto; + struct ofproto *p = ofconn_get_ofproto(ofconn); struct ofp_table_stats *ots; struct ofpbuf *msg; @@ -3430,14 +3542,14 @@ 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->flow_format == NXFF_OPENFLOW10 + ots->wildcards = (ofconn_get_flow_format(ofconn) == NXFF_OPENFLOW10 ? htonl(OFPFW_ALL) : htonl(OVSFW_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 */ put_32aligned_be64(&ots->matched_count, htonll(0)); /* XXX */ - queue_tx(msg, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, msg); return 0; } @@ -3473,7 +3585,7 @@ append_port_stat(struct ofport *port, struct ofconn *ofconn, static int handle_port_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) { - struct ofproto *p = ofconn->ofproto; + struct ofproto *p = ofconn_get_ofproto(ofconn); const struct ofp_port_stats_request *psr = ofputil_stats_body(oh); struct ofp_port_stats *ops; struct ofpbuf *msg; @@ -3491,16 +3603,26 @@ handle_port_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) } } - queue_tx(msg, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, msg); return 0; } static void -calc_flow_duration(long long int start, ovs_be32 *sec, ovs_be32 *nsec) +calc_flow_duration__(long long int start, uint32_t *sec, uint32_t *nsec) { long long int msecs = time_msec() - start; - *sec = htonl(msecs / 1000); - *nsec = htonl((msecs % 1000) * (1000 * 1000)); + *sec = msecs / 1000; + *nsec = (msecs % 1000) * (1000 * 1000); +} + +static void +calc_flow_duration(long long int start, ovs_be32 *sec_be, ovs_be32 *nsec_be) +{ + uint32_t sec, nsec; + + calc_flow_duration__(start, &sec, &nsec); + *sec_be = htonl(sec); + *nsec_be = htonl(nsec); } static void @@ -3525,8 +3647,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->flow_format, &ofs->match, - rule->flow_cookie, &cookie); + ofputil_cls_rule_to_match(&rule->cr, ofconn_get_flow_format(ofconn), + &ofs->match, rule->flow_cookie, &cookie); put_32aligned_be64(&ofs->cookie, cookie); calc_flow_duration(rule->created, &ofs->duration_sec, &ofs->duration_nsec); ofs->priority = htons(rule->cr.priority); @@ -3559,6 +3681,7 @@ static int handle_flow_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) { const struct ofp_flow_stats_request *fsr = ofputil_stats_body(oh); + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct ofpbuf *reply; COVERAGE_INC(ofproto_flows_req); @@ -3570,12 +3693,12 @@ handle_flow_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) ofputil_cls_rule_from_match(&fsr->match, 0, NXFF_OPENFLOW10, 0, &target); - cls_cursor_init(&cursor, &ofconn->ofproto->cls, &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); } } - queue_tx(reply, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, reply); return 0; } @@ -3622,6 +3745,7 @@ put_nx_flow_stats(struct ofconn *ofconn, struct rule *rule, static int handle_nxst_flow(struct ofconn *ofconn, const struct ofp_header *oh) { + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct nx_flow_stats_request *nfsr; struct cls_rule target; struct ofpbuf *reply; @@ -3646,12 +3770,12 @@ handle_nxst_flow(struct ofconn *ofconn, const struct ofp_header *oh) struct cls_cursor cursor; struct rule *rule; - cls_cursor_init(&cursor, &ofconn->ofproto->cls, &target); + cls_cursor_init(&cursor, &ofproto->cls, &target); CLS_CURSOR_FOR_EACH (rule, cr, &cursor) { put_nx_flow_stats(ofconn, rule, nfsr->out_port, &reply); } } - queue_tx(reply, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, reply); return 0; } @@ -3681,7 +3805,7 @@ flow_stats_ds(struct rule *rule, struct ds *results) } /* Adds a pretty-printed description of all flows to 'results', including - * those marked hidden by secchan (e.g., by in-band control). */ + * hidden flows (e.g., set up by in-band control). */ void ofproto_get_all_flows(struct ofproto *p, struct ds *results) { @@ -3735,6 +3859,7 @@ handle_aggregate_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) { const struct ofp_aggregate_stats_request *request = ofputil_stats_body(oh); + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct ofp_aggregate_stats_reply *reply; struct cls_rule target; struct ofpbuf *msg; @@ -3744,15 +3869,16 @@ handle_aggregate_stats_request(struct ofconn *ofconn, msg = start_ofp_stats_reply(oh, sizeof *reply); reply = append_ofp_stats_reply(sizeof *reply, ofconn, &msg); - query_aggregate_stats(ofconn->ofproto, &target, request->out_port, + query_aggregate_stats(ofproto, &target, request->out_port, request->table_id, reply); - queue_tx(msg, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, msg); return 0; } static int handle_nxst_aggregate(struct ofconn *ofconn, const struct ofp_header *oh) { + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct nx_aggregate_stats_request *request; struct ofp_aggregate_stats_reply *reply; struct cls_rule target; @@ -3776,9 +3902,9 @@ handle_nxst_aggregate(struct ofconn *ofconn, const struct ofp_header *oh) COVERAGE_INC(ofproto_flows_req); buf = start_nxstats_reply(&request->nsm, sizeof *reply); reply = ofpbuf_put_uninit(buf, sizeof *reply); - query_aggregate_stats(ofconn->ofproto, &target, request->out_port, + query_aggregate_stats(ofproto, &target, request->out_port, request->table_id, reply); - queue_tx(buf, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, buf); return 0; } @@ -3834,7 +3960,7 @@ handle_queue_stats_for_port(struct ofport *port, uint32_t queue_id, static int handle_queue_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) { - struct ofproto *ofproto = ofconn->ofproto; + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); const struct ofp_queue_stats_request *qsr; struct queue_stats_cbdata cbdata; struct ofport *port; @@ -3866,7 +3992,7 @@ handle_queue_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) ofpbuf_delete(cbdata.msg); return ofp_mkerr(OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT); } - queue_tx(cbdata.msg, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, cbdata.msg); return 0; } @@ -3896,7 +4022,7 @@ static void facet_update_stats(struct ofproto *ofproto, struct facet *facet, const struct dpif_flow_stats *stats) { - if (stats->n_packets) { + if (stats->n_packets || stats->used > facet->used) { facet_update_time(ofproto, facet, stats->used); facet->packet_count += stats->n_packets; facet->byte_count += stats->n_bytes; @@ -3968,7 +4094,7 @@ flow_push_stats(struct ofproto *ofproto, const struct rule *rule, * in which no matching flow already exists in the flow table. * * Adds the flow specified by 'ofm', which is followed by 'n_actions' - * ofp_actions, to ofconn->ofproto's flow table. Returns 0 on success or an + * ofp_actions, to the ofproto's flow table. Returns 0 on success or an * OpenFlow error code as encoded by ofp_mkerr() on failure. * * 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id, @@ -3976,7 +4102,7 @@ flow_push_stats(struct ofproto *ofproto, const struct rule *rule, static int add_flow(struct ofconn *ofconn, struct flow_mod *fm) { - struct ofproto *p = ofconn->ofproto; + struct ofproto *p = ofconn_get_ofproto(ofconn); struct ofpbuf *packet; struct rule *rule; uint16_t in_port; @@ -4016,6 +4142,7 @@ static int send_buffered_packet(struct ofconn *ofconn, struct rule *rule, uint32_t buffer_id) { + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct ofpbuf *packet; uint16_t in_port; int error; @@ -4029,7 +4156,7 @@ send_buffered_packet(struct ofconn *ofconn, return error; } - rule_execute(ofconn->ofproto, rule, in_port, packet); + rule_execute(ofproto, rule, in_port, packet); return 0; } @@ -4053,7 +4180,7 @@ static int modify_flow(struct ofproto *, const struct flow_mod *, static int modify_flows_loose(struct ofconn *ofconn, struct flow_mod *fm) { - struct ofproto *p = ofconn->ofproto; + struct ofproto *p = ofconn_get_ofproto(ofconn); struct rule *match = NULL; struct cls_cursor cursor; struct rule *rule; @@ -4085,7 +4212,7 @@ modify_flows_loose(struct ofconn *ofconn, struct flow_mod *fm) static int modify_flow_strict(struct ofconn *ofconn, struct flow_mod *fm) { - struct ofproto *p = ofconn->ofproto; + struct ofproto *p = ofconn_get_ofproto(ofconn); struct rule *rule = find_flow_strict(p, fm); if (rule && !rule_is_hidden(rule)) { modify_flow(p, fm, rule); @@ -4176,7 +4303,7 @@ delete_flow(struct ofproto *p, struct rule *rule, ovs_be16 out_port) static int handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh) { - struct ofproto *p = ofconn->ofproto; + struct ofproto *p = ofconn_get_ofproto(ofconn); struct flow_mod fm; int error; @@ -4185,7 +4312,7 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh) return error; } - error = ofputil_decode_flow_mod(&fm, oh, ofconn->flow_format); + error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_flow_format(ofconn)); if (error) { return error; } @@ -4232,8 +4359,11 @@ 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); - ofconn->flow_format = msg->set ? NXFF_TUN_ID_FROM_COOKIE : NXFF_OPENFLOW10; return 0; } @@ -4245,7 +4375,7 @@ handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh) struct ofpbuf *buf; uint32_t role; - if (ofconn->type != OFCONN_PRIMARY) { + if (ofconn_get_type(ofconn) != OFCONN_PRIMARY) { VLOG_WARN_RL(&rl, "ignoring role request on non-controller " "connection"); return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM); @@ -4261,19 +4391,20 @@ handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh) } if (role == NX_ROLE_MASTER) { + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); struct ofconn *other; - HMAP_FOR_EACH (other, hmap_node, &ofconn->ofproto->controllers) { - if (other->role == NX_ROLE_MASTER) { - other->role = NX_ROLE_SLAVE; + HMAP_FOR_EACH (other, hmap_node, &ofproto->controllers) { + if (ofconn_get_role(other) == NX_ROLE_MASTER) { + ofconn_set_role(other, NX_ROLE_SLAVE); } } } - ofconn->role = role; + ofconn_set_role(ofconn, role); reply = make_nxmsg_xid(sizeof *reply, NXT_ROLE_REPLY, oh->xid, &buf); reply->role = htonl(role); - queue_tx(buf, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, buf); return 0; } @@ -4289,7 +4420,7 @@ handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh) if (format == NXFF_OPENFLOW10 || format == NXFF_TUN_ID_FROM_COOKIE || format == NXFF_NXM) { - ofconn->flow_format = format; + ofconn_set_flow_format(ofconn, format); return 0; } else { return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM); @@ -4305,7 +4436,7 @@ handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh) /* Currently, everything executes synchronously, so we can just * immediately send the barrier reply. */ ob = make_openflow_xid(sizeof *ob, OFPT_BARRIER_REPLY, oh->xid, &buf); - queue_tx(buf, ofconn, ofconn->reply_counter); + ofconn_send_reply(ofconn, buf); return 0; } @@ -4352,10 +4483,6 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) return 0; /* Nicira extension requests. */ - case OFPUTIL_NXT_STATUS_REQUEST: - return switch_status_handle_request( - ofconn->ofproto->switch_status, ofconn->rconn, oh); - case OFPUTIL_NXT_TUN_ID_FROM_COOKIE: return handle_tun_id_from_cookie(ofconn, oh); @@ -4411,7 +4538,6 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg) case OFPUTIL_OFPST_PORT_REPLY: case OFPUTIL_OFPST_TABLE_REPLY: case OFPUTIL_OFPST_AGGREGATE_REPLY: - case OFPUTIL_NXT_STATUS_REPLY: case OFPUTIL_NXT_ROLE_REPLY: case OFPUTIL_NXT_FLOW_REMOVED: case OFPUTIL_NXST_FLOW_REPLY: @@ -4452,8 +4578,12 @@ handle_miss_upcall(struct ofproto *p, struct dpif_upcall *upcall) /* Set header pointers in 'flow'. */ flow_extract(upcall->packet, flow.tun_id, flow.in_port, &flow); - if (p->ofhooks->special_cb - && !p->ofhooks->special_cb(&flow, upcall->packet, p->aux)) { + if (cfm_should_process_flow(&flow)) { + ofproto_process_cfm(p, &flow, upcall->packet); + ofpbuf_delete(upcall->packet); + return; + } else if (p->ofhooks->special_cb + && !p->ofhooks->special_cb(&flow, upcall->packet, p->aux)) { ofpbuf_delete(upcall->packet); return; } @@ -4461,13 +4591,7 @@ handle_miss_upcall(struct ofproto *p, struct dpif_upcall *upcall) /* 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, upcall->packet)) { - struct ofpbuf odp_actions; - - ofpbuf_init(&odp_actions, 32); - nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_OUTPUT, ODPP_LOCAL); - dpif_execute(p->dpif, odp_actions.data, odp_actions.size, - upcall->packet); - ofpbuf_uninit(&odp_actions); + ofproto_send_packet(p, ODPP_LOCAL, 0, upcall->packet); } facet = facet_lookup_valid(p, &flow); @@ -4823,58 +4947,24 @@ rule_expire(struct ofproto *ofproto, struct rule *rule) rule_remove(ofproto, rule); } -static struct ofpbuf * -compose_ofp_flow_removed(struct ofconn *ofconn, const struct rule *rule, - uint8_t reason) -{ - struct ofp_flow_removed *ofr; - struct ofpbuf *buf; - - ofr = make_openflow_xid(sizeof *ofr, OFPT_FLOW_REMOVED, htonl(0), &buf); - ofputil_cls_rule_to_match(&rule->cr, ofconn->flow_format, &ofr->match, - rule->flow_cookie, &ofr->cookie); - ofr->priority = htons(rule->cr.priority); - ofr->reason = reason; - calc_flow_duration(rule->created, &ofr->duration_sec, &ofr->duration_nsec); - ofr->idle_timeout = htons(rule->idle_timeout); - ofr->packet_count = htonll(rule->packet_count); - ofr->byte_count = htonll(rule->byte_count); - - return buf; -} - -static struct ofpbuf * -compose_nx_flow_removed(const struct rule *rule, uint8_t reason) -{ - struct nx_flow_removed *nfr; - struct ofpbuf *buf; - int match_len; - - make_nxmsg_xid(sizeof *nfr, NXT_FLOW_REMOVED, htonl(0), &buf); - match_len = nx_put_match(buf, &rule->cr); - - nfr = buf->data; - nfr->cookie = rule->flow_cookie; - nfr->priority = htons(rule->cr.priority); - nfr->reason = reason; - calc_flow_duration(rule->created, &nfr->duration_sec, &nfr->duration_nsec); - nfr->idle_timeout = htons(rule->idle_timeout); - nfr->match_len = htons(match_len); - nfr->packet_count = htonll(rule->packet_count); - nfr->byte_count = htonll(rule->byte_count); - - return buf; -} - static void rule_send_removed(struct ofproto *p, struct rule *rule, uint8_t reason) { + struct ofputil_flow_removed fr; struct ofconn *ofconn; if (!rule->send_flow_removed) { return; } + fr.rule = rule->cr; + fr.cookie = rule->flow_cookie; + fr.reason = reason; + calc_flow_duration__(rule->created, &fr.duration_sec, &fr.duration_nsec); + fr.idle_timeout = rule->idle_timeout; + fr.packet_count = rule->packet_count; + fr.byte_count = rule->byte_count; + LIST_FOR_EACH (ofconn, node, &p->all_conns) { struct ofpbuf *msg; @@ -4883,16 +4973,13 @@ rule_send_removed(struct ofproto *p, struct rule *rule, uint8_t reason) continue; } - msg = (ofconn->flow_format == NXFF_NXM - ? compose_nx_flow_removed(rule, reason) - : compose_ofp_flow_removed(ofconn, rule, reason)); - - /* Account flow expirations under ofconn->reply_counter, the counter - * for replies to OpenFlow requests. That works because preventing - * OpenFlow requests from being processed also prevents new flows from - * being added (and expiring). (It also prevents processing OpenFlow - * requests that would not add new flows, so it is imperfect.) */ - queue_tx(msg, ofconn, ofconn->reply_counter); + /* This accounts flow expirations as if they were replies to OpenFlow + * requests. That works because preventing OpenFlow requests from + * being processed also prevents new flows from being added (and + * expiring). (It also prevents processing OpenFlow requests that + * would not add new flows, so it is imperfect.) */ + msg = ofputil_encode_flow_removed(&fr, ofconn_get_flow_format(ofconn)); + ofconn_send_reply(ofconn, msg); } } @@ -4941,66 +5028,50 @@ static void schedule_packet_in(struct ofconn *ofconn, struct dpif_upcall *upcall, const struct flow *flow, bool clone) { - enum { OPI_SIZE = offsetof(struct ofp_packet_in, data) }; - struct ofproto *ofproto = ofconn->ofproto; - struct ofp_packet_in *opi; - int total_len, send_len; - struct ofpbuf *packet; - uint32_t buffer_id; - int idx; + struct ofproto *ofproto = ofconn_get_ofproto(ofconn); + struct ofputil_packet_in pin; + struct ofpbuf *msg; + + /* Figure out the easy parts. */ + 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; /* Get OpenFlow buffer_id. */ if (upcall->type == DPIF_UC_ACTION) { - buffer_id = UINT32_MAX; + pin.buffer_id = UINT32_MAX; } else if (ofproto->fail_open && fail_open_is_active(ofproto->fail_open)) { - buffer_id = pktbuf_get_null(); + pin.buffer_id = pktbuf_get_null(); } else if (!ofconn->pktbuf) { - buffer_id = UINT32_MAX; + pin.buffer_id = UINT32_MAX; } else { - buffer_id = pktbuf_save(ofconn->pktbuf, upcall->packet, flow->in_port); + pin.buffer_id = pktbuf_save(ofconn->pktbuf, upcall->packet, + flow->in_port); } /* Figure out how much of the packet to send. */ - total_len = send_len = upcall->packet->size; - if (buffer_id != UINT32_MAX) { - send_len = MIN(send_len, ofconn->miss_send_len); + pin.send_len = upcall->packet->size; + if (pin.buffer_id != UINT32_MAX) { + pin.send_len = MIN(pin.send_len, ofconn->miss_send_len); } if (upcall->type == DPIF_UC_ACTION) { - send_len = MIN(send_len, upcall->userdata); - } - - /* Copy or steal buffer for OFPT_PACKET_IN. */ - if (clone) { - packet = ofpbuf_clone_data_with_headroom(upcall->packet->data, - send_len, OPI_SIZE); - } else { - packet = upcall->packet; - packet->size = send_len; + pin.send_len = MIN(pin.send_len, upcall->userdata); } - /* Add OFPT_PACKET_IN. */ - opi = ofpbuf_push_zeros(packet, OPI_SIZE); - opi->header.version = OFP_VERSION; - opi->header.type = OFPT_PACKET_IN; - opi->total_len = htons(total_len); - opi->in_port = htons(odp_port_to_ofp_port(flow->in_port)); - opi->reason = upcall->type == DPIF_UC_MISS ? OFPR_NO_MATCH : OFPR_ACTION; - opi->buffer_id = htonl(buffer_id); - update_openflow_length(packet); - - /* Hand over to packet scheduler. It might immediately call into - * do_send_packet_in() or it might buffer it for a while (until a later - * call to pinsched_run()). */ - idx = upcall->type == DPIF_UC_MISS ? 0 : 1; - pinsched_send(ofconn->schedulers[idx], flow->in_port, - packet, do_send_packet_in, ofconn); + /* Make OFPT_PACKET_IN and hand over to packet scheduler. It might + * immediately call into do_send_packet_in() or it might buffer it for a + * while (until a later call to pinsched_run()). */ + msg = ofputil_encode_packet_in(&pin, clone ? NULL : upcall->packet); + pinsched_send(ofconn->schedulers[upcall->type == DPIF_UC_MISS ? 0 : 1], + flow->in_port, msg, do_send_packet_in, ofconn); } /* Given 'upcall', of type DPIF_UC_ACTION or DPIF_UC_MISS, sends an * OFPT_PACKET_IN message to each OpenFlow controller as necessary according to * their individual configurations. * - * Takes ownership of 'packet'. */ + * If 'clone' is true, the caller retains ownership of 'upcall->packet'. + * Otherwise, ownership is transferred to this function. */ static void send_packet_in(struct ofproto *ofproto, struct dpif_upcall *upcall, const struct flow *flow, bool clone) @@ -5154,7 +5225,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, const char *args_, goto exit; } - tun_id = htonll(strtoull(tun_id_s, NULL, 10)); + tun_id = htonll(strtoull(tun_id_s, NULL, 0)); in_port = ofp_port_to_odp_port(atoi(in_port_s)); packet_s = ofpbuf_put_hex(&packet, packet_s, NULL); @@ -5225,7 +5296,7 @@ default_normal_ofhook_cb(const struct flow *flow, const struct ofpbuf *packet, uint16_t *nf_output_iface, void *ofproto_) { struct ofproto *ofproto = ofproto_; - int out_port; + struct mac_entry *dst_mac; /* Drop frames for reserved multicast addresses. */ if (eth_addr_is_reserved(flow->dl_dst)) { @@ -5233,31 +5304,37 @@ default_normal_ofhook_cb(const struct flow *flow, const struct ofpbuf *packet, } /* Learn source MAC (but don't try to learn from revalidation). */ - if (packet != NULL) { - tag_type rev_tag = mac_learning_learn(ofproto->ml, flow->dl_src, - 0, flow->in_port, - GRAT_ARP_LOCK_NONE); - if (rev_tag) { + if (packet != NULL + && mac_learning_may_learn(ofproto->ml, flow->dl_src, 0)) { + struct mac_entry *src_mac; + + src_mac = mac_learning_insert(ofproto->ml, flow->dl_src, 0); + if (mac_entry_is_new(src_mac) || src_mac->port.i != flow->in_port) { /* The log messages here could actually be useful in debugging, * so keep the rate limit relatively high. */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300); VLOG_DBG_RL(&rl, "learned that "ETH_ADDR_FMT" is on port %"PRIu16, ETH_ADDR_ARGS(flow->dl_src), flow->in_port); - ofproto_revalidate(ofproto, rev_tag); + + ofproto_revalidate(ofproto, + mac_learning_changed(ofproto->ml, src_mac)); + src_mac->port.i = flow->in_port; } } /* Determine output port. */ - out_port = mac_learning_lookup_tag(ofproto->ml, flow->dl_dst, 0, tags, - NULL); - if (out_port < 0) { + dst_mac = mac_learning_lookup(ofproto->ml, flow->dl_dst, 0, tags); + if (!dst_mac) { flood_packets(ofproto, flow->in_port, OFPPC_NO_FLOOD, nf_output_iface, odp_actions); - } else if (out_port != flow->in_port) { - nl_msg_put_u32(odp_actions, ODP_ACTION_ATTR_OUTPUT, out_port); - *nf_output_iface = out_port; } else { - /* Drop. */ + int out_port = dst_mac->port.i; + if (out_port != flow->in_port) { + nl_msg_put_u32(odp_actions, ODP_ACTION_ATTR_OUTPUT, out_port); + *nf_output_iface = out_port; + } else { + /* Drop. */ + } } return true;