X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=4403a53448fd8f1708d5004312ef3b0f9f7d2451;hb=a339aa8162f4ac29784bc4e35612137f9cb1a025;hp=92c2e9ddf8c9dfe4f2d8b00442b5afc42f1fbc0e;hpb=3052b0c5e566564fc1768af33292c0acf2ed61a0;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 92c2e9dd..4403a534 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -37,6 +37,7 @@ #include "mac-learning.h" #include "netdev.h" #include "netflow.h" +#include "nx-match.h" #include "odp-util.h" #include "ofp-print.h" #include "ofp-util.h" @@ -87,7 +88,7 @@ struct rule { uint16_t idle_timeout; /* In seconds from time of last use. */ uint16_t hard_timeout; /* In seconds from time of creation. */ bool send_flow_removed; /* Send a flow removed message? */ - long long int used; /* Last-used time (0 if never used). */ + long long int used; /* Time last used; time created if not used. */ long long int created; /* Creation time. */ uint64_t packet_count; /* Number of packets received. */ uint64_t byte_count; /* Number of bytes received. */ @@ -1297,30 +1298,32 @@ ofproto_send_packet(struct ofproto *p, const struct flow *flow, return 0; } +/* Adds a flow to the OpenFlow flow table in 'p' that matches 'cls_rule' and + * performs the 'n_actions' actions in 'actions'. The new flow will not + * timeout. + * + * If cls_rule->priority is in the range of priorities supported by OpenFlow + * (0...65535, inclusive) then the flow will be visible to OpenFlow + * controllers; otherwise, it will be hidden. + * + * The caller retains ownership of 'cls_rule' and 'actions'. */ void -ofproto_add_flow(struct ofproto *p, const struct flow *flow, - uint32_t wildcards, unsigned int priority, - const union ofp_action *actions, size_t n_actions, - int idle_timeout) +ofproto_add_flow(struct ofproto *p, const struct cls_rule *cls_rule, + const union ofp_action *actions, size_t n_actions) { struct rule *rule; - rule = rule_create(p, NULL, actions, n_actions, - idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, - 0, 0, false); - cls_rule_from_flow(flow, wildcards, priority, &rule->cr); + rule = rule_create(p, NULL, actions, n_actions, 0, 0, 0, false); + rule->cr = *cls_rule; rule_insert(p, rule, NULL, 0); } void -ofproto_delete_flow(struct ofproto *ofproto, const struct flow *flow, - uint32_t wildcards, unsigned int priority) +ofproto_delete_flow(struct ofproto *ofproto, const struct cls_rule *target) { - struct cls_rule target; struct rule *rule; - cls_rule_from_flow(flow, wildcards, priority, &target); rule = rule_from_cls_rule(classifier_find_rule_exactly(&ofproto->cls, - &target)); + target)); if (rule) { rule_remove(ofproto, rule); } @@ -1857,7 +1860,7 @@ rule_create(struct ofproto *ofproto, struct rule *super, rule->n_actions = n_actions; rule->actions = xmemdup(actions, n_actions * sizeof *actions); } - netflow_flow_clear(&rule->nf_flow); + netflow_flow_init(&rule->nf_flow); netflow_flow_update_time(ofproto->netflow, &rule->nf_flow, rule->created); return rule; @@ -2057,8 +2060,9 @@ rule_create_subrule(struct ofproto *ofproto, struct rule *rule, rule->idle_timeout, rule->hard_timeout, 0, false); COVERAGE_INC(ofproto_subrule_create); - cls_rule_from_flow(flow, 0, (rule->cr.priority <= UINT16_MAX ? UINT16_MAX - : rule->cr.priority), &subrule->cr); + cls_rule_init_exact(flow, (rule->cr.priority <= UINT16_MAX ? UINT16_MAX + : rule->cr.priority), + &subrule->cr); if (classifier_insert(&ofproto->cls, &subrule->cr)) { /* Can't happen, */ @@ -2104,7 +2108,6 @@ rule_make_actions(struct ofproto *p, struct rule *rule, assert(!rule->cr.wc.wildcards); super = rule->super ? rule->super : rule; - rule->tags = 0; xlate_actions(super->actions, super->n_actions, &rule->cr.flow, p, packet, &a, &rule->tags, &rule->may_install, &rule->nf_flow.output_iface); @@ -2433,7 +2436,7 @@ struct action_xlate_ctx { /* Output. */ struct odp_actions *out; /* Datapath actions. */ - tag_type *tags; /* Tags associated with OFPP_NORMAL actions. */ + tag_type tags; /* Tags associated with OFPP_NORMAL actions. */ bool may_set_up_flow; /* True ordinarily; false if the actions must * be reassessed for every packet. */ uint16_t nf_output_iface; /* Output interface index for NetFlow. */ @@ -2553,7 +2556,7 @@ xlate_output_action__(struct action_xlate_ctx *ctx, break; case OFPP_NORMAL: if (!ctx->ofproto->ofhooks->normal_cb(&ctx->flow, ctx->packet, - ctx->out, ctx->tags, + ctx->out, &ctx->tags, &ctx->nf_output_iface, ctx->ofproto->aux)) { COVERAGE_INC(ofproto_uninstallable); @@ -2671,6 +2674,36 @@ xlate_set_queue_action(struct action_xlate_ctx *ctx, = priority; } +static void +xlate_set_dl_tci(struct action_xlate_ctx *ctx) +{ + ovs_be16 dl_vlan = ctx->flow.dl_vlan; + uint8_t dl_vlan_pcp = ctx->flow.dl_vlan_pcp; + + if (dl_vlan == htons(OFP_VLAN_NONE)) { + odp_actions_add(ctx->out, ODPAT_STRIP_VLAN); + } else { + union odp_action *oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI); + oa->dl_tci.tci = htons(ntohs(dl_vlan & htons(VLAN_VID_MASK)) + | (dl_vlan_pcp << VLAN_PCP_SHIFT) + | VLAN_CFI); + } +} + +static void +xlate_reg_move_action(struct action_xlate_ctx *ctx, + const struct nx_action_reg_move *narm) +{ + ovs_be16 old_vlan = ctx->flow.dl_vlan; + uint8_t old_pcp = ctx->flow.dl_vlan_pcp; + + nxm_execute_reg_move(narm, &ctx->flow); + + if (ctx->flow.dl_vlan != old_vlan || ctx->flow.dl_vlan_pcp != old_pcp) { + xlate_set_dl_tci(ctx); + } +} + static void xlate_nicira_action(struct action_xlate_ctx *ctx, const struct nx_action_header *nah) @@ -2709,6 +2742,15 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, 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); + 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. */ @@ -2744,23 +2786,19 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, break; case OFPAT_SET_VLAN_VID: - oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI); - oa->dl_tci.tci = ia->vlan_vid.vlan_vid; - oa->dl_tci.tci |= htons(ctx->flow.dl_vlan_pcp << VLAN_PCP_SHIFT); ctx->flow.dl_vlan = ia->vlan_vid.vlan_vid; + xlate_set_dl_tci(ctx); break; case OFPAT_SET_VLAN_PCP: - oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI); - oa->dl_tci.tci = htons(ia->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT); - oa->dl_tci.tci |= ctx->flow.dl_vlan; ctx->flow.dl_vlan_pcp = ia->vlan_pcp.vlan_pcp; + xlate_set_dl_tci(ctx); break; case OFPAT_STRIP_VLAN: - odp_actions_add(ctx->out, ODPAT_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: @@ -2826,8 +2864,8 @@ xlate_actions(const union ofp_action *in, size_t n_in, struct odp_actions *out, tag_type *tags, bool *may_set_up_flow, uint16_t *nf_output_iface) { - tag_type no_tags = 0; struct action_xlate_ctx ctx; + COVERAGE_INC(ofproto_ofp2odp); odp_actions_init(out); ctx.flow = *flow; @@ -2835,7 +2873,7 @@ xlate_actions(const union ofp_action *in, size_t n_in, ctx.ofproto = ofproto; ctx.packet = packet; ctx.out = out; - ctx.tags = tags ? tags : &no_tags; + ctx.tags = 0; ctx.may_set_up_flow = true; ctx.nf_output_iface = NF_OUT_DROP; do_xlate_actions(in, n_in, &ctx); @@ -2847,6 +2885,9 @@ xlate_actions(const union ofp_action *in, size_t n_in, 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; } @@ -2886,24 +2927,37 @@ handle_packet_out(struct ofconn *ofconn, struct ofp_header *oh) struct ofproto *p = ofconn->ofproto; struct ofp_packet_out *opo; struct ofpbuf payload, *buffer; - struct odp_actions actions; + union ofp_action *ofp_actions; + struct odp_actions odp_actions; + struct ofpbuf request; struct flow flow; - int n_actions; + 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; } - error = check_ofp_packet_out(oh, &payload, &n_actions, p->max_ports); + /* 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; } - opo = (struct ofp_packet_out *) oh; - COVERAGE_INC(ofproto_packet_out); + /* Get payload. */ if (opo->buffer_id != htonl(UINT32_MAX)) { error = pktbuf_retrieve(ofconn->pktbuf, ntohl(opo->buffer_id), &buffer, &in_port); @@ -2912,18 +2966,29 @@ handle_packet_out(struct ofconn *ofconn, struct ofp_header *oh) } payload = *buffer; } else { + payload = request; buffer = NULL; } - flow_extract(&payload, 0, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow); - error = xlate_actions((const union ofp_action *) opo->actions, n_actions, - &flow, p, &payload, &actions, NULL, NULL, 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, actions.actions, actions.n_actions, &payload); + dpif_execute(p->dpif, odp_actions.actions, odp_actions.n_actions, + &payload); } - ofpbuf_delete(buffer); - return error; +exit: + ofpbuf_delete(buffer); + return 0; } static void @@ -2984,7 +3049,7 @@ handle_port_mod(struct ofconn *ofconn, struct ofp_header *oh) } static struct ofpbuf * -make_stats_reply(ovs_be32 xid, ovs_be16 type, size_t body_len) +make_ofp_stats_reply(ovs_be32 xid, ovs_be16 type, size_t body_len) { struct ofp_stats_reply *osr; struct ofpbuf *msg; @@ -2997,25 +3062,62 @@ make_stats_reply(ovs_be32 xid, ovs_be16 type, size_t body_len) } static struct ofpbuf * -start_stats_reply(const struct ofp_stats_request *request, size_t body_len) +start_ofp_stats_reply(const struct ofp_stats_request *request, size_t body_len) { - return make_stats_reply(request->header.xid, request->type, body_len); + return make_ofp_stats_reply(request->header.xid, request->type, body_len); } static void * -append_stats_reply(size_t nbytes, struct ofconn *ofconn, struct ofpbuf **msgp) +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_stats_reply(reply->header.xid, reply->type, nbytes); + *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) @@ -3024,8 +3126,8 @@ handle_desc_stats_request(struct ofconn *ofconn, struct ofp_desc_stats *ods; struct ofpbuf *msg; - msg = start_stats_reply(request, sizeof *ods); - ods = append_stats_reply(sizeof *ods, ofconn, &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); @@ -3047,7 +3149,7 @@ handle_table_stats_request(struct ofconn *ofconn, struct rule *rule; int n_rules; - msg = start_stats_reply(request, sizeof *ots * 2); + msg = start_ofp_stats_reply(request, sizeof *ots * 2); /* Count rules other than subrules. */ n_rules = classifier_count(&p->cls); @@ -3058,7 +3160,7 @@ handle_table_stats_request(struct ofconn *ofconn, } /* Classifier table. */ - ots = append_stats_reply(sizeof *ots, ofconn, &msg); + 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 @@ -3084,7 +3186,7 @@ append_port_stat(struct ofport *port, struct ofconn *ofconn, * netdev_get_stats() will log errors. */ netdev_get_stats(port->netdev, &stats); - ops = append_stats_reply(sizeof *ops, ofconn, msgp); + 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); @@ -3116,7 +3218,7 @@ handle_port_stats_request(struct ofconn *ofconn, struct ofp_stats_request *osr, } psr = (struct ofp_port_stats_request *) osr->body; - msg = start_stats_reply(osr, sizeof *ops * 16); + 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) { @@ -3218,7 +3320,7 @@ flow_stats_cb(struct cls_rule *rule_, void *cbdata_) query_stats(cbdata->ofconn->ofproto, rule, &packet_count, &byte_count); - ofs = append_stats_reply(len, cbdata->ofconn, &cbdata->msg); + ofs = append_ofp_stats_reply(len, cbdata->ofconn, &cbdata->msg); ofs->length = htons(len); ofs->table_id = 0; ofs->pad = 0; @@ -3259,7 +3361,7 @@ handle_flow_stats_request(struct ofconn *ofconn, COVERAGE_INC(ofproto_flows_req); cbdata.ofconn = ofconn; cbdata.out_port = fsr->out_port; - cbdata.msg = start_stats_reply(osr, 1024); + cbdata.msg = start_ofp_stats_reply(osr, 1024); cls_rule_from_match(&fsr->match, 0, NXFF_OPENFLOW10, 0, &target); classifier_for_each_match(&ofconn->ofproto->cls, &target, table_id_to_include(fsr->table_id), @@ -3268,6 +3370,73 @@ handle_flow_stats_request(struct ofconn *ofconn, return 0; } +static void +nx_flow_stats_cb(struct cls_rule *rule_, void *cbdata_) +{ + struct rule *rule = rule_from_cls_rule(rule_); + struct flow_stats_cbdata *cbdata = cbdata_; + struct nx_flow_stats *nfs; + uint64_t packet_count, byte_count; + size_t act_len, start_len; + + if (rule_is_hidden(rule) || !rule_has_out_port(rule, cbdata->out_port)) { + return; + } + + query_stats(cbdata->ofconn->ofproto, rule, &packet_count, &byte_count); + + act_len = sizeof *rule->actions * rule->n_actions; + + start_len = cbdata->msg->size; + append_nxstats_reply(sizeof *nfs + NXM_MAX_LEN + act_len, + cbdata->ofconn, &cbdata->msg); + nfs = ofpbuf_put_uninit(cbdata->msg, 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(cbdata->msg, &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(cbdata->msg, rule->actions, act_len); + } + nfs->length = htons(cbdata->msg->size - start_len); +} + +static int +handle_nxst_flow(struct ofconn *ofconn, struct ofpbuf *b) +{ + struct nx_flow_stats_request *nfsr; + struct flow_stats_cbdata cbdata; + struct cls_rule target; + 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); + cbdata.ofconn = ofconn; + cbdata.out_port = nfsr->out_port; + cbdata.msg = start_nxstats_reply(&nfsr->nsm, 1024); + classifier_for_each_match(&ofconn->ofproto->cls, &target, + table_id_to_include(nfsr->table_id), + nx_flow_stats_cb, &cbdata); + queue_tx(cbdata.msg, ofconn, ofconn->reply_counter); + return 0; +} + struct flow_stats_ds_cbdata { struct ofproto *ofproto; struct ds *results; @@ -3354,7 +3523,7 @@ aggregate_stats_cb(struct cls_rule *rule_, void *cbdata_) static void query_aggregate_stats(struct ofproto *ofproto, struct cls_rule *target, - uint16_t out_port, uint8_t table_id, + ovs_be16 out_port, uint8_t table_id, struct ofp_aggregate_stats_reply *oasr) { struct aggregate_stats_cbdata cbdata; @@ -3392,14 +3561,44 @@ handle_aggregate_stats_request(struct ofconn *ofconn, cls_rule_from_match(&request->match, 0, NXFF_OPENFLOW10, 0, &target); - msg = start_stats_reply(osr, sizeof *reply); - reply = append_stats_reply(sizeof *reply, ofconn, &msg); + 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; @@ -3412,7 +3611,7 @@ put_queue_stats(struct queue_stats_cbdata *cbdata, uint32_t queue_id, { struct ofp_queue_stats *reply; - reply = append_stats_reply(sizeof *reply, cbdata->ofconn, &cbdata->msg); + 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); @@ -3468,7 +3667,7 @@ handle_queue_stats_request(struct ofconn *ofconn, COVERAGE_INC(ofproto_queue_req); cbdata.ofconn = ofconn; - cbdata.msg = start_stats_reply(osr, 128); + cbdata.msg = start_ofp_stats_reply(osr, 128); port_no = ntohs(qsr->port_no); queue_id = ntohl(qsr->queue_id); @@ -3490,6 +3689,44 @@ handle_queue_stats_request(struct ofconn *ofconn, 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) { @@ -3524,7 +3761,7 @@ handle_stats_request(struct ofconn *ofconn, struct ofp_header *oh) return handle_queue_stats_request(ofconn, osr, arg_size); case OFPST_VENDOR: - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR); + return handle_vendor_stats_request(ofconn, osr, arg_size); default: return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT); @@ -3828,7 +4065,8 @@ flow_mod_core(struct ofconn *ofconn, struct flow_mod *fm) return error; } - error = validate_actions(fm->actions, fm->n_actions, p->max_ports); + error = validate_actions(fm->actions, fm->n_actions, + &fm->cr.flow, p->max_ports); if (error) { return error; } @@ -3865,7 +4103,7 @@ flow_mod_core(struct ofconn *ofconn, struct flow_mod *fm) } static int -handle_flow_mod(struct ofconn *ofconn, struct ofp_header *oh) +handle_ofpt_flow_mod(struct ofconn *ofconn, struct ofp_header *oh) { struct ofp_match orig_match; struct ofp_flow_mod *ofm; @@ -3920,6 +4158,45 @@ handle_flow_mod(struct ofconn *ofconn, struct ofp_header *oh) return flow_mod_core(ofconn, &fm); } +static int +handle_nxt_flow_mod(struct ofconn *ofconn, struct ofp_header *oh) +{ + struct nx_flow_mod *nfm; + struct flow_mod fm; + struct ofpbuf b; + int error; + + b.data = oh; + b.size = ntohs(oh->length); + + /* Dissect the message. */ + nfm = ofpbuf_try_pull(&b, sizeof *nfm); + if (!nfm) { + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + error = nx_pull_match(&b, ntohs(nfm->match_len), ntohs(nfm->priority), + &fm.cr); + if (error) { + return error; + } + error = ofputil_pull_actions(&b, b.size, &fm.actions, &fm.n_actions); + if (error) { + return error; + } + + /* Translate the message. */ + fm.cookie = nfm->cookie; + fm.command = ntohs(nfm->command); + fm.idle_timeout = ntohs(nfm->idle_timeout); + fm.hard_timeout = ntohs(nfm->hard_timeout); + fm.buffer_id = ntohl(nfm->buffer_id); + fm.out_port = ntohs(nfm->out_port); + fm.flags = ntohs(nfm->flags); + + /* Execute the command. */ + return flow_mod_core(ofconn, &fm); +} + static int handle_tun_id_from_cookie(struct ofconn *ofconn, struct nxt_tun_id_cookie *msg) { @@ -3983,6 +4260,29 @@ handle_role_request(struct ofconn *ofconn, struct nicira_header *msg) return 0; } +static int +handle_nxt_set_flow_format(struct ofconn *ofconn, + struct nxt_set_flow_format *msg) +{ + uint32_t format; + int error; + + error = check_ofp_message(&msg->header, OFPT_VENDOR, sizeof *msg); + if (error) { + return error; + } + + format = ntohl(msg->format); + if (format == NXFF_OPENFLOW10 + || format == NXFF_TUN_ID_FROM_COOKIE + || format == NXFF_NXM) { + ofconn->flow_format = format; + return 0; + } else { + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM); + } +} + static int handle_vendor(struct ofconn *ofconn, void *msg) { @@ -4017,6 +4317,12 @@ handle_vendor(struct ofconn *ofconn, void *msg) case NXT_ROLE_REQUEST: return handle_role_request(ofconn, msg); + + case NXT_SET_FLOW_FORMAT: + return handle_nxt_set_flow_format(ofconn, msg); + + case NXT_FLOW_MOD: + return handle_nxt_flow_mod(ofconn, &ovh->header); } return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE); @@ -4072,7 +4378,7 @@ handle_openflow(struct ofconn *ofconn, struct ofpbuf *ofp_msg) break; case OFPT_FLOW_MOD: - error = handle_flow_mod(ofconn, ofp_msg->data); + error = handle_ofpt_flow_mod(ofconn, ofp_msg->data); break; case OFPT_STATS_REQUEST: @@ -4274,7 +4580,7 @@ ofproto_update_used(struct ofproto *p) struct flow flow; odp_flow_key_to_flow(&f->key, &flow); - cls_rule_from_flow(&flow, 0, UINT16_MAX, &target); + cls_rule_init_exact(&flow, UINT16_MAX, &target); rule = rule_from_cls_rule(classifier_find_rule_exactly(&p->cls, &target)); @@ -4525,8 +4831,7 @@ revalidate_rule(struct ofproto *p, struct rule *rule) rule->super = super; rule->hard_timeout = super->hard_timeout; rule->idle_timeout = super->idle_timeout; - rule->created = super->created; - rule->used = 0; + rule->created = rule->used = super->created; } } @@ -4535,8 +4840,8 @@ revalidate_rule(struct ofproto *p, struct rule *rule) } static struct ofpbuf * -compose_flow_removed(struct ofconn *ofconn, const struct rule *rule, - uint8_t reason) +compose_ofp_flow_removed(struct ofconn *ofconn, const struct rule *rule, + uint8_t reason) { struct ofp_flow_removed *ofr; struct ofpbuf *buf; @@ -4555,6 +4860,29 @@ compose_flow_removed(struct ofconn *ofconn, const struct rule *rule, return buf; } +static struct ofpbuf * +compose_nx_flow_removed(const struct rule *rule, uint8_t reason) +{ + struct nx_flow_removed *nfr; + struct ofpbuf *buf; + int match_len; + + nfr = make_nxmsg(sizeof *nfr, NXT_FLOW_REMOVED, &buf); + + match_len = nx_put_match(buf, &rule->cr); + + nfr->cookie = rule->flow_cookie; + nfr->priority = htons(rule->cr.priority); + nfr->reason = reason; + calc_flow_duration(rule->created, &nfr->duration_sec, &nfr->duration_nsec); + nfr->idle_timeout = htons(rule->idle_timeout); + nfr->match_len = htons(match_len); + nfr->packet_count = htonll(rule->packet_count); + nfr->byte_count = htonll(rule->byte_count); + + return buf; +} + static void send_flow_removed(struct ofproto *p, struct rule *rule, uint8_t reason) { @@ -4572,7 +4900,9 @@ send_flow_removed(struct ofproto *p, struct rule *rule, uint8_t reason) continue; } - msg = compose_flow_removed(ofconn, rule, reason); + msg = (ofconn->flow_format == NXFF_NXM + ? compose_nx_flow_removed(rule, reason) + : compose_ofp_flow_removed(ofconn, rule, reason)); /* Account flow expirations under ofconn->reply_counter, the counter * for replies to OpenFlow requests. That works because preventing