X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=5c7a497ecd72a5cd05e5c2d1c8fb3f5ffda8973f;hb=82272eded1ede569bcec3ba4ab212e5e3fb632ff;hp=5cd76df81301cab9a61ad2ceb20506cacdf0aa34;hpb=4d0ed51998b35595474d62f6696928c8d0cd209e;p=sliver-openvswitch.git diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 5cd76df81..5c7a497ec 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Nicira Networks. + * Copyright (c) 2009, 2010, 2011 Nicira Networks. * Copyright (c) 2010 Jean Tourrilhes - HP-Labs. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,6 +35,7 @@ #include "hmap.h" #include "in-band.h" #include "mac-learning.h" +#include "multipath.h" #include "netdev.h" #include "netflow.h" #include "netlink.h" @@ -205,7 +206,8 @@ struct facet { * * - Do include packets and bytes that were obtained from the datapath * when a flow was deleted (e.g. dpif_flow_del()) or when its - * statistics were reset (e.g. dpif_flow_put() with ODPPF_ZERO_STATS). + * statistics were reset (e.g. dpif_flow_put() with + * DPIF_FP_ZERO_STATS). * * - Do not include any packets or bytes that can currently be obtained * from the datapath by, e.g., dpif_flow_get(). @@ -247,7 +249,7 @@ static void facet_flush_stats(struct ofproto *, struct facet *); static void facet_make_actions(struct ofproto *, struct facet *, const struct ofpbuf *packet); static void facet_update_stats(struct ofproto *, struct facet *, - const struct odp_flow_stats *); + const struct dpif_flow_stats *); /* ofproto supports two kinds of OpenFlow connections: * @@ -299,7 +301,8 @@ struct ofconn { /* OFPT_PACKET_IN related data. */ struct rconn_packet_counter *packet_in_counter; /* # queued on 'rconn'. */ - struct pinsched *schedulers[2]; /* Indexed by reason code; see below. */ +#define N_SCHEDULERS 2 + struct pinsched *schedulers[N_SCHEDULERS]; struct pktbuf *pktbuf; /* OpenFlow packet buffers. */ int miss_send_len; /* Bytes to send of buffered packets. */ @@ -317,15 +320,6 @@ struct ofconn { enum ofproto_band band; /* In-band or out-of-band? */ }; -/* We use OFPR_NO_MATCH and OFPR_ACTION as indexes into struct ofconn's - * "schedulers" array. Their values are 0 and 1, and their meanings and values - * coincide with _ODPL_MISS_NR and _ODPL_ACTION_NR, so this is convenient. In - * case anything ever changes, check their values here. */ -#define N_SCHEDULERS 2 -BUILD_ASSERT_DECL(OFPR_NO_MATCH == 0); -BUILD_ASSERT_DECL(OFPR_NO_MATCH == _ODPL_MISS_NR); -BUILD_ASSERT_DECL(OFPR_ACTION == 1); -BUILD_ASSERT_DECL(OFPR_ACTION == _ODPL_ACTION_NR); static struct ofconn *ofconn_create(struct ofproto *, struct rconn *, enum ofconn_type); @@ -339,8 +333,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. */ @@ -411,7 +406,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 *); @@ -427,7 +422,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; @@ -442,14 +436,10 @@ 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); + error = dpif_recv_set_mask(dpif, + ((1u << DPIF_UC_MISS) | + (1u << DPIF_UC_ACTION) | + (1u << DPIF_UC_SAMPLE))); if (error) { VLOG_ERR("failed to listen on datapath %s: %s", datapath, strerror(error)); @@ -474,7 +464,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); @@ -1172,9 +1162,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 @@ -1188,7 +1178,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) { @@ -1353,6 +1343,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 @@ -1480,33 +1524,30 @@ ofproto_flush_flows(struct ofproto *ofproto) static void reinit_ports(struct ofproto *p) { - struct svec devnames; + 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); - svec_init(&devnames); + shash_init(&devnames); HMAP_FOR_EACH (ofport, hmap_node, &p->ports) { - svec_add (&devnames, ofport->opp.name); + 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++) { - svec_add (&devnames, odp_ports[i].devname); + DPIF_PORT_FOR_EACH (&dpif_port, &dump, p->dpif) { + shash_add_once (&devnames, dpif_port.name, NULL); } - free(odp_ports); - svec_sort_unique(&devnames); - for (i = 0; i < devnames.n; i++) { - update_port(p, devnames.names[i]); + SHASH_FOR_EACH (node, &devnames) { + update_port(p, node->name); } - svec_destroy(&devnames); + shash_destroy(&devnames); } 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; @@ -1515,27 +1556,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; @@ -1549,15 +1588,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; @@ -1658,7 +1697,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; @@ -1666,7 +1705,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); @@ -1682,20 +1721,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 @@ -1706,7 +1745,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; } } @@ -1722,31 +1761,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; - - error = dpif_port_list(p->dpif, &ports, &n_ports); - if (error) { - return error; - } + struct dpif_port_dump dump; + struct dpif_port dpif_port; - 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; } @@ -2049,7 +2083,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) { @@ -2058,15 +2092,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 = DPIF_UC_ACTION; + 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 { @@ -2094,12 +2131,12 @@ static void facet_execute(struct ofproto *ofproto, struct facet *facet, struct ofpbuf *packet) { - struct odp_flow_stats stats; + struct dpif_flow_stats stats; 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(); @@ -2151,7 +2188,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++; @@ -2265,16 +2302,25 @@ facet_make_actions(struct ofproto *p, struct facet *facet, } static int -facet_put__(struct ofproto *ofproto, struct facet *facet, int flags, - struct odp_flow_put *put) +facet_put__(struct ofproto *ofproto, struct facet *facet, + const struct nlattr *actions, size_t actions_len, + struct dpif_flow_stats *stats) { - memset(&put->flow.stats, 0, sizeof put->flow.stats); - odp_flow_key_from_flow(&put->flow.key, &facet->flow); - put->flow.actions = facet->actions; - put->flow.actions_len = facet->actions_len; - put->flow.flags = 0; - put->flags = flags; - return dpif_flow_put(ofproto->dpif, put); + uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S]; + enum dpif_flow_put_flags flags; + struct ofpbuf key; + + flags = DPIF_FP_CREATE | DPIF_FP_MODIFY; + if (stats) { + flags |= DPIF_FP_ZERO_STATS; + } + + ofpbuf_use_stack(&key, keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, &facet->flow); + assert(key.base == keybuf); + + return dpif_flow_put(ofproto->dpif, flags, key.data, key.size, + actions, actions_len, stats); } /* If 'facet' is installable, inserts or re-inserts it into 'p''s datapath. If @@ -2283,17 +2329,12 @@ facet_put__(struct ofproto *ofproto, struct facet *facet, int flags, static void facet_install(struct ofproto *p, struct facet *facet, bool zero_stats) { - if (facet->may_install) { - struct odp_flow_put put; - int flags; + struct dpif_flow_stats stats; - flags = ODPPF_CREATE | ODPPF_MODIFY; - if (zero_stats) { - flags |= ODPPF_ZERO_STATS; - } - if (!facet_put__(p, facet, flags, &put)) { - facet->installed = true; - } + if (facet->may_install + && !facet_put__(p, facet, facet->actions, facet->actions_len, + zero_stats ? &stats : NULL)) { + facet->installed = true; } } @@ -2320,14 +2361,16 @@ static void facet_uninstall(struct ofproto *p, struct facet *facet) { if (facet->installed) { - struct odp_flow odp_flow; - - odp_flow_key_from_flow(&odp_flow.key, &facet->flow); - odp_flow.actions = NULL; - odp_flow.actions_len = 0; - odp_flow.flags = 0; - if (!dpif_flow_del(p->dpif, &odp_flow)) { - facet_update_stats(p, facet, &odp_flow.stats); + uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S]; + struct dpif_flow_stats stats; + struct ofpbuf key; + + ofpbuf_use_stack(&key, keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, &facet->flow); + assert(key.base == keybuf); + + if (!dpif_flow_del(p->dpif, key.data, key.size, &stats)) { + facet_update_stats(p, facet, &stats); } facet->installed = false; } @@ -2456,19 +2499,13 @@ facet_revalidate(struct ofproto *ofproto, struct facet *facet) /* If the ODP actions changed or the installability changed, then we need * to talk to the datapath. */ - if (actions_changed || facet->may_install != facet->installed) { - if (facet->may_install) { - struct odp_flow_put put; - - memset(&put.flow.stats, 0, sizeof put.flow.stats); - odp_flow_key_from_flow(&put.flow.key, &facet->flow); - put.flow.actions = odp_actions->data; - put.flow.actions_len = odp_actions->size; - put.flow.flags = 0; - put.flags = ODPPF_CREATE | ODPPF_MODIFY | ODPPF_ZERO_STATS; - dpif_flow_put(ofproto->dpif, &put); - - facet_update_stats(ofproto, facet, &put.flow.stats); + if (actions_changed || ctx.may_set_up_flow != facet->installed) { + if (ctx.may_set_up_flow) { + struct dpif_flow_stats stats; + + facet_put__(ofproto, facet, + odp_actions->data, odp_actions->size, &stats); + facet_update_stats(ofproto, facet, &stats); } else { facet_uninstall(ofproto, facet); } @@ -2514,7 +2551,7 @@ static void send_error_oh(const struct ofconn *ofconn, const struct ofp_header *oh, int error) { - struct ofpbuf *buf = make_ofp_error_msg(error, oh); + struct ofpbuf *buf = ofputil_encode_error_msg(error, oh); if (buf) { COVERAGE_INC(ofproto_error); queue_tx(buf, ofconn, ofconn->reply_counter); @@ -2622,7 +2659,7 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc) /* Maximum depth of flow table recursion (due to NXAST_RESUBMIT actions) in a * flow translation. */ -#define MAX_RESUBMIT_RECURSION 8 +#define MAX_RESUBMIT_RECURSION 16 static void do_xlate_actions(const union ofp_action *in, size_t n_in, struct action_xlate_ctx *ctx); @@ -2680,7 +2717,7 @@ xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port) ctx->recurse--; } } else { - struct vlog_rate_limit recurse_rl = VLOG_RATE_LIMIT_INIT(1, 1); + static struct vlog_rate_limit recurse_rl = VLOG_RATE_LIMIT_INIT(1, 1); VLOG_ERR_RL(&recurse_rl, "NXAST_RESUBMIT recursed over %d times", MAX_RESUBMIT_RECURSION); @@ -2857,17 +2894,29 @@ xlate_set_dl_tci(struct action_xlate_ctx *ctx) } } +struct xlate_reg_state { + ovs_be16 vlan_tci; + ovs_be64 tun_id; +}; + static void -xlate_reg_move_action(struct action_xlate_ctx *ctx, - const struct nx_action_reg_move *narm) +save_reg_state(const struct action_xlate_ctx *ctx, + struct xlate_reg_state *state) { - ovs_be16 old_tci = ctx->flow.vlan_tci; - - nxm_execute_reg_move(narm, &ctx->flow); + state->vlan_tci = ctx->flow.vlan_tci; + state->tun_id = ctx->flow.tun_id; +} - if (ctx->flow.vlan_tci != old_tci) { +static void +update_reg_state(struct action_xlate_ctx *ctx, + const struct xlate_reg_state *state) +{ + if (ctx->flow.vlan_tci != state->vlan_tci) { xlate_set_dl_tci(ctx); } + if (ctx->flow.tun_id != state->tun_id) { + nl_msg_put_be64(ctx->odp_actions, ODPAT_SET_TUNNEL, ctx->flow.tun_id); + } } static void @@ -2877,7 +2926,9 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, const struct nx_action_resubmit *nar; const struct nx_action_set_tunnel *nast; const struct nx_action_set_queue *nasq; + const struct nx_action_multipath *nam; enum nx_action_subtype subtype = ntohs(nah->subtype); + struct xlate_reg_state state; ovs_be64 tun_id; assert(nah->vendor == htonl(NX_VENDOR_ID)); @@ -2910,12 +2961,18 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, break; case NXAST_REG_MOVE: - xlate_reg_move_action(ctx, (const struct nx_action_reg_move *) nah); + save_reg_state(ctx, &state); + nxm_execute_reg_move((const struct nx_action_reg_move *) nah, + &ctx->flow); + update_reg_state(ctx, &state); break; case NXAST_REG_LOAD: + save_reg_state(ctx, &state); nxm_execute_reg_load((const struct nx_action_reg_load *) nah, &ctx->flow); + update_reg_state(ctx, &state); + break; case NXAST_NOTE: /* Nothing to do. */ @@ -2927,6 +2984,11 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, ctx->flow.tun_id = tun_id; break; + case NXAST_MULTIPATH: + nam = (const struct nx_action_multipath *) nah; + multipath_execute(nam, &ctx->flow); + break; + /* If you add a new action here that modifies flow data, don't forget to * update the flow key in ctx->flow at the same time. */ @@ -3258,7 +3320,7 @@ make_nxstats_reply(ovs_be32 xid, ovs_be32 subtype, size_t body_len) nsm->type = htons(OFPST_VENDOR); nsm->flags = htons(0); nsm->vendor = htonl(NX_VENDOR_ID); - nsm->subtype = htonl(subtype); + nsm->subtype = subtype; return msg; } @@ -3390,42 +3452,33 @@ 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. * * 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 dpif_flow_stats stats; - /* 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); + dpif_flow_get(p->dpif, key.data, key.size, NULL, &stats); - 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; - } + packet_count += stats.n_packets + facet->packet_count; + byte_count += stats.n_bytes + facet->byte_count; } - free(odp_flows); /* Return the stats to the caller. */ *packet_countp = packet_count; @@ -3523,8 +3576,8 @@ put_nx_flow_stats(struct ofconn *ofconn, struct rule *rule, act_len = sizeof *rule->actions * rule->n_actions; - start_len = (*replyp)->size; append_nxstats_reply(sizeof *nfs + NXM_MAX_LEN + act_len, ofconn, replyp); + start_len = (*replyp)->size; reply = *replyp; nfs = ofpbuf_put_uninit(reply, sizeof *nfs); @@ -3795,17 +3848,11 @@ handle_queue_stats_request(struct ofconn *ofconn, const struct ofp_header *oh) return 0; } -static long long int -msec_from_nsec(uint64_t sec, uint32_t nsec) -{ - return !sec ? 0 : sec * 1000 + nsec / 1000000; -} - static void facet_update_time(struct ofproto *ofproto, struct facet *facet, - const struct odp_flow_stats *stats) + const struct dpif_flow_stats *stats) { - long long int used = msec_from_nsec(stats->used_sec, stats->used_nsec); + long long int used = stats->used; if (used > facet->used) { facet->used = used; if (used > facet->rule->used) { @@ -3823,7 +3870,7 @@ facet_update_time(struct ofproto *ofproto, struct facet *facet, * cleared out of the datapath. */ static void facet_update_stats(struct ofproto *ofproto, struct facet *facet, - const struct odp_flow_stats *stats) + const struct dpif_flow_stats *stats) { if (stats->n_packets) { facet_update_time(ofproto, facet, stats); @@ -4310,29 +4357,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); } @@ -4341,29 +4385,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) { @@ -4377,40 +4421,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) { - case _ODPL_ACTION_NR: + switch (upcall->type) { + case DPIF_UC_ACTION: 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: + case DPIF_UC_SAMPLE: 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); + case DPIF_UC_MISS: + 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; } } @@ -4463,36 +4506,40 @@ 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; + const struct dpif_flow_stats *stats; + struct dpif_flow_dump dump; + const struct nlattr *key; + size_t key_len; - 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); + while (dpif_flow_dump_next(&dump, &key, &key_len, NULL, NULL, &stats)) { struct facet *facet; struct flow flow; - odp_flow_key_to_flow(&f->key, &flow); + if (odp_flow_key_to_flow(key, key_len, &flow)) { + struct ds s; + + ds_init(&s); + odp_flow_key_format(key, 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, stats); + facet_account(p, facet, 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, key, key_len, NULL); } - } - free(flows); + dpif_flow_dump_done(&dump); } /* Calculates and returns the number of milliseconds of idle time after which @@ -4591,32 +4638,19 @@ facet_active_timeout(struct ofproto *ofproto, struct facet *facet) if (ofproto->netflow && !facet_is_controller_flow(facet) && netflow_active_timeout_expired(ofproto->netflow, &facet->nf_flow)) { struct ofexpired expired; - struct odp_flow odp_flow; - /* Get updated flow stats. - * - * XXX We could avoid this call entirely if (1) ofproto_update_used() - * updated TCP flags and (2) the dpif_flow_list_all() in - * 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); - odp_flow.flags = ODPFF_ZERO_TCP_FLAGS; - dpif_flow_get(ofproto->dpif, &odp_flow); - - if (odp_flow.stats.n_packets) { - facet_update_time(ofproto, facet, &odp_flow.stats); - netflow_flow_update_flags(&facet->nf_flow, - odp_flow.stats.tcp_flags); - } + struct dpif_flow_stats stats; + + facet_put__(ofproto, facet, facet->actions, facet->actions_len, + &stats); + facet_update_stats(ofproto, facet, &stats); } expired.flow = facet->flow; - expired.packet_count = facet->packet_count + - odp_flow.stats.n_packets; - expired.byte_count = facet->byte_count + odp_flow.stats.n_bytes; + expired.packet_count = facet->packet_count; + expired.byte_count = facet->byte_count; expired.used = facet->used; - netflow_expire(ofproto->netflow, &facet->nf_flow, &expired); } } @@ -4678,7 +4712,7 @@ compose_ofp_flow_removed(struct ofconn *ofconn, const struct rule *rule, struct ofp_flow_removed *ofr; struct ofpbuf *buf; - ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &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); @@ -4698,9 +4732,9 @@ compose_nx_flow_removed(const struct rule *rule, uint8_t reason) struct ofpbuf *buf; int match_len; - make_nxmsg(sizeof *nfr, NXT_FLOW_REMOVED, &buf); - + 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); @@ -4744,150 +4778,105 @@ 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. - * - * 'max_len' specifies the maximum number of bytes of the packet to send on - * 'ofconn' (INT_MAX specifies no limit). +/* 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. * - * 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; + int idx; - /* Get buffer. */ - if (opi->reason == OFPR_ACTION) { + /* Get OpenFlow buffer_id. */ + if (upcall->type == DPIF_UC_ACTION) { 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 == DPIF_UC_ACTION) { + 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 == 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()). */ - pinsched_send(ofconn->schedulers[opi->reason], in_port, + idx = upcall->type == DPIF_UC_MISS ? 0 : 1; + pinsched_send(ofconn->schedulers[idx], 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 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'. */ 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); } } @@ -5000,7 +4989,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, const char *args_, struct ds result; struct flow flow; uint16_t in_port; - ovs_be32 tun_id; + ovs_be64 tun_id; char *s; ofpbuf_init(&packet, strlen(args) / 2); @@ -5022,7 +5011,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, const char *args_, goto exit; } - tun_id = ntohl(strtoul(tun_id_s, NULL, 10)); + tun_id = htonll(strtoull(tun_id_s, NULL, 10)); in_port = ofp_port_to_odp_port(atoi(in_port_s)); packet_s = ofpbuf_put_hex(&packet, packet_s, NULL);