X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=ea869f1ec781295915fbcdf5f057d3d6478d688f;hb=996c1b3d7a4d6e82e1831ff8821e5fd7e1a5522c;hp=7df8600e54b853c9c8859b691b7968440147bfe7;hpb=1dfee98d87605bc52ed58738edf01e201b189615;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 7df8600e..ea869f1e 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -340,8 +340,9 @@ static void ofconn_set_rate_limit(struct ofconn *, int rate, int burst); static void queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn, struct rconn_packet_counter *counter); -static void send_packet_in(struct ofproto *, struct ofpbuf *odp_msg); -static void do_send_packet_in(struct ofpbuf *odp_msg, void *ofconn); +static void send_packet_in(struct ofproto *, struct dpif_upcall *, + const struct flow *, bool clone); +static void do_send_packet_in(struct ofpbuf *ofp_packet_in, void *ofconn); struct ofproto { /* Settings. */ @@ -412,7 +413,7 @@ static uint64_t pick_fallback_dpid(void); static int ofproto_expire(struct ofproto *); -static void handle_odp_msg(struct ofproto *, struct ofpbuf *); +static void handle_upcall(struct ofproto *, struct dpif_upcall *); static void handle_openflow(struct ofconn *, struct ofpbuf *); @@ -428,7 +429,6 @@ ofproto_create(const char *datapath, const char *datapath_type, const struct ofhooks *ofhooks, void *aux, struct ofproto **ofprotop) { - struct odp_stats stats; struct ofproto *p; struct dpif *dpif; int error; @@ -443,13 +443,6 @@ ofproto_create(const char *datapath, const char *datapath_type, VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error)); return error; } - error = dpif_get_dp_stats(dpif, &stats); - if (error) { - VLOG_ERR("failed to obtain stats for datapath %s: %s", - datapath, strerror(error)); - dpif_close(dpif); - return error; - } error = dpif_recv_set_mask(dpif, ODPL_MISS | ODPL_ACTION | ODPL_SFLOW); if (error) { VLOG_ERR("failed to listen on datapath %s: %s", @@ -475,7 +468,7 @@ ofproto_create(const char *datapath, const char *datapath_type, p->netdev_monitor = netdev_monitor_create(); hmap_init(&p->ports); shash_init(&p->port_by_name); - p->max_ports = stats.max_ports; + p->max_ports = dpif_get_max_ports(dpif); /* Initialize submodules. */ p->switch_status = switch_status_create(p); @@ -1173,9 +1166,9 @@ ofproto_run1(struct ofproto *p) } for (i = 0; i < 50; i++) { - struct ofpbuf *buf; + struct dpif_upcall packet; - error = dpif_recv(p->dpif, &buf); + error = dpif_recv(p->dpif, &packet); if (error) { if (error == ENODEV) { /* Someone destroyed the datapath behind our back. The caller @@ -1189,7 +1182,7 @@ ofproto_run1(struct ofproto *p) break; } - handle_odp_msg(p, buf); + handle_upcall(p, &packet); } while ((error = dpif_port_poll(p->dpif, &devname)) != EAGAIN) { @@ -1354,6 +1347,60 @@ ofproto_is_alive(const struct ofproto *p) return !hmap_is_empty(&p->controllers); } +void +ofproto_get_ofproto_controller_info(const struct ofproto * ofproto, + struct shash *info) +{ + const struct ofconn *ofconn; + + shash_init(info); + + HMAP_FOR_EACH (ofconn, hmap_node, &ofproto->controllers) { + const struct rconn *rconn = ofconn->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->pairs.n = 0; + + if (last_error == EOF) { + cinfo->pairs.keys[cinfo->pairs.n] = "last_error"; + cinfo->pairs.values[cinfo->pairs.n++] = xstrdup("End of file"); + } else if (last_error > 0) { + cinfo->pairs.keys[cinfo->pairs.n] = "last_error"; + cinfo->pairs.values[cinfo->pairs.n++] = + xstrdup(strerror(last_error)); + } + + cinfo->pairs.keys[cinfo->pairs.n] = "state"; + 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)); + } +} + +void +ofproto_free_ofproto_controller_info(struct shash *info) +{ + struct shash_node *node; + + SHASH_FOR_EACH (node, info) { + struct ofproto_controller_info *cinfo = node->data; + while (cinfo->pairs.n) { + free((char *) cinfo->pairs.values[--cinfo->pairs.n]); + } + free(cinfo); + } + shash_destroy(info); +} + /* Deletes port number 'odp_port' from the datapath for 'ofproto'. * * This is almost the same as calling dpif_port_del() directly on the @@ -1481,12 +1528,11 @@ ofproto_flush_flows(struct ofproto *ofproto) static void reinit_ports(struct ofproto *p) { + struct dpif_port_dump dump; struct shash_node *node; struct shash devnames; struct ofport *ofport; - struct odp_port *odp_ports; - size_t n_odp_ports; - size_t i; + struct dpif_port dpif_port; COVERAGE_INC(ofproto_reinit_ports); @@ -1494,11 +1540,9 @@ reinit_ports(struct ofproto *p) HMAP_FOR_EACH (ofport, hmap_node, &p->ports) { shash_add_once (&devnames, ofport->opp.name, NULL); } - dpif_port_list(p->dpif, &odp_ports, &n_odp_ports); - for (i = 0; i < n_odp_ports; i++) { - shash_add_once (&devnames, odp_ports[i].devname, NULL); + DPIF_PORT_FOR_EACH (&dpif_port, &dump, p->dpif) { + shash_add_once (&devnames, dpif_port.name, NULL); } - free(odp_ports); SHASH_FOR_EACH (node, &devnames) { update_port(p, node->name); @@ -1507,7 +1551,7 @@ reinit_ports(struct ofproto *p) } static struct ofport * -make_ofport(const struct odp_port *odp_port) +make_ofport(const struct dpif_port *dpif_port) { struct netdev_options netdev_options; enum netdev_flags flags; @@ -1516,27 +1560,25 @@ make_ofport(const struct odp_port *odp_port) int error; memset(&netdev_options, 0, sizeof netdev_options); - netdev_options.name = odp_port->devname; - netdev_options.type = odp_port->type; + netdev_options.name = dpif_port->name; + netdev_options.type = dpif_port->type; netdev_options.ethertype = NETDEV_ETH_TYPE_NONE; error = netdev_open(&netdev_options, &netdev); if (error) { VLOG_WARN_RL(&rl, "ignoring port %s (%"PRIu16") because netdev %s " "cannot be opened (%s)", - odp_port->devname, odp_port->port, - odp_port->devname, strerror(error)); + dpif_port->name, dpif_port->port_no, + dpif_port->name, strerror(error)); return NULL; } ofport = xmalloc(sizeof *ofport); ofport->netdev = netdev; - ofport->odp_port = odp_port->port; - ofport->opp.port_no = odp_port_to_ofp_port(odp_port->port); + 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); - memcpy(ofport->opp.name, odp_port->devname, - MIN(sizeof ofport->opp.name, sizeof odp_port->devname)); - ofport->opp.name[sizeof ofport->opp.name - 1] = '\0'; + 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; @@ -1550,15 +1592,15 @@ make_ofport(const struct odp_port *odp_port) } static bool -ofport_conflicts(const struct ofproto *p, const struct odp_port *odp_port) +ofport_conflicts(const struct ofproto *p, const struct dpif_port *dpif_port) { - if (get_port(p, odp_port->port)) { + if (get_port(p, dpif_port->port_no)) { VLOG_WARN_RL(&rl, "ignoring duplicate port %"PRIu16" in datapath", - odp_port->port); + dpif_port->port_no); return true; - } else if (shash_find(&p->port_by_name, odp_port->devname)) { + } else if (shash_find(&p->port_by_name, dpif_port->name)) { VLOG_WARN_RL(&rl, "ignoring duplicate device %s in datapath", - odp_port->devname); + dpif_port->name); return true; } else { return false; @@ -1659,7 +1701,7 @@ get_port(const struct ofproto *ofproto, uint16_t odp_port) static void update_port(struct ofproto *p, const char *devname) { - struct odp_port odp_port; + struct dpif_port dpif_port; struct ofport *old_ofport; struct ofport *new_ofport; int error; @@ -1667,7 +1709,7 @@ update_port(struct ofproto *p, const char *devname) COVERAGE_INC(ofproto_update_port); /* Query the datapath for port information. */ - error = dpif_port_query_by_name(p->dpif, devname, &odp_port); + 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); @@ -1683,20 +1725,20 @@ update_port(struct ofproto *p, const char *devname) * 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, odp_port.port); + 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)); - return; + goto exit; } /* Create a new ofport. */ - new_ofport = !error ? make_ofport(&odp_port) : NULL; + new_ofport = !error ? make_ofport(&dpif_port) : NULL; /* Eliminate a few pathological cases. */ if (!old_ofport && !new_ofport) { - return; + 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 @@ -1707,7 +1749,7 @@ update_port(struct ofproto *p, const char *devname) if (ofport_equal(old_ofport, new_ofport)) { /* False alarm--no change. */ ofport_free(new_ofport); - return; + goto exit; } } @@ -1723,31 +1765,26 @@ update_port(struct ofproto *p, const char *devname) : !new_ofport ? OFPPR_DELETE : OFPPR_MODIFY)); ofport_free(old_ofport); + +exit: + dpif_port_destroy(&dpif_port); } static int init_ports(struct ofproto *p) { - struct odp_port *ports; - size_t n_ports; - size_t i; - int error; + struct dpif_port_dump dump; + struct dpif_port dpif_port; - error = dpif_port_list(p->dpif, &ports, &n_ports); - if (error) { - return error; - } - - for (i = 0; i < n_ports; i++) { - const struct odp_port *odp_port = &ports[i]; - if (!ofport_conflicts(p, odp_port)) { - struct ofport *ofport = make_ofport(odp_port); + 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); } } } - free(ports); + return 0; } @@ -2050,7 +2087,7 @@ rule_has_out_port(const struct rule *rule, ovs_be16 out_port) * * Takes ownership of 'packet'. */ static bool -execute_odp_actions(struct ofproto *ofproto, uint16_t in_port, +execute_odp_actions(struct ofproto *ofproto, const struct flow *flow, const struct nlattr *odp_actions, size_t actions_len, struct ofpbuf *packet) { @@ -2059,15 +2096,18 @@ execute_odp_actions(struct ofproto *ofproto, uint16_t in_port, /* As an optimization, avoid a round-trip from userspace to kernel to * userspace. This also avoids possibly filling up kernel packet * buffers along the way. */ - struct odp_msg *msg; + struct dpif_upcall upcall; - msg = ofpbuf_push_uninit(packet, sizeof *msg); - msg->type = _ODPL_ACTION_NR; - msg->length = sizeof(struct odp_msg) + packet->size; - msg->port = in_port; - msg->arg = nl_attr_get_u64(odp_actions); + upcall.type = _ODPL_ACTION_NR; + upcall.packet = packet; + upcall.key = NULL; + upcall.key_len = 0; + upcall.userdata = nl_attr_get_u64(odp_actions); + upcall.sample_pool = 0; + upcall.actions = NULL; + upcall.actions_len = 0; - send_packet_in(ofproto, packet); + send_packet_in(ofproto, &upcall, flow, false); return true; } else { @@ -2100,7 +2140,7 @@ facet_execute(struct ofproto *ofproto, struct facet *facet, assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in)); flow_extract_stats(&facet->flow, packet, &stats); - if (execute_odp_actions(ofproto, facet->flow.in_port, + if (execute_odp_actions(ofproto, &facet->flow, facet->actions, facet->actions_len, packet)) { facet_update_stats(ofproto, facet, &stats); facet->used = time_msec(); @@ -2152,7 +2192,7 @@ rule_execute(struct ofproto *ofproto, struct rule *rule, uint16_t in_port, action_xlate_ctx_init(&ctx, ofproto, &flow, packet); odp_actions = xlate_actions(&ctx, rule->actions, rule->n_actions); size = packet->size; - if (execute_odp_actions(ofproto, in_port, odp_actions->data, + if (execute_odp_actions(ofproto, &flow, odp_actions->data, odp_actions->size, packet)) { rule->used = time_msec(); rule->packet_count++; @@ -2269,8 +2309,16 @@ static int facet_put__(struct ofproto *ofproto, struct facet *facet, int flags, struct odp_flow_put *put) { + uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S]; + struct ofpbuf key; + + ofpbuf_use_stack(&key, keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, &facet->flow); + assert(key.base == keybuf); + memset(&put->flow.stats, 0, sizeof put->flow.stats); - odp_flow_key_from_flow(&put->flow.key, &facet->flow); + put->flow.key = key.data; + put->flow.key_len = key.size; put->flow.actions = facet->actions; put->flow.actions_len = facet->actions_len; put->flow.flags = 0; @@ -2321,9 +2369,16 @@ static void facet_uninstall(struct ofproto *p, struct facet *facet) { if (facet->installed) { + uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S]; struct odp_flow odp_flow; + struct ofpbuf key; + + ofpbuf_use_stack(&key, keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, &facet->flow); + assert(key.base == keybuf); - odp_flow_key_from_flow(&odp_flow.key, &facet->flow); + odp_flow.key = key.data; + odp_flow.key_len = key.size; odp_flow.actions = NULL; odp_flow.actions_len = 0; odp_flow.flags = 0; @@ -2459,10 +2514,16 @@ facet_revalidate(struct ofproto *ofproto, struct facet *facet) * to talk to the datapath. */ if (actions_changed || facet->may_install != facet->installed) { if (facet->may_install) { + uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S]; struct odp_flow_put put; + struct ofpbuf key; + + ofpbuf_use_stack(&key, keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, &facet->flow); memset(&put.flow.stats, 0, sizeof put.flow.stats); - odp_flow_key_from_flow(&put.flow.key, &facet->flow); + put.flow.key = key.data; + put.flow.key_len = key.size; put.flow.actions = odp_actions->data; put.flow.actions_len = odp_actions->size; put.flow.flags = 0; @@ -3416,42 +3477,44 @@ static void query_stats(struct ofproto *p, struct rule *rule, uint64_t *packet_countp, uint64_t *byte_countp) { + uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S]; uint64_t packet_count, byte_count; struct facet *facet; - struct odp_flow *odp_flows; - size_t n_odp_flows; + struct ofpbuf key; /* Start from historical data for 'rule' itself that are no longer tracked * by the datapath. This counts, for example, facets that have expired. */ packet_count = rule->packet_count; byte_count = rule->byte_count; - /* Prepare to ask the datapath for statistics on all of the rule's facets. + /* Ask the datapath for statistics on all of the rule's facets. (We could + * batch up statistics requests using dpif_flow_get_multiple(), but that is + * not yet implemented.) * * Also, add any statistics that are not tracked by the datapath for each * facet. This includes, for example, statistics for packets that were * executed "by hand" by ofproto via dpif_execute() but must be accounted * to a rule. */ - odp_flows = xzalloc(list_size(&rule->facets) * sizeof *odp_flows); - n_odp_flows = 0; + ofpbuf_use_stack(&key, keybuf, sizeof keybuf); LIST_FOR_EACH (facet, list_node, &rule->facets) { - struct odp_flow *odp_flow = &odp_flows[n_odp_flows++]; - odp_flow_key_from_flow(&odp_flow->key, &facet->flow); - packet_count += facet->packet_count; - byte_count += facet->byte_count; - } + struct odp_flow odp_flow; - /* Fetch up-to-date statistics from the datapath and add them in. */ - if (!dpif_flow_get_multiple(p->dpif, odp_flows, n_odp_flows)) { - size_t i; + ofpbuf_clear(&key); + odp_flow_key_from_flow(&key, &facet->flow); - for (i = 0; i < n_odp_flows; i++) { - struct odp_flow *odp_flow = &odp_flows[i]; - packet_count += odp_flow->stats.n_packets; - byte_count += odp_flow->stats.n_bytes; + odp_flow.key = key.data; + odp_flow.key_len = key.size; + odp_flow.actions = NULL; + odp_flow.actions_len = 0; + odp_flow.flags = 0; + if (!dpif_flow_get(p->dpif, &odp_flow)) { + packet_count += odp_flow.stats.n_packets; + byte_count += odp_flow.stats.n_bytes; } + + packet_count += facet->packet_count; + byte_count += facet->byte_count; } - free(odp_flows); /* Return the stats to the caller. */ *packet_countp = packet_count; @@ -4336,29 +4399,26 @@ handle_openflow(struct ofconn *ofconn, struct ofpbuf *ofp_msg) } static void -handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet) +handle_miss_upcall(struct ofproto *p, struct dpif_upcall *upcall) { - struct odp_msg *msg = packet->data; - struct ofpbuf payload; struct facet *facet; struct flow flow; - ofpbuf_use_const(&payload, msg + 1, msg->length - sizeof *msg); - flow_extract(&payload, msg->arg, msg->port, &flow); + /* Obtain in_port and tun_id, at least. */ + odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow); - packet->l2 = payload.l2; - packet->l3 = payload.l3; - packet->l4 = payload.l4; - packet->l7 = payload.l7; + /* Set header pointers in 'flow'. */ + flow_extract(upcall->packet, flow.tun_id, flow.in_port, &flow); /* Check with in-band control to see if this packet should be sent * to the local port regardless of the flow table. */ - if (in_band_msg_in_hook(p->in_band, &flow, &payload)) { + 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, ODPAT_OUTPUT, ODPP_LOCAL); - dpif_execute(p->dpif, odp_actions.data, odp_actions.size, &payload); + dpif_execute(p->dpif, odp_actions.data, odp_actions.size, + upcall->packet); ofpbuf_uninit(&odp_actions); } @@ -4367,29 +4427,29 @@ handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet) struct rule *rule = rule_lookup(p, &flow); if (!rule) { /* Don't send a packet-in if OFPPC_NO_PACKET_IN asserted. */ - struct ofport *port = get_port(p, msg->port); + struct ofport *port = get_port(p, flow.in_port); if (port) { if (port->opp.config & OFPPC_NO_PACKET_IN) { COVERAGE_INC(ofproto_no_packet_in); /* XXX install 'drop' flow entry */ - ofpbuf_delete(packet); + ofpbuf_delete(upcall->packet); return; } } else { VLOG_WARN_RL(&rl, "packet-in on unknown port %"PRIu16, - msg->port); + flow.in_port); } COVERAGE_INC(ofproto_packet_in); - send_packet_in(p, packet); + send_packet_in(p, upcall, &flow, false); return; } - facet = facet_create(p, rule, &flow, packet); + facet = facet_create(p, rule, &flow, upcall->packet); } else if (!facet->may_install) { /* The facet is not installable, that is, we need to process every * packet, so process the current packet's actions into 'facet'. */ - facet_make_actions(p, facet, packet); + facet_make_actions(p, facet, upcall->packet); } if (facet->rule->cr.priority == FAIL_OPEN_PRIORITY) { @@ -4403,40 +4463,39 @@ handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet) * * See the top-level comment in fail-open.c for more information. */ - send_packet_in(p, ofpbuf_clone_with_headroom(packet, - DPIF_RECV_MSG_PADDING)); + send_packet_in(p, upcall, &flow, true); } - ofpbuf_pull(packet, sizeof *msg); - facet_execute(p, facet, packet); + facet_execute(p, facet, upcall->packet); facet_install(p, facet, false); } static void -handle_odp_msg(struct ofproto *p, struct ofpbuf *packet) +handle_upcall(struct ofproto *p, struct dpif_upcall *upcall) { - struct odp_msg *msg = packet->data; + struct flow flow; - switch (msg->type) { + switch (upcall->type) { case _ODPL_ACTION_NR: COVERAGE_INC(ofproto_ctlr_action); - send_packet_in(p, packet); + odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow); + send_packet_in(p, upcall, &flow, false); break; case _ODPL_SFLOW_NR: if (p->sflow) { - ofproto_sflow_received(p->sflow, msg); + odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow); + ofproto_sflow_received(p->sflow, upcall, &flow); } - ofpbuf_delete(packet); + ofpbuf_delete(upcall->packet); break; case _ODPL_MISS_NR: - handle_odp_miss_msg(p, packet); + handle_miss_upcall(p, upcall); break; default: - VLOG_WARN_RL(&rl, "received ODP message of unexpected type %"PRIu32, - msg->type); + VLOG_WARN_RL(&rl, "upcall has unexpected type %"PRIu32, upcall->type); break; } } @@ -4489,36 +4548,50 @@ ofproto_expire(struct ofproto *ofproto) static void ofproto_update_used(struct ofproto *p) { - struct odp_flow *flows; - size_t n_flows; - size_t i; - int error; + struct dpif_flow_dump dump; - error = dpif_flow_list_all(p->dpif, &flows, &n_flows); - if (error) { - return; - } - - for (i = 0; i < n_flows; i++) { - struct odp_flow *f = &flows[i]; + dpif_flow_dump_start(&dump, p->dpif); + for (;;) { + uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S]; struct facet *facet; + struct odp_flow f; struct flow flow; - odp_flow_key_to_flow(&f->key, &flow); + memset(&f, 0, sizeof f); + f.key = (struct nlattr *) keybuf; + f.key_len = sizeof keybuf; + if (!dpif_flow_dump_next(&dump, &f)) { + break; + } + + if (f.key_len > sizeof keybuf) { + VLOG_WARN_RL(&rl, "ODP flow key overflowed buffer"); + continue; + } + if (odp_flow_key_to_flow(f.key, f.key_len, &flow)) { + struct ds s; + + ds_init(&s); + odp_flow_key_format(f.key, f.key_len, &s); + VLOG_WARN_RL(&rl, "failed to convert ODP flow key to flow: %s", + ds_cstr(&s)); + ds_destroy(&s); + + continue; + } facet = facet_find(p, &flow); if (facet && facet->installed) { - facet_update_time(p, facet, &f->stats); - facet_account(p, facet, f->stats.n_bytes); + facet_update_time(p, facet, &f.stats); + facet_account(p, facet, f.stats.n_bytes); } else { /* There's a flow in the datapath that we know nothing about. * Delete it. */ COVERAGE_INC(ofproto_unexpected_rule); - dpif_flow_del(p->dpif, f); + dpif_flow_del(p->dpif, &f); } - } - free(flows); + dpif_flow_dump_done(&dump); } /* Calculates and returns the number of milliseconds of idle time after which @@ -4626,7 +4699,14 @@ facet_active_timeout(struct ofproto *ofproto, struct facet *facet) * ofproto_update_used() zeroed TCP flags. */ memset(&odp_flow, 0, sizeof odp_flow); if (facet->installed) { - odp_flow_key_from_flow(&odp_flow.key, &facet->flow); + uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S]; + struct ofpbuf key; + + ofpbuf_use_stack(&key, keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, &facet->flow); + + odp_flow.key = key.data; + odp_flow.key_len = key.size; odp_flow.flags = ODPFF_ZERO_TCP_FLAGS; dpif_flow_get(ofproto->dpif, &odp_flow); @@ -4770,150 +4850,103 @@ rule_send_removed(struct ofproto *p, struct rule *rule, uint8_t reason) } } -/* pinsched callback for sending 'packet' on 'ofconn'. */ +/* pinsched callback for sending 'ofp_packet_in' on 'ofconn'. */ static void -do_send_packet_in(struct ofpbuf *packet, void *ofconn_) +do_send_packet_in(struct ofpbuf *ofp_packet_in, void *ofconn_) { struct ofconn *ofconn = ofconn_; - rconn_send_with_limit(ofconn->rconn, packet, + rconn_send_with_limit(ofconn->rconn, ofp_packet_in, ofconn->packet_in_counter, 100); } -/* Takes 'packet', which has been converted with do_convert_to_packet_in(), and - * finalizes its content for sending on 'ofconn', and passes it to 'ofconn''s - * packet scheduler for sending. +/* Takes 'upcall', whose packet has the flow specified by 'flow', composes an + * OpenFlow packet-in message from it, and passes it to 'ofconn''s packet + * scheduler for sending. * - * 'max_len' specifies the maximum number of bytes of the packet to send on - * 'ofconn' (INT_MAX specifies no limit). - * - * If 'clone' is true, the caller retains ownership of 'packet'. Otherwise, - * ownership is transferred to this function. */ + * If 'clone' is true, the caller retains ownership of 'upcall->packet'. + * Otherwise, ownership is transferred to this function. */ static void -schedule_packet_in(struct ofconn *ofconn, struct ofpbuf *packet, int max_len, - bool clone) +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 = packet->data; - uint16_t in_port = ofp_port_to_odp_port(ntohs(opi->in_port)); - int send_len, trim_size; + struct ofp_packet_in *opi; + int total_len, send_len; + struct ofpbuf *packet; uint32_t buffer_id; - /* Get buffer. */ - if (opi->reason == OFPR_ACTION) { + /* Get OpenFlow buffer_id. */ + if (upcall->type == _ODPL_ACTION_NR) { buffer_id = UINT32_MAX; } else if (ofproto->fail_open && fail_open_is_active(ofproto->fail_open)) { buffer_id = pktbuf_get_null(); } else if (!ofconn->pktbuf) { buffer_id = UINT32_MAX; } else { - struct ofpbuf payload; - - ofpbuf_use_const(&payload, opi->data, - packet->size - offsetof(struct ofp_packet_in, data)); - buffer_id = pktbuf_save(ofconn->pktbuf, &payload, in_port); + buffer_id = pktbuf_save(ofconn->pktbuf, upcall->packet, flow->in_port); } /* Figure out how much of the packet to send. */ - send_len = ntohs(opi->total_len); + total_len = send_len = upcall->packet->size; if (buffer_id != UINT32_MAX) { send_len = MIN(send_len, ofconn->miss_send_len); } - send_len = MIN(send_len, max_len); + if (upcall->type == _ODPL_ACTION_NR) { + send_len = MIN(send_len, upcall->userdata); + } - /* Adjust packet length and clone if necessary. */ - trim_size = offsetof(struct ofp_packet_in, data) + send_len; + /* Copy or steal buffer for OFPT_PACKET_IN. */ if (clone) { - packet = ofpbuf_clone_data(packet->data, trim_size); - opi = packet->data; + packet = ofpbuf_clone_data_with_headroom(upcall->packet->data, + send_len, OPI_SIZE); } else { - packet->size = trim_size; + packet = upcall->packet; + packet->size = send_len; } - /* Update packet headers. */ + /* 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 == _ODPL_MISS_NR ? 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()). */ - pinsched_send(ofconn->schedulers[opi->reason], in_port, + pinsched_send(ofconn->schedulers[opi->reason], flow->in_port, packet, do_send_packet_in, ofconn); } -/* Replace struct odp_msg header in 'packet' by equivalent struct - * ofp_packet_in. The odp_msg must have sufficient headroom to do so (e.g. as - * returned by dpif_recv()). - * - * The conversion is not complete: the caller still needs to trim any unneeded - * payload off the end of the buffer, set the length in the OpenFlow header, - * and set buffer_id. Those require us to know the controller settings and so - * must be done on a per-controller basis. - * - * Returns the maximum number of bytes of the packet that should be sent to - * the controller (INT_MAX if no limit). */ -static int -do_convert_to_packet_in(struct ofpbuf *packet) -{ - struct odp_msg *msg = packet->data; - struct ofp_packet_in *opi; - uint8_t reason; - uint16_t total_len; - uint16_t in_port; - int max_len; - - /* Extract relevant header fields */ - if (msg->type == _ODPL_ACTION_NR) { - reason = OFPR_ACTION; - max_len = msg->arg; - } else { - reason = OFPR_NO_MATCH; - max_len = INT_MAX; - } - total_len = msg->length - sizeof *msg; - in_port = odp_port_to_ofp_port(msg->port); - - /* Repurpose packet buffer by overwriting header. */ - ofpbuf_pull(packet, sizeof(struct odp_msg)); - opi = ofpbuf_push_zeros(packet, offsetof(struct ofp_packet_in, data)); - opi->header.version = OFP_VERSION; - opi->header.type = OFPT_PACKET_IN; - opi->total_len = htons(total_len); - opi->in_port = htons(in_port); - opi->reason = reason; - - return max_len; -} - -/* Given 'packet' containing an odp_msg of type _ODPL_ACTION_NR or - * _ODPL_MISS_NR, sends an OFPT_PACKET_IN message to each OpenFlow controller - * as necessary according to their individual configurations. - * - * 'packet' must have sufficient headroom to convert it into a struct - * ofp_packet_in (e.g. as returned by dpif_recv()). +/* Given 'upcall', of type _ODPL_ACTION_NR or _ODPL_MISS_NR, sends an + * OFPT_PACKET_IN message to each OpenFlow controller as necessary according to + * their individual configurations. * * Takes ownership of 'packet'. */ static void -send_packet_in(struct ofproto *ofproto, struct ofpbuf *packet) +send_packet_in(struct ofproto *ofproto, struct dpif_upcall *upcall, + const struct flow *flow, bool clone) { struct ofconn *ofconn, *prev; - int max_len; - - max_len = do_convert_to_packet_in(packet); prev = NULL; LIST_FOR_EACH (ofconn, node, &ofproto->all_conns) { if (ofconn_receives_async_msgs(ofconn)) { if (prev) { - schedule_packet_in(prev, packet, max_len, true); + schedule_packet_in(prev, upcall, flow, true); } prev = ofconn; } } if (prev) { - schedule_packet_in(prev, packet, max_len, false); - } else { - ofpbuf_delete(packet); + schedule_packet_in(prev, upcall, flow, clone); + } else if (!clone) { + ofpbuf_delete(upcall->packet); } }