- case NXAST_SET_TUNNEL:
- nast = (const struct nx_action_set_tunnel *) nah;
- oa = odp_actions_add(ctx->out, ODPAT_SET_TUNNEL);
- ctx->flow.tun_id = oa->tunnel.tun_id = nast->tun_id;
- break;
-
- case NXAST_DROP_SPOOFED_ARP:
- if (ctx->flow.dl_type == htons(ETH_TYPE_ARP)) {
- odp_actions_add(ctx->out, ODPAT_DROP_SPOOFED_ARP);
- }
- break;
-
- case NXAST_SET_QUEUE:
- nasq = (const struct nx_action_set_queue *) nah;
- xlate_set_queue_action(ctx, nasq);
- break;
-
- case NXAST_POP_QUEUE:
- odp_actions_add(ctx->out, ODPAT_POP_PRIORITY);
- break;
-
- case NXAST_REG_MOVE:
- xlate_reg_move_action(ctx, (const struct nx_action_reg_move *) nah);
- break;
-
- case NXAST_REG_LOAD:
- nxm_execute_reg_load((const struct nx_action_reg_load *) nah,
- &ctx->flow);
-
- case NXAST_NOTE:
- /* Nothing to do. */
- 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. */
-
- default:
- VLOG_DBG_RL(&rl, "unknown Nicira action type %"PRIu16, subtype);
- break;
- }
-}
-
-static void
-do_xlate_actions(const union ofp_action *in, size_t n_in,
- struct action_xlate_ctx *ctx)
-{
- struct actions_iterator iter;
- const union ofp_action *ia;
- const struct ofport *port;
-
- port = get_port(ctx->ofproto, ctx->flow.in_port);
- if (port && port->opp.config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) &&
- port->opp.config & (eth_addr_equals(ctx->flow.dl_dst, eth_addr_stp)
- ? OFPPC_NO_RECV_STP : OFPPC_NO_RECV)) {
- /* Drop this flow. */
- return;
- }
-
- for (ia = actions_first(&iter, in, n_in); ia; ia = actions_next(&iter)) {
- uint16_t type = ntohs(ia->type);
- union odp_action *oa;
-
- switch (type) {
- case OFPAT_OUTPUT:
- xlate_output_action(ctx, &ia->output);
- break;
-
- case OFPAT_SET_VLAN_VID:
- ctx->flow.dl_vlan = ia->vlan_vid.vlan_vid;
- xlate_set_dl_tci(ctx);
- break;
-
- case OFPAT_SET_VLAN_PCP:
- ctx->flow.dl_vlan_pcp = ia->vlan_pcp.vlan_pcp;
- xlate_set_dl_tci(ctx);
- break;
-
- case OFPAT_STRIP_VLAN:
- ctx->flow.dl_vlan = htons(OFP_VLAN_NONE);
- ctx->flow.dl_vlan_pcp = 0;
- xlate_set_dl_tci(ctx);
- break;
-
- case OFPAT_SET_DL_SRC:
- oa = odp_actions_add(ctx->out, ODPAT_SET_DL_SRC);
- memcpy(oa->dl_addr.dl_addr,
- ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
- memcpy(ctx->flow.dl_src,
- ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
- break;
-
- case OFPAT_SET_DL_DST:
- oa = odp_actions_add(ctx->out, ODPAT_SET_DL_DST);
- memcpy(oa->dl_addr.dl_addr,
- ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
- memcpy(ctx->flow.dl_dst,
- ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
- break;
-
- case OFPAT_SET_NW_SRC:
- oa = odp_actions_add(ctx->out, ODPAT_SET_NW_SRC);
- ctx->flow.nw_src = oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
- break;
-
- case OFPAT_SET_NW_DST:
- oa = odp_actions_add(ctx->out, ODPAT_SET_NW_DST);
- ctx->flow.nw_dst = oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
- break;
-
- case OFPAT_SET_NW_TOS:
- oa = odp_actions_add(ctx->out, ODPAT_SET_NW_TOS);
- ctx->flow.nw_tos = oa->nw_tos.nw_tos = ia->nw_tos.nw_tos;
- break;
-
- case OFPAT_SET_TP_SRC:
- oa = odp_actions_add(ctx->out, ODPAT_SET_TP_SRC);
- ctx->flow.tp_src = oa->tp_port.tp_port = ia->tp_port.tp_port;
- break;
-
- case OFPAT_SET_TP_DST:
- oa = odp_actions_add(ctx->out, ODPAT_SET_TP_DST);
- ctx->flow.tp_dst = oa->tp_port.tp_port = ia->tp_port.tp_port;
- break;
-
- case OFPAT_VENDOR:
- xlate_nicira_action(ctx, (const struct nx_action_header *) ia);
- break;
-
- case OFPAT_ENQUEUE:
- xlate_enqueue_action(ctx, (const struct ofp_action_enqueue *) ia);
- break;
-
- default:
- VLOG_DBG_RL(&rl, "unknown action type %"PRIu16, type);
- break;
- }
- }
-}
-
-static int
-xlate_actions(const union ofp_action *in, size_t n_in,
- const struct flow *flow, struct ofproto *ofproto,
- const struct ofpbuf *packet,
- struct odp_actions *out, tag_type *tags, bool *may_set_up_flow,
- uint16_t *nf_output_iface)
-{
- struct action_xlate_ctx ctx;
-
- COVERAGE_INC(ofproto_ofp2odp);
- odp_actions_init(out);
- ctx.flow = *flow;
- ctx.recurse = 0;
- ctx.ofproto = ofproto;
- ctx.packet = packet;
- ctx.out = out;
- ctx.tags = 0;
- ctx.may_set_up_flow = true;
- ctx.nf_output_iface = NF_OUT_DROP;
- do_xlate_actions(in, n_in, &ctx);
- remove_pop_action(&ctx);
-
- /* Check with in-band control to see if we're allowed to set up this
- * flow. */
- if (!in_band_rule_check(ofproto->in_band, flow, out)) {
- ctx.may_set_up_flow = false;
- }
-
- if (tags) {
- *tags = ctx.tags;
- }
- if (may_set_up_flow) {
- *may_set_up_flow = ctx.may_set_up_flow;
- }
- if (nf_output_iface) {
- *nf_output_iface = ctx.nf_output_iface;
- }
- if (odp_actions_overflow(out)) {
- COVERAGE_INC(odp_overflow);
- odp_actions_init(out);
- return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_TOO_MANY);
- }
- return 0;
-}
-
-/* Checks whether 'ofconn' is a slave controller. If so, returns an OpenFlow
- * error message code (composed with ofp_mkerr()) for the caller to propagate
- * upward. Otherwise, returns 0.
- *
- * The log message mentions 'msg_type'. */
-static int
-reject_slave_controller(struct ofconn *ofconn, const const char *msg_type)
-{
- if (ofconn->type == OFCONN_PRIMARY && ofconn->role == NX_ROLE_SLAVE) {
- static struct vlog_rate_limit perm_rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&perm_rl, "rejecting %s message from slave controller",
- msg_type);
-
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM);
- } else {
- return 0;
- }
-}
-
-static int
-handle_packet_out(struct ofconn *ofconn, struct ofp_header *oh)
-{
- struct ofproto *p = ofconn->ofproto;
- struct ofp_packet_out *opo;
- struct ofpbuf payload, *buffer;
- union ofp_action *ofp_actions;
- struct odp_actions odp_actions;
- struct ofpbuf request;
- struct flow flow;
- size_t n_ofp_actions;
- uint16_t in_port;
- int error;
-
- COVERAGE_INC(ofproto_packet_out);
-
- error = reject_slave_controller(ofconn, "OFPT_PACKET_OUT");
- if (error) {
- return error;
- }
-
- /* Get ofp_packet_out. */
- request.data = oh;
- request.size = ntohs(oh->length);
- opo = ofpbuf_try_pull(&request, offsetof(struct ofp_packet_out, actions));
- if (!opo) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
-
- /* Get actions. */
- error = ofputil_pull_actions(&request, ntohs(opo->actions_len),
- &ofp_actions, &n_ofp_actions);
- if (error) {
- return error;
- }
-
- /* Get payload. */
- if (opo->buffer_id != htonl(UINT32_MAX)) {
- error = pktbuf_retrieve(ofconn->pktbuf, ntohl(opo->buffer_id),
- &buffer, &in_port);
- if (error || !buffer) {
- return error;
- }
- payload = *buffer;
- } else {
- payload = request;
- buffer = NULL;
- }
-
- /* Extract flow, check actions. */
- flow_extract(&payload, 0, ofp_port_to_odp_port(ntohs(opo->in_port)),
- &flow);
- error = validate_actions(ofp_actions, n_ofp_actions, &flow, p->max_ports);
- if (error) {
- goto exit;
- }
-
- /* Send. */
- error = xlate_actions(ofp_actions, n_ofp_actions, &flow, p, &payload,
- &odp_actions, NULL, NULL, NULL);
- if (!error) {
- dpif_execute(p->dpif, odp_actions.actions, odp_actions.n_actions,
- &payload);
- }
-
-exit:
- ofpbuf_delete(buffer);
- return 0;
-}
-
-static void
-update_port_config(struct ofproto *p, struct ofport *port,
- uint32_t config, uint32_t mask)
-{
- mask &= config ^ port->opp.config;
- if (mask & OFPPC_PORT_DOWN) {
- if (config & OFPPC_PORT_DOWN) {
- netdev_turn_flags_off(port->netdev, NETDEV_UP, true);
- } else {
- netdev_turn_flags_on(port->netdev, NETDEV_UP, true);
- }
- }
-#define REVALIDATE_BITS (OFPPC_NO_RECV | OFPPC_NO_RECV_STP | \
- OFPPC_NO_FWD | OFPPC_NO_FLOOD)
- if (mask & REVALIDATE_BITS) {
- COVERAGE_INC(ofproto_costly_flags);
- port->opp.config ^= mask & REVALIDATE_BITS;
- p->need_revalidate = true;
- }
-#undef REVALIDATE_BITS
- if (mask & OFPPC_NO_PACKET_IN) {
- port->opp.config ^= OFPPC_NO_PACKET_IN;
- }
-}
-
-static int
-handle_port_mod(struct ofconn *ofconn, struct ofp_header *oh)
-{
- struct ofproto *p = ofconn->ofproto;
- const struct ofp_port_mod *opm;
- struct ofport *port;
- int error;
-
- error = reject_slave_controller(ofconn, "OFPT_PORT_MOD");
- if (error) {
- return error;
- }
- error = check_ofp_message(oh, OFPT_PORT_MOD, sizeof *opm);
- if (error) {
- return error;
- }
- opm = (struct ofp_port_mod *) oh;
-
- port = get_port(p, ofp_port_to_odp_port(ntohs(opm->port_no)));
- if (!port) {
- return ofp_mkerr(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_PORT);
- } else if (memcmp(port->opp.hw_addr, opm->hw_addr, OFP_ETH_ALEN)) {
- return ofp_mkerr(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_HW_ADDR);
- } else {
- update_port_config(p, port, ntohl(opm->config), ntohl(opm->mask));
- if (opm->advertise) {
- netdev_set_advertisements(port->netdev, ntohl(opm->advertise));
- }
- }
- return 0;
-}
-
-static struct ofpbuf *
-make_ofp_stats_reply(ovs_be32 xid, ovs_be16 type, size_t body_len)
-{
- struct ofp_stats_reply *osr;
- struct ofpbuf *msg;
-
- msg = ofpbuf_new(MIN(sizeof *osr + body_len, UINT16_MAX));
- osr = put_openflow_xid(sizeof *osr, OFPT_STATS_REPLY, xid, msg);
- osr->type = type;
- osr->flags = htons(0);
- return msg;
-}
-
-static struct ofpbuf *
-start_ofp_stats_reply(const struct ofp_stats_request *request, size_t body_len)
-{
- return make_ofp_stats_reply(request->header.xid, request->type, body_len);
-}
-
-static void *
-append_ofp_stats_reply(size_t nbytes, struct ofconn *ofconn,
- struct ofpbuf **msgp)
-{
- struct ofpbuf *msg = *msgp;
- assert(nbytes <= UINT16_MAX - sizeof(struct ofp_stats_reply));
- if (nbytes + msg->size > UINT16_MAX) {
- struct ofp_stats_reply *reply = msg->data;
- reply->flags = htons(OFPSF_REPLY_MORE);
- *msgp = make_ofp_stats_reply(reply->header.xid, reply->type, nbytes);
- queue_tx(msg, ofconn, ofconn->reply_counter);
- }
- return ofpbuf_put_uninit(*msgp, nbytes);
-}
-
-static struct ofpbuf *
-make_nxstats_reply(ovs_be32 xid, ovs_be32 subtype, size_t body_len)
-{
- struct nicira_stats_msg *nsm;
- struct ofpbuf *msg;
-
- msg = ofpbuf_new(MIN(sizeof *nsm + body_len, UINT16_MAX));
- nsm = put_openflow_xid(sizeof *nsm, OFPT_STATS_REPLY, xid, msg);
- nsm->type = htons(OFPST_VENDOR);
- nsm->flags = htons(0);
- nsm->vendor = htonl(NX_VENDOR_ID);
- nsm->subtype = htonl(subtype);
- return msg;
-}
-
-static struct ofpbuf *
-start_nxstats_reply(const struct nicira_stats_msg *request, size_t body_len)
-{
- return make_nxstats_reply(request->header.xid, request->subtype, body_len);
-}
-
-static void
-append_nxstats_reply(size_t nbytes, struct ofconn *ofconn,
- struct ofpbuf **msgp)
-{
- struct ofpbuf *msg = *msgp;
- assert(nbytes <= UINT16_MAX - sizeof(struct nicira_stats_msg));
- if (nbytes + msg->size > UINT16_MAX) {
- struct nicira_stats_msg *reply = msg->data;
- reply->flags = htons(OFPSF_REPLY_MORE);
- *msgp = make_nxstats_reply(reply->header.xid, reply->subtype, nbytes);
- queue_tx(msg, ofconn, ofconn->reply_counter);
- }
- ofpbuf_prealloc_tailroom(*msgp, nbytes);
-}
-
-static int
-handle_desc_stats_request(struct ofconn *ofconn,
- struct ofp_stats_request *request)
-{
- struct ofproto *p = ofconn->ofproto;
- struct ofp_desc_stats *ods;
- struct ofpbuf *msg;
-
- msg = start_ofp_stats_reply(request, sizeof *ods);
- ods = append_ofp_stats_reply(sizeof *ods, ofconn, &msg);
- memset(ods, 0, sizeof *ods);
- ovs_strlcpy(ods->mfr_desc, p->mfr_desc, sizeof ods->mfr_desc);
- ovs_strlcpy(ods->hw_desc, p->hw_desc, sizeof ods->hw_desc);
- ovs_strlcpy(ods->sw_desc, p->sw_desc, sizeof ods->sw_desc);
- ovs_strlcpy(ods->serial_num, p->serial_desc, sizeof ods->serial_num);
- ovs_strlcpy(ods->dp_desc, p->dp_desc, sizeof ods->dp_desc);
- queue_tx(msg, ofconn, ofconn->reply_counter);
-
- return 0;
-}
-
-static int
-handle_table_stats_request(struct ofconn *ofconn,
- struct ofp_stats_request *request)
-{
- struct ofproto *p = ofconn->ofproto;
- struct ofp_table_stats *ots;
- struct ofpbuf *msg;
-
- msg = start_ofp_stats_reply(request, sizeof *ots * 2);
-
- /* Classifier table. */
- ots = append_ofp_stats_reply(sizeof *ots, ofconn, &msg);
- memset(ots, 0, sizeof *ots);
- strcpy(ots->name, "classifier");
- ots->wildcards = (ofconn->flow_format == NXFF_OPENFLOW10
- ? htonl(OFPFW_ALL) : htonl(OVSFW_ALL));
- ots->max_entries = htonl(1024 * 1024); /* An arbitrary big number. */
- ots->active_count = htonl(classifier_count(&p->cls));
- ots->lookup_count = htonll(0); /* XXX */
- ots->matched_count = htonll(0); /* XXX */
-
- queue_tx(msg, ofconn, ofconn->reply_counter);
- return 0;
-}
-
-static void
-append_port_stat(struct ofport *port, struct ofconn *ofconn,
- struct ofpbuf **msgp)
-{
- struct netdev_stats stats;
- struct ofp_port_stats *ops;
-
- /* Intentionally ignore return value, since errors will set
- * 'stats' to all-1s, which is correct for OpenFlow, and
- * netdev_get_stats() will log errors. */
- netdev_get_stats(port->netdev, &stats);
-
- ops = append_ofp_stats_reply(sizeof *ops, ofconn, msgp);
- ops->port_no = htons(port->opp.port_no);
- memset(ops->pad, 0, sizeof ops->pad);
- ops->rx_packets = htonll(stats.rx_packets);
- ops->tx_packets = htonll(stats.tx_packets);
- ops->rx_bytes = htonll(stats.rx_bytes);
- ops->tx_bytes = htonll(stats.tx_bytes);
- ops->rx_dropped = htonll(stats.rx_dropped);
- ops->tx_dropped = htonll(stats.tx_dropped);
- ops->rx_errors = htonll(stats.rx_errors);
- ops->tx_errors = htonll(stats.tx_errors);
- ops->rx_frame_err = htonll(stats.rx_frame_errors);
- ops->rx_over_err = htonll(stats.rx_over_errors);
- ops->rx_crc_err = htonll(stats.rx_crc_errors);
- ops->collisions = htonll(stats.collisions);
-}
-
-static int
-handle_port_stats_request(struct ofconn *ofconn, struct ofp_stats_request *osr,
- size_t arg_size)
-{
- struct ofproto *p = ofconn->ofproto;
- struct ofp_port_stats_request *psr;
- struct ofp_port_stats *ops;
- struct ofpbuf *msg;
- struct ofport *port;
-
- if (arg_size != sizeof *psr) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- psr = (struct ofp_port_stats_request *) osr->body;
-
- msg = start_ofp_stats_reply(osr, sizeof *ops * 16);
- if (psr->port_no != htons(OFPP_NONE)) {
- port = get_port(p, ofp_port_to_odp_port(ntohs(psr->port_no)));
- if (port) {
- append_port_stat(port, ofconn, &msg);
- }
- } else {
- HMAP_FOR_EACH (port, hmap_node, &p->ports) {
- append_port_stat(port, ofconn, &msg);
- }
- }
-
- queue_tx(msg, ofconn, ofconn->reply_counter);
- return 0;
-}
-
-/* Obtains statistic counters for 'rule' within 'p' and stores them into
- * '*packet_countp' and '*byte_countp'. The returned statistics include
- * statistics for all of 'rule''s facets. */
-static void
-query_stats(struct ofproto *p, struct rule *rule,
- uint64_t *packet_countp, uint64_t *byte_countp)
-{
- uint64_t packet_count, byte_count;
- struct facet *facet;
- struct odp_flow *odp_flows;
- size_t n_odp_flows;
-
- /* 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.
- *
- * 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;
- 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;
- }
-
- /* 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;
-
- 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;
- }
- }
- free(odp_flows);
-
- /* Return the stats to the caller. */
- *packet_countp = packet_count;
- *byte_countp = byte_count;
-}
-
-static void
-calc_flow_duration(long long int start, ovs_be32 *sec, ovs_be32 *nsec)
-{
- long long int msecs = time_msec() - start;
- *sec = htonl(msecs / 1000);
- *nsec = htonl((msecs % 1000) * (1000 * 1000));
-}
-
-static void
-put_ofp_flow_stats(struct ofconn *ofconn, struct rule *rule,
- ovs_be16 out_port, struct ofpbuf **replyp)
-{
- struct ofp_flow_stats *ofs;
- uint64_t packet_count, byte_count;
- size_t act_len, len;
-
- if (rule_is_hidden(rule) || !rule_has_out_port(rule, out_port)) {
- return;
- }
-
- act_len = sizeof *rule->actions * rule->n_actions;
- len = offsetof(struct ofp_flow_stats, actions) + act_len;
-
- query_stats(ofconn->ofproto, rule, &packet_count, &byte_count);
-
- ofs = append_ofp_stats_reply(len, ofconn, replyp);
- ofs->length = htons(len);
- ofs->table_id = 0;
- ofs->pad = 0;
- flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards,
- ofconn->flow_format, &ofs->match);
- calc_flow_duration(rule->created, &ofs->duration_sec, &ofs->duration_nsec);
- ofs->cookie = rule->flow_cookie;
- ofs->priority = htons(rule->cr.priority);
- ofs->idle_timeout = htons(rule->idle_timeout);
- ofs->hard_timeout = htons(rule->hard_timeout);
- memset(ofs->pad2, 0, sizeof ofs->pad2);
- ofs->packet_count = htonll(packet_count);
- ofs->byte_count = htonll(byte_count);
- if (rule->n_actions > 0) {
- memcpy(ofs->actions, rule->actions, act_len);
- }
-}
-
-static bool
-is_valid_table(uint8_t table_id)
-{
- return table_id == 0 || table_id == 0xff;
-}
-
-static int
-handle_flow_stats_request(struct ofconn *ofconn,
- const struct ofp_stats_request *osr, size_t arg_size)
-{
- struct ofp_flow_stats_request *fsr;
- struct ofpbuf *reply;
-
- if (arg_size != sizeof *fsr) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- fsr = (struct ofp_flow_stats_request *) osr->body;
-
- COVERAGE_INC(ofproto_flows_req);
- reply = start_ofp_stats_reply(osr, 1024);
- if (is_valid_table(fsr->table_id)) {
- struct cls_cursor cursor;
- struct cls_rule target;
- struct rule *rule;
-
- cls_rule_from_match(&fsr->match, 0, NXFF_OPENFLOW10, 0, &target);
- cls_cursor_init(&cursor, &ofconn->ofproto->cls, &target);
- CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
- put_ofp_flow_stats(ofconn, rule, fsr->out_port, &reply);
- }
- }
- queue_tx(reply, ofconn, ofconn->reply_counter);
-
- return 0;
-}
-
-static void
-put_nx_flow_stats(struct ofconn *ofconn, struct rule *rule,
- ovs_be16 out_port, struct ofpbuf **replyp)
-{
- struct nx_flow_stats *nfs;
- uint64_t packet_count, byte_count;
- size_t act_len, start_len;
- struct ofpbuf *reply;
-
- if (rule_is_hidden(rule) || !rule_has_out_port(rule, out_port)) {
- return;
- }
-
- query_stats(ofconn->ofproto, rule, &packet_count, &byte_count);
-
- act_len = sizeof *rule->actions * rule->n_actions;
-
- start_len = (*replyp)->size;
- append_nxstats_reply(sizeof *nfs + NXM_MAX_LEN + act_len, ofconn, replyp);
- reply = *replyp;
-
- nfs = ofpbuf_put_uninit(reply, sizeof *nfs);
- nfs->table_id = 0;
- nfs->pad = 0;
- calc_flow_duration(rule->created, &nfs->duration_sec, &nfs->duration_nsec);
- nfs->cookie = rule->flow_cookie;
- nfs->priority = htons(rule->cr.priority);
- nfs->idle_timeout = htons(rule->idle_timeout);
- nfs->hard_timeout = htons(rule->hard_timeout);
- nfs->match_len = htons(nx_put_match(reply, &rule->cr));
- memset(nfs->pad2, 0, sizeof nfs->pad2);
- nfs->packet_count = htonll(packet_count);
- nfs->byte_count = htonll(byte_count);
- if (rule->n_actions > 0) {
- ofpbuf_put(reply, rule->actions, act_len);
- }
- nfs->length = htons(reply->size - start_len);
-}
-
-static int
-handle_nxst_flow(struct ofconn *ofconn, struct ofpbuf *b)
-{
- struct nx_flow_stats_request *nfsr;
- struct cls_rule target;
- struct ofpbuf *reply;
- int error;
-
- /* Dissect the message. */
- nfsr = ofpbuf_try_pull(b, sizeof *nfsr);
- if (!nfsr) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- error = nx_pull_match(b, ntohs(nfsr->match_len), 0, &target);
- if (error) {
- return error;
- }
-
- COVERAGE_INC(ofproto_flows_req);
- reply = start_nxstats_reply(&nfsr->nsm, 1024);
- if (is_valid_table(nfsr->table_id)) {
- struct cls_cursor cursor;
- struct rule *rule;
-
- cls_cursor_init(&cursor, &ofconn->ofproto->cls, &target);
- CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
- put_nx_flow_stats(ofconn, rule, nfsr->out_port, &reply);
- }
- }
- queue_tx(reply, ofconn, ofconn->reply_counter);
-
- return 0;
-}
-
-static void
-flow_stats_ds(struct ofproto *ofproto, struct rule *rule, struct ds *results)
-{
- struct ofp_match match;
- uint64_t packet_count, byte_count;
- size_t act_len = sizeof *rule->actions * rule->n_actions;
-
- query_stats(ofproto, rule, &packet_count, &byte_count);
- flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards,
- NXFF_OPENFLOW10, &match);
-
- ds_put_format(results, "duration=%llds, ",
- (time_msec() - rule->created) / 1000);
- ds_put_format(results, "priority=%u, ", rule->cr.priority);
- ds_put_format(results, "n_packets=%"PRIu64", ", packet_count);
- ds_put_format(results, "n_bytes=%"PRIu64", ", byte_count);
- ofp_print_match(results, &match, true);
- if (act_len > 0) {
- ofp_print_actions(results, &rule->actions->header, act_len);
- } else {
- ds_put_cstr(results, "drop");
- }
- ds_put_cstr(results, "\n");
-}
-
-/* Adds a pretty-printed description of all flows to 'results', including
- * those marked hidden by secchan (e.g., by in-band control). */
-void
-ofproto_get_all_flows(struct ofproto *p, struct ds *results)
-{
- struct cls_cursor cursor;
- struct rule *rule;
-
- cls_cursor_init(&cursor, &p->cls, NULL);
- CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
- flow_stats_ds(p, rule, results);
- }
-}
-
-static void
-query_aggregate_stats(struct ofproto *ofproto, struct cls_rule *target,
- ovs_be16 out_port, uint8_t table_id,
- struct ofp_aggregate_stats_reply *oasr)
-{
- uint64_t total_packets = 0;
- uint64_t total_bytes = 0;
- int n_flows = 0;
-
- COVERAGE_INC(ofproto_agg_request);
-
- if (is_valid_table(table_id)) {
- struct cls_cursor cursor;
- struct rule *rule;
-
- cls_cursor_init(&cursor, &ofproto->cls, target);
- CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
- if (!rule_is_hidden(rule) && rule_has_out_port(rule, out_port)) {
- uint64_t packet_count;
- uint64_t byte_count;
-
- query_stats(ofproto, rule, &packet_count, &byte_count);
-
- total_packets += packet_count;
- total_bytes += byte_count;
- n_flows++;
- }
- }
- }
-
- oasr->flow_count = htonl(n_flows);
- oasr->packet_count = htonll(total_packets);
- oasr->byte_count = htonll(total_bytes);
- memset(oasr->pad, 0, sizeof oasr->pad);
-}
-
-static int
-handle_aggregate_stats_request(struct ofconn *ofconn,
- const struct ofp_stats_request *osr,
- size_t arg_size)
-{
- struct ofp_aggregate_stats_request *request;
- struct ofp_aggregate_stats_reply *reply;
- struct cls_rule target;
- struct ofpbuf *msg;
-
- if (arg_size != sizeof *request) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- request = (struct ofp_aggregate_stats_request *) osr->body;
-
- cls_rule_from_match(&request->match, 0, NXFF_OPENFLOW10, 0, &target);
-
- msg = start_ofp_stats_reply(osr, sizeof *reply);
- reply = append_ofp_stats_reply(sizeof *reply, ofconn, &msg);
- query_aggregate_stats(ofconn->ofproto, &target, request->out_port,
- request->table_id, reply);
- queue_tx(msg, ofconn, ofconn->reply_counter);
- return 0;
-}
-
-static int
-handle_nxst_aggregate(struct ofconn *ofconn, struct ofpbuf *b)
-{
- struct nx_aggregate_stats_request *request;
- struct ofp_aggregate_stats_reply *reply;
- struct cls_rule target;
- struct ofpbuf *buf;
- int error;
-
- /* Dissect the message. */
- request = ofpbuf_try_pull(b, sizeof *request);
- if (!request) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- error = nx_pull_match(b, ntohs(request->match_len), 0, &target);
- if (error) {
- return error;
- }
-
- /* Reply. */
- COVERAGE_INC(ofproto_flows_req);
- buf = start_nxstats_reply(&request->nsm, sizeof *reply);
- reply = ofpbuf_put_uninit(buf, sizeof *reply);
- query_aggregate_stats(ofconn->ofproto, &target, request->out_port,
- request->table_id, reply);
- queue_tx(buf, ofconn, ofconn->reply_counter);
-
- return 0;
-}
-
-struct queue_stats_cbdata {
- struct ofconn *ofconn;
- struct ofport *ofport;
- struct ofpbuf *msg;
-};
-
-static void
-put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id,
- const struct netdev_queue_stats *stats)
-{
- struct ofp_queue_stats *reply;
-
- reply = append_ofp_stats_reply(sizeof *reply, cbdata->ofconn, &cbdata->msg);
- reply->port_no = htons(cbdata->ofport->opp.port_no);
- memset(reply->pad, 0, sizeof reply->pad);
- reply->queue_id = htonl(queue_id);
- reply->tx_bytes = htonll(stats->tx_bytes);
- reply->tx_packets = htonll(stats->tx_packets);
- reply->tx_errors = htonll(stats->tx_errors);
-}
-
-static void
-handle_queue_stats_dump_cb(uint32_t queue_id,
- struct netdev_queue_stats *stats,
- void *cbdata_)
-{
- struct queue_stats_cbdata *cbdata = cbdata_;
-
- put_queue_stats(cbdata, queue_id, stats);
-}
-
-static void
-handle_queue_stats_for_port(struct ofport *port, uint32_t queue_id,
- struct queue_stats_cbdata *cbdata)
-{
- cbdata->ofport = port;
- if (queue_id == OFPQ_ALL) {
- netdev_dump_queue_stats(port->netdev,
- handle_queue_stats_dump_cb, cbdata);
- } else {
- struct netdev_queue_stats stats;
-
- if (!netdev_get_queue_stats(port->netdev, queue_id, &stats)) {
- put_queue_stats(cbdata, queue_id, &stats);
- }
- }
-}
-
-static int
-handle_queue_stats_request(struct ofconn *ofconn,
- const struct ofp_stats_request *osr,
- size_t arg_size)
-{
- struct ofproto *ofproto = ofconn->ofproto;
- struct ofp_queue_stats_request *qsr;
- struct queue_stats_cbdata cbdata;
- struct ofport *port;
- unsigned int port_no;
- uint32_t queue_id;
-
- if (arg_size != sizeof *qsr) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- qsr = (struct ofp_queue_stats_request *) osr->body;
-
- COVERAGE_INC(ofproto_queue_req);
-
- cbdata.ofconn = ofconn;
- cbdata.msg = start_ofp_stats_reply(osr, 128);
-
- port_no = ntohs(qsr->port_no);
- queue_id = ntohl(qsr->queue_id);
- if (port_no == OFPP_ALL) {
- HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
- handle_queue_stats_for_port(port, queue_id, &cbdata);
- }
- } else if (port_no < ofproto->max_ports) {
- port = get_port(ofproto, ofp_port_to_odp_port(port_no));
- if (port) {
- handle_queue_stats_for_port(port, queue_id, &cbdata);
- }
- } else {
- ofpbuf_delete(cbdata.msg);
- return ofp_mkerr(OFPET_QUEUE_OP_FAILED, OFPQOFC_BAD_PORT);
- }
- queue_tx(cbdata.msg, ofconn, ofconn->reply_counter);
-
- return 0;
-}
-
-static int
-handle_vendor_stats_request(struct ofconn *ofconn,
- struct ofp_stats_request *osr, size_t arg_size)
-{
- struct nicira_stats_msg *nsm;
- struct ofpbuf b;
- ovs_be32 vendor;
-
- if (arg_size < 4) {
- VLOG_WARN_RL(&rl, "truncated vendor stats request body");
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
-
- memcpy(&vendor, osr->body, sizeof vendor);
- if (vendor != htonl(NX_VENDOR_ID)) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
- }
-
- if (ntohs(osr->header.length) < sizeof(struct nicira_stats_msg)) {
- VLOG_WARN_RL(&rl, "truncated Nicira stats request");
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
-
- nsm = (struct nicira_stats_msg *) osr;
- b.data = nsm;
- b.size = ntohs(nsm->header.length);
- switch (ntohl(nsm->subtype)) {
- case NXST_FLOW:
- return handle_nxst_flow(ofconn, &b);
-
- case NXST_AGGREGATE:
- return handle_nxst_aggregate(ofconn, &b);
-
- default:
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
- }
-}
-
-static int
-handle_stats_request(struct ofconn *ofconn, struct ofp_header *oh)
-{
- struct ofp_stats_request *osr;
- size_t arg_size;
- int error;
-
- error = check_ofp_message_array(oh, OFPT_STATS_REQUEST, sizeof *osr,
- 1, &arg_size);
- if (error) {
- return error;
- }
- osr = (struct ofp_stats_request *) oh;
-
- switch (ntohs(osr->type)) {
- case OFPST_DESC:
- return handle_desc_stats_request(ofconn, osr);
-
- case OFPST_FLOW:
- return handle_flow_stats_request(ofconn, osr, arg_size);
-
- case OFPST_AGGREGATE:
- return handle_aggregate_stats_request(ofconn, osr, arg_size);
-
- case OFPST_TABLE:
- return handle_table_stats_request(ofconn, osr);
-
- case OFPST_PORT:
- return handle_port_stats_request(ofconn, osr, arg_size);
-
- case OFPST_QUEUE:
- return handle_queue_stats_request(ofconn, osr, arg_size);
-
- case OFPST_VENDOR:
- return handle_vendor_stats_request(ofconn, osr, arg_size);
-
- default:
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT);
- }
-}
-
-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)
-{
- long long int used = msec_from_nsec(stats->used_sec, stats->used_nsec);
- if (used > facet->used) {
- facet->used = used;
- if (used > facet->rule->used) {
- facet->rule->used = used;
- }
- netflow_flow_update_time(ofproto->netflow, &facet->nf_flow, used);
- }
-}
-
-/* Folds the statistics from 'stats' into the counters in 'facet'.
- *
- * Because of the meaning of a facet's counters, it only makes sense to do this
- * if 'stats' are not tracked in the datapath, that is, if 'stats' represents a
- * packet that was sent by hand or if it represents statistics that have been
- * cleared out of the datapath. */
-static void
-facet_update_stats(struct ofproto *ofproto, struct facet *facet,
- const struct odp_flow_stats *stats)
-{
- if (stats->n_packets) {
- facet_update_time(ofproto, facet, stats);
- facet->packet_count += stats->n_packets;
- facet->byte_count += stats->n_bytes;
- netflow_flow_update_flags(&facet->nf_flow, stats->tcp_flags);
- }
-}
-
-struct flow_mod {
- struct cls_rule cr;
- ovs_be64 cookie;
- uint16_t command;
- uint16_t idle_timeout;
- uint16_t hard_timeout;
- uint32_t buffer_id;
- uint16_t out_port;
- uint16_t flags;
- union ofp_action *actions;
- size_t 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.
- *
- * Adds the flow specified by 'ofm', which is followed by 'n_actions'
- * ofp_actions, to ofconn->ofproto's flow table. Returns 0 on success or an
- * OpenFlow error code as encoded by ofp_mkerr() on failure.
- *
- * 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id,
- * if any. */
-static int
-add_flow(struct ofconn *ofconn, struct flow_mod *fm)
-{
- struct ofproto *p = ofconn->ofproto;
- struct ofpbuf *packet;
- struct rule *rule;
- uint16_t in_port;
- int error;
-
- if (fm->flags & OFPFF_CHECK_OVERLAP
- && classifier_rule_overlaps(&p->cls, &fm->cr)) {
- return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP);
- }
-
- error = 0;
- if (fm->buffer_id != UINT32_MAX) {
- error = pktbuf_retrieve(ofconn->pktbuf, fm->buffer_id,
- &packet, &in_port);
- } else {
- packet = NULL;
- in_port = UINT16_MAX;
- }
-
- rule = rule_create(&fm->cr, fm->actions, fm->n_actions,
- fm->idle_timeout, fm->hard_timeout, fm->cookie,
- fm->flags & OFPFF_SEND_FLOW_REM);
- rule_insert(p, rule);
- if (packet) {
- rule_execute(p, rule, in_port, packet);
- }
- return error;
-}
-
-static struct rule *
-find_flow_strict(struct ofproto *p, const struct flow_mod *fm)
-{
- return rule_from_cls_rule(classifier_find_rule_exactly(&p->cls, &fm->cr));
-}
-
-static int
-send_buffered_packet(struct ofconn *ofconn,
- struct rule *rule, uint32_t buffer_id)
-{
- struct ofpbuf *packet;
- uint16_t in_port;
- int error;
-
- if (buffer_id == UINT32_MAX) {
- return 0;
- }
-
- error = pktbuf_retrieve(ofconn->pktbuf, buffer_id, &packet, &in_port);
- if (error) {
- return error;
- }
-
- rule_execute(ofconn->ofproto, rule, in_port, packet);
-
- return 0;
-}
-\f
-/* OFPFC_MODIFY and OFPFC_MODIFY_STRICT. */
-
-struct modify_flows_cbdata {
- struct ofproto *ofproto;
- const struct flow_mod *fm;
- struct rule *match;
-};
-
-static int modify_flow(struct ofproto *, const struct flow_mod *,
- struct rule *);
-
-/* Implements OFPFC_MODIFY. Returns 0 on success or an OpenFlow error code as
- * encoded by ofp_mkerr() on failure.
- *
- * 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id,
- * if any. */
-static int
-modify_flows_loose(struct ofconn *ofconn, struct flow_mod *fm)
-{
- struct ofproto *p = ofconn->ofproto;
- struct rule *match = NULL;
- struct cls_cursor cursor;
- struct rule *rule;
-
- cls_cursor_init(&cursor, &p->cls, &fm->cr);
- CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
- if (!rule_is_hidden(rule)) {
- match = rule;
- modify_flow(p, fm, rule);
- }
- }
-
- if (match) {
- /* This credits the packet to whichever flow happened to happened to
- * match last. That's weird. Maybe we should do a lookup for the
- * flow that actually matches the packet? Who knows. */
- send_buffered_packet(ofconn, match, fm->buffer_id);
- return 0;
- } else {
- return add_flow(ofconn, fm);
- }
-}
-
-/* Implements OFPFC_MODIFY_STRICT. Returns 0 on success or an OpenFlow error
- * code as encoded by ofp_mkerr() on failure.
- *
- * 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id,
- * if any. */
-static int
-modify_flow_strict(struct ofconn *ofconn, struct flow_mod *fm)
-{
- struct ofproto *p = ofconn->ofproto;
- struct rule *rule = find_flow_strict(p, fm);
- if (rule && !rule_is_hidden(rule)) {
- modify_flow(p, fm, rule);
- return send_buffered_packet(ofconn, rule, fm->buffer_id);
- } else {
- return add_flow(ofconn, fm);
- }
-}
-
-/* Implements core of OFPFC_MODIFY and OFPFC_MODIFY_STRICT where 'rule' has
- * been identified as a flow in 'p''s flow table to be modified, by changing
- * the rule's actions to match those in 'ofm' (which is followed by 'n_actions'
- * ofp_action[] structures). */
-static int
-modify_flow(struct ofproto *p, const struct flow_mod *fm, struct rule *rule)
-{
- size_t actions_len = fm->n_actions * sizeof *rule->actions;
-
- rule->flow_cookie = fm->cookie;