X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=ofproto%2Fofproto.c;h=72ec8dd9dc7d147d1cacabf200940d492b0e35cc;hb=8fec720d1371b5a15abdc02e173c746f2b8088d9;hp=27f9ef4d488763d7137c1394fe9e71d98f9c9fc6;hpb=3394b5b69070b0aef4fc3231ca28bdf09bc0a0d2;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 27f9ef4d..72ec8dd9 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,7 +90,9 @@ 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 struct rule; @@ -100,9 +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 ofport_run(struct ofproto *, struct ofport *); +static void ofport_wait(struct ofport *); static void hton_ofp_phy_port(struct ofp_phy_port *); struct action_xlate_ctx { @@ -123,7 +127,7 @@ struct action_xlate_ctx { * * This is normally null so the client has to set it manually after * calling action_xlate_ctx_init(). */ - void (*resubmit_hook)(struct action_xlate_ctx *, const struct rule *); + void (*resubmit_hook)(struct action_xlate_ctx *, struct rule *); /* If true, the speciality of 'flow' should be checked before executing * its actions. If special_cb returns false on 'flow' rendered @@ -226,6 +230,10 @@ struct facet { uint64_t dp_packet_count; /* Last known packet count in the datapath. */ uint64_t dp_byte_count; /* Last known byte count in the datapath. */ + uint64_t rs_packet_count; /* Packets pushed to resubmit children. */ + uint64_t rs_byte_count; /* Bytes pushed to resubmit children. */ + long long int rs_used; /* Used time pushed to resubmit children. */ + /* Number of bytes passed to account_cb. This may include bytes that can * currently obtained from the datapath (thus, it can be greater than * byte_count). */ @@ -261,6 +269,7 @@ static void facet_make_actions(struct ofproto *, struct facet *, const struct ofpbuf *packet); static void facet_update_stats(struct ofproto *, struct facet *, const struct dpif_flow_stats *); +static void facet_push_stats(struct ofproto *, struct facet *); /* ofproto supports two kinds of OpenFlow connections: * @@ -326,8 +335,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? */ }; @@ -366,7 +373,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; @@ -416,6 +422,9 @@ static uint64_t pick_datapath_id(const struct ofproto *); static uint64_t pick_fallback_dpid(void); static int ofproto_expire(struct ofproto *); +static void flow_push_stats(struct ofproto *, const struct rule *, + struct flow *, uint64_t packets, uint64_t bytes, + long long int used); static void handle_upcall(struct ofproto *, struct dpif_upcall *); @@ -478,7 +487,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; @@ -538,82 +546,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 * @@ -636,7 +609,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. */ @@ -645,7 +617,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]; @@ -658,23 +629,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); @@ -701,7 +664,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; @@ -726,7 +689,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. @@ -735,7 +697,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); } @@ -754,7 +716,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; @@ -763,9 +724,6 @@ ofproto_set_controllers(struct ofproto *p, ofconn_destroy(ofconn); } else { update_controller(ofconn, c); - if (ofconn->ss) { - ss_exists = true; - } } } @@ -787,13 +745,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 @@ -1000,7 +951,71 @@ 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->eth_src, cfm->eth_src, ETH_ADDR_LEN); + 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) { @@ -1068,7 +1083,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); @@ -1164,6 +1178,7 @@ ofproto_run1(struct ofproto *p) { struct ofconn *ofconn, *next_ofconn; struct ofservice *ofservice; + struct ofport *ofport; char *devname; int error; int i; @@ -1200,6 +1215,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); @@ -1300,11 +1319,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); } @@ -1355,7 +1378,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; @@ -1364,6 +1387,9 @@ 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); @@ -1384,9 +1410,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)); + } } } @@ -1447,26 +1481,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 @@ -1514,6 +1556,8 @@ ofproto_flush_flows(struct ofproto *ofproto) * individually since we are about to blow away all the facets with * dpif_flow_flush(). */ facet->installed = false; + facet->dp_packet_count = 0; + facet->dp_byte_count = 0; facet_remove(ofproto, facet); } @@ -1681,10 +1725,31 @@ ofport_remove(struct ofproto *p, struct ofport *ofport) } } +static void +ofport_run(struct ofproto *ofproto, struct ofport *ofport) +{ + if (ofport->cfm) { + struct ofpbuf *packet = cfm_run(ofport->cfm); + if (packet) { + ofproto_send_packet(ofproto, ofport->odp_port, 0, packet); + ofpbuf_delete(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); } @@ -1817,10 +1882,8 @@ ofconn_destroy(struct ofconn *ofconn) if (ofconn->type == OFCONN_PRIMARY) { hmap_remove(&ofconn->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); @@ -1835,22 +1898,6 @@ ofconn_run(struct ofconn *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); - } else { - rconn_disconnect(ofconn->rconn); - } - } - } - for (i = 0; i < N_SCHEDULERS; i++) { pinsched_run(ofconn->schedulers[i], do_send_packet_in, ofconn); } @@ -1873,7 +1920,7 @@ ofconn_run(struct ofconn *ofconn) } } - if (!ofconn->discovery && !rconn_is_alive(ofconn->rconn)) { + if (!rconn_is_alive(ofconn->rconn)) { ofconn_destroy(ofconn); } } @@ -1883,9 +1930,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]); } @@ -1934,8 +1978,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); } @@ -2146,12 +2189,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_update_stats(ofproto, facet, &stats); - facet->used = time_msec(); - netflow_flow_update_time(ofproto->netflow, - &facet->nf_flow, facet->used); } } @@ -2203,6 +2244,7 @@ rule_execute(struct ofproto *ofproto, struct rule *rule, uint16_t in_port, rule->used = time_msec(); rule->packet_count++; rule->byte_count += size; + flow_push_stats(ofproto, rule, &flow, 1, size, rule->used); } ofpbuf_delete(odp_actions); } @@ -2387,6 +2429,9 @@ facet_uninstall(struct ofproto *p, struct facet *facet) 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); } } @@ -2412,6 +2457,7 @@ facet_flush_stats(struct ofproto *ofproto, struct facet *facet) assert(!facet->dp_byte_count); assert(!facet->dp_packet_count); + facet_push_stats(ofproto, facet); facet_account(ofproto, facet, 0); if (ofproto->netflow && !facet_is_controller_flow(facet)) { @@ -2430,6 +2476,8 @@ facet_flush_stats(struct ofproto *ofproto, struct facet *facet) * reinstalled. */ facet->packet_count = 0; facet->byte_count = 0; + facet->rs_packet_count = 0; + facet->rs_byte_count = 0; facet->accounted_bytes = 0; netflow_flow_clear(&facet->nf_flow); @@ -2549,6 +2597,7 @@ facet_revalidate(struct ofproto *ofproto, struct facet *facet) list_push_back(&new_rule->facets, &facet->list_node); facet->rule = new_rule; facet->used = new_rule->created; + facet->rs_used = facet->used; } ofpbuf_delete(odp_actions); @@ -2676,10 +2725,6 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc) return 0; } -/* Maximum depth of flow table recursion (due to NXAST_RESUBMIT actions) in a - * flow translation. */ -#define MAX_RESUBMIT_RECURSION 16 - static void do_xlate_actions(const union ofp_action *in, size_t n_in, struct action_xlate_ctx *ctx); @@ -3134,6 +3179,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) @@ -3147,13 +3204,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); @@ -3524,7 +3586,16 @@ put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule, static bool is_valid_table(uint8_t table_id) { - return table_id == 0 || table_id == 0xff; + if (table_id == 0 || table_id == 0xff) { + return true; + } else { + /* It would probably be better to reply with an error but there doesn't + * seem to be any appropriate value, so that might just be + * confusing. */ + VLOG_WARN_RL(&rl, "controller asked for invalid table %"PRIu8, + table_id); + return false; + } } static int @@ -3653,7 +3724,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) { @@ -3843,6 +3914,8 @@ handle_queue_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) return 0; } +/* Updates 'facet''s used time. Caller is responsible for calling + * facet_push_stats() to update the flows which 'facet' resubmits into. */ static void facet_update_time(struct ofproto *ofproto, struct facet *facet, long long int used) @@ -3866,14 +3939,74 @@ 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; + facet_push_stats(ofproto, facet); netflow_flow_update_flags(&facet->nf_flow, stats->tcp_flags); } } +static void +facet_push_stats(struct ofproto *ofproto, struct facet *facet) +{ + uint64_t rs_packets, rs_bytes; + + assert(facet->packet_count >= facet->rs_packet_count); + assert(facet->byte_count >= facet->rs_byte_count); + assert(facet->used >= facet->rs_used); + + rs_packets = facet->packet_count - facet->rs_packet_count; + rs_bytes = facet->byte_count - facet->rs_byte_count; + + if (rs_packets || rs_bytes || facet->used > facet->rs_used) { + facet->rs_packet_count = facet->packet_count; + facet->rs_byte_count = facet->byte_count; + facet->rs_used = facet->used; + + flow_push_stats(ofproto, facet->rule, &facet->flow, + rs_packets, rs_bytes, facet->used); + } +} + +struct ofproto_push { + struct action_xlate_ctx ctx; + uint64_t packets; + uint64_t bytes; + long long int used; +}; + +static void +push_resubmit(struct action_xlate_ctx *ctx, struct rule *rule) +{ + struct ofproto_push *push = CONTAINER_OF(ctx, struct ofproto_push, ctx); + + if (rule) { + rule->packet_count += push->packets; + rule->byte_count += push->bytes; + rule->used = MAX(push->used, rule->used); + } +} + +/* Pushes flow statistics to the rules which 'flow' resubmits into given + * 'rule''s actions. */ +static void +flow_push_stats(struct ofproto *ofproto, const struct rule *rule, + struct flow *flow, uint64_t packets, uint64_t bytes, + long long int used) +{ + struct ofproto_push push; + + push.packets = packets; + push.bytes = bytes; + push.used = used; + + action_xlate_ctx_init(&push.ctx, ofproto, flow, NULL); + push.ctx.resubmit_hook = push_resubmit; + ofpbuf_delete(xlate_actions(&push.ctx, rule->actions, rule->n_actions)); +} + /* Implements OFPFC_ADD and the cases for OFPFC_MODIFY and OFPFC_MODIFY_STRICT * in which no matching flow already exists in the flow table. * @@ -4262,10 +4395,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); @@ -4321,7 +4450,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: @@ -4362,8 +4490,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; } @@ -4371,13 +4503,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); @@ -4504,6 +4630,15 @@ ofproto_expire(struct ofproto *ofproto) } /* Update 'packet_count', 'byte_count', and 'used' members of installed facets. + * + * This function also pushes statistics updates to rules which each facet + * resubmits into. Generally these statistics will be accurate. However, if a + * facet changes the rule it resubmits into at some time in between + * ofproto_update_stats() runs, it is possible that statistics accrued to the + * old rule will be incorrectly attributed to the new rule. This could be + * avoided by calling ofproto_update_stats() whenever rules are created or + * deleted. However, the performance impact of making so many calls to the + * datapath do not justify the benefit of having perfectly accurate statistics. */ static void ofproto_update_stats(struct ofproto *p) @@ -4550,6 +4685,7 @@ ofproto_update_stats(struct ofproto *p) facet_update_time(p, facet, stats->used); facet_account(p, facet, stats->n_bytes); + facet_push_stats(p, facet); } else { /* There's a flow in the datapath that we know nothing about. * Delete it. */ @@ -4900,7 +5036,8 @@ schedule_packet_in(struct ofconn *ofconn, struct dpif_upcall *upcall, * 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) @@ -5009,7 +5146,7 @@ trace_format_flow(struct ds *result, int level, const char *title, } static void -trace_resubmit(struct action_xlate_ctx *ctx, const struct rule *rule) +trace_resubmit(struct action_xlate_ctx *ctx, struct rule *rule) { struct ofproto_trace *trace = CONTAINER_OF(ctx, struct ofproto_trace, ctx); struct ds *result = trace->result; @@ -5054,7 +5191,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); @@ -5125,7 +5262,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)) { @@ -5133,31 +5270,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;