X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=ba9ef1903db12d59260fbd2a170010e6bfaca885;hb=f7de2cdffcadaca5f62003f9c115052aa295aa70;hp=1a653ec4113bf46fd04675747c486ad40c6c5452;hpb=28998b228c837c5c447ef01491182b2e3a645294;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 1a653ec4..ba9ef190 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -108,6 +108,9 @@ struct rule { struct list list; /* OpenFlow actions. + * + * 'n_actions' is the number of elements in the 'actions' array. A single + * action may take up more more than one element's worth of space. * * A subrule has no actions (it uses the super-rule's actions). */ int n_actions; @@ -216,6 +219,7 @@ struct ofproto { bool need_revalidate; long long int next_expiration; struct tag_set revalidate_set; + bool tun_id_from_cookie; /* OpenFlow connections. */ struct list all_conns; @@ -714,8 +718,9 @@ ofproto_destroy(struct ofproto *p) return; } - /* Destroy fail-open early, because it touches the classifier. */ + /* Destroy fail-open and in-band early, since they touch the classifier. */ ofproto_set_failure(p, false); + ofproto_set_in_band(p, false); ofproto_flush_flows(p); classifier_destroy(&p->cls); @@ -733,7 +738,6 @@ ofproto_destroy(struct ofproto *p) shash_destroy(&p->port_by_name); switch_status_destroy(p->switch_status); - in_band_destroy(p->in_band); discovery_destroy(p->discovery); pinsched_destroy(p->miss_sched); pinsched_destroy(p->action_sched); @@ -1026,7 +1030,7 @@ ofproto_add_flow(struct ofproto *p, rule = rule_create(p, NULL, actions, n_actions, idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, 0, 0, false); - cls_rule_from_flow(&rule->cr, flow, wildcards, priority); + cls_rule_from_flow(flow, wildcards, priority, &rule->cr); rule_insert(p, rule, NULL, 0); } @@ -1580,7 +1584,7 @@ rule_insert(struct ofproto *p, struct rule *rule, struct ofpbuf *packet, /* Send the packet and credit it to the rule. */ if (packet) { flow_t flow; - flow_extract(packet, in_port, &flow); + flow_extract(packet, 0, in_port, &flow); rule_execute(p, rule, packet, &flow); } @@ -1607,9 +1611,8 @@ 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(&subrule->cr, flow, 0, - (rule->cr.priority <= UINT16_MAX ? UINT16_MAX - : rule->cr.priority)); + cls_rule_from_flow(flow, 0, (rule->cr.priority <= UINT16_MAX ? UINT16_MAX + : rule->cr.priority), &subrule->cr); classifier_insert_exact(&ofproto->cls, &subrule->cr); return subrule; @@ -1666,6 +1669,7 @@ do_put_flow(struct ofproto *ofproto, struct rule *rule, int flags, put->flow.key = rule->cr.flow; put->flow.actions = rule->odp_actions; put->flow.n_actions = rule->n_odp_actions; + put->flow.flags = 0; put->flags = flags; return dpif_flow_put(ofproto->dpif, put); } @@ -1761,6 +1765,7 @@ rule_uninstall(struct ofproto *p, struct rule *rule) odp_flow.key = rule->cr.flow; odp_flow.actions = NULL; odp_flow.n_actions = 0; + odp_flow.flags = 0; if (!dpif_flow_del(p->dpif, &odp_flow)) { update_stats(p, rule, &odp_flow.stats); } @@ -1996,7 +2001,7 @@ add_controller_action(struct odp_actions *actions, struct action_xlate_ctx { /* Input. */ - const flow_t *flow; /* Flow to which these actions correspond. */ + flow_t flow; /* Flow to which these actions correspond. */ int recurse; /* Recursion level, via xlate_table_action. */ struct ofproto *ofproto; const struct ofpbuf *packet; /* The packet corresponding to 'flow', or a @@ -2059,13 +2064,17 @@ static void xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port) { if (!ctx->recurse) { + uint16_t old_in_port; struct rule *rule; - flow_t flow; - flow = *ctx->flow; - flow.in_port = in_port; + /* Look up a flow with 'in_port' as the input port. Then restore the + * original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will + * have surprising behavior). */ + old_in_port = ctx->flow.in_port; + ctx->flow.in_port = in_port; + rule = lookup_valid_rule(ctx->ofproto, &ctx->flow); + ctx->flow.in_port = old_in_port; - rule = lookup_valid_rule(ctx->ofproto, &flow); if (rule) { if (rule->super) { rule = rule->super; @@ -2089,13 +2098,13 @@ xlate_output_action(struct action_xlate_ctx *ctx, switch (ntohs(oao->port)) { case OFPP_IN_PORT: - add_output_action(ctx, ctx->flow->in_port); + add_output_action(ctx, ctx->flow.in_port); break; case OFPP_TABLE: - xlate_table_action(ctx, ctx->flow->in_port); + xlate_table_action(ctx, ctx->flow.in_port); break; case OFPP_NORMAL: - if (!ctx->ofproto->ofhooks->normal_cb(ctx->flow, ctx->packet, + if (!ctx->ofproto->ofhooks->normal_cb(&ctx->flow, ctx->packet, ctx->out, ctx->tags, &ctx->nf_output_iface, ctx->ofproto->aux)) { @@ -2118,7 +2127,7 @@ xlate_output_action(struct action_xlate_ctx *ctx, break; default: odp_port = ofp_port_to_odp_port(ntohs(oao->port)); - if (odp_port != ctx->flow->in_port) { + if (odp_port != ctx->flow.in_port) { add_output_action(ctx, odp_port); } break; @@ -2139,6 +2148,8 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, const struct nx_action_header *nah) { const struct nx_action_resubmit *nar; + const struct nx_action_set_tunnel *nast; + union odp_action *oa; int subtype = ntohs(nah->subtype); assert(nah->vendor == htonl(NX_VENDOR_ID)); @@ -2148,6 +2159,15 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, xlate_table_action(ctx, ofp_port_to_odp_port(ntohs(nar->in_port))); break; + 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; + + /* If you add a new action here that modifies flow data, don't forget to + * update the flow key in ctx->flow in the same key. */ + default: VLOG_DBG_RL(&rl, "unknown Nicira action type %"PRIu16, subtype); break; @@ -2162,9 +2182,9 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, const union ofp_action *ia; const struct ofport *port; - port = port_array_get(&ctx->ofproto->ports, ctx->flow->in_port); + port = port_array_get(&ctx->ofproto->ports, 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, stp_eth_addr) + port->opp.config & (eth_addr_equals(ctx->flow.dl_dst, stp_eth_addr) ? OFPPC_NO_RECV_STP : OFPPC_NO_RECV)) { /* Drop this flow. */ return; @@ -2181,53 +2201,59 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, case OFPAT_SET_VLAN_VID: oa = odp_actions_add(ctx->out, ODPAT_SET_VLAN_VID); - oa->vlan_vid.vlan_vid = ia->vlan_vid.vlan_vid; + ctx->flow.dl_vlan = oa->vlan_vid.vlan_vid = ia->vlan_vid.vlan_vid; break; case OFPAT_SET_VLAN_PCP: oa = odp_actions_add(ctx->out, ODPAT_SET_VLAN_PCP); - oa->vlan_pcp.vlan_pcp = ia->vlan_pcp.vlan_pcp; + ctx->flow.dl_vlan_pcp = oa->vlan_pcp.vlan_pcp = ia->vlan_pcp.vlan_pcp; break; case OFPAT_STRIP_VLAN: odp_actions_add(ctx->out, ODPAT_STRIP_VLAN); + ctx->flow.dl_vlan = OFP_VLAN_NONE; + ctx->flow.dl_vlan_pcp = 0; 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); - oa->nw_addr.nw_addr = ia->nw_addr.nw_addr; + 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); - oa->nw_addr.nw_addr = ia->nw_addr.nw_addr; + 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); - oa->nw_tos.nw_tos = ia->nw_tos.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); - oa->tp_port.tp_port = ia->tp_port.tp_port; + 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); - oa->tp_port.tp_port = ia->tp_port.tp_port; + ctx->flow.tp_dst = oa->tp_port.tp_port = ia->tp_port.tp_port; break; case OFPAT_VENDOR: @@ -2252,7 +2278,7 @@ xlate_actions(const union ofp_action *in, size_t n_in, struct action_xlate_ctx ctx; COVERAGE_INC(ofproto_ofp2odp); odp_actions_init(out); - ctx.flow = flow; + ctx.flow = *flow; ctx.recurse = 0; ctx.ofproto = ofproto; ctx.packet = packet; @@ -2311,7 +2337,7 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn, buffer = NULL; } - flow_extract(&payload, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow); + 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); if (error) { @@ -2480,7 +2506,8 @@ handle_table_stats_request(struct ofproto *p, struct ofconn *ofconn, memset(ots, 0, sizeof *ots); ots->table_id = TABLEID_CLASSIFIER; strcpy(ots->name, "classifier"); - ots->wildcards = htonl(OFPFW_ALL); + ots->wildcards = p->tun_id_from_cookie ? htonl(OVSFW_ALL) + : htonl(OFPFW_ALL); ots->max_entries = htonl(65536); ots->active_count = htonl(n_wild); ots->lookup_count = htonll(0); /* XXX */ @@ -2638,7 +2665,8 @@ flow_stats_cb(struct cls_rule *rule_, void *cbdata_) ofs->length = htons(len); ofs->table_id = rule->cr.wc.wildcards ? TABLEID_CLASSIFIER : TABLEID_HASH; ofs->pad = 0; - flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofs->match); + flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, + cbdata->ofproto->tun_id_from_cookie, &ofs->match); ofs->duration_sec = htonl(sec); ofs->duration_nsec = htonl(msec * 1000000); ofs->cookie = rule->flow_cookie; @@ -2679,7 +2707,7 @@ handle_flow_stats_request(struct ofproto *p, struct ofconn *ofconn, cbdata.ofconn = ofconn; cbdata.out_port = fsr->out_port; cbdata.msg = start_stats_reply(osr, 1024); - cls_rule_from_match(&target, &fsr->match, 0); + cls_rule_from_match(&fsr->match, 0, false, 0, &target); classifier_for_each_match(&p->cls, &target, table_id_to_include(fsr->table_id), flow_stats_cb, &cbdata); @@ -2708,7 +2736,8 @@ flow_stats_ds_cb(struct cls_rule *rule_, void *cbdata_) } query_stats(cbdata->ofproto, rule, &packet_count, &byte_count); - flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &match); + flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, + cbdata->ofproto->tun_id_from_cookie, &match); ds_put_format(results, "duration=%llds, ", (time_msec() - rule->created) / 1000); @@ -2730,12 +2759,12 @@ ofproto_get_all_flows(struct ofproto *p, struct ds *results) struct flow_stats_ds_cbdata cbdata; memset(&match, 0, sizeof match); - match.wildcards = htonl(OFPFW_ALL); + match.wildcards = htonl(OVSFW_ALL); cbdata.ofproto = p; cbdata.results = results; - cls_rule_from_match(&target, &match, 0); + cls_rule_from_match(&match, 0, false, 0, &target); classifier_for_each_match(&p->cls, &target, CLS_INC_ALL, flow_stats_ds_cb, &cbdata); } @@ -2788,7 +2817,7 @@ handle_aggregate_stats_request(struct ofproto *p, struct ofconn *ofconn, cbdata.packet_count = 0; cbdata.byte_count = 0; cbdata.n_flows = 0; - cls_rule_from_match(&target, &asr->match, 0); + cls_rule_from_match(&asr->match, 0, false, 0, &target); classifier_for_each_match(&p->cls, &target, table_id_to_include(asr->table_id), aggregate_stats_cb, &cbdata); @@ -2874,9 +2903,18 @@ update_stats(struct ofproto *ofproto, struct rule *rule, } } +/* 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 'p''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 ofproto *p, struct ofconn *ofconn, - struct ofp_flow_mod *ofm, size_t n_actions) + const struct ofp_flow_mod *ofm, size_t n_actions) { struct ofpbuf *packet; struct rule *rule; @@ -2887,7 +2925,8 @@ add_flow(struct ofproto *p, struct ofconn *ofconn, flow_t flow; uint32_t wildcards; - flow_from_match(&flow, &wildcards, &ofm->match); + flow_from_match(&ofm->match, p->tun_id_from_cookie, ofm->cookie, + &flow, &wildcards); if (classifier_rule_overlaps(&p->cls, &flow, wildcards, ntohs(ofm->priority))) { return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP); @@ -2898,7 +2937,8 @@ add_flow(struct ofproto *p, struct ofconn *ofconn, n_actions, ntohs(ofm->idle_timeout), ntohs(ofm->hard_timeout), ofm->cookie, ofm->flags & htons(OFPFF_SEND_FLOW_REM)); - cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority)); + cls_rule_from_match(&ofm->match, ntohs(ofm->priority), + p->tun_id_from_cookie, ofm->cookie, &rule->cr); error = 0; if (ofm->buffer_id != htonl(UINT32_MAX)) { @@ -2914,112 +2954,227 @@ add_flow(struct ofproto *p, struct ofconn *ofconn, return error; } -static int -modify_flow(struct ofproto *p, const struct ofp_flow_mod *ofm, - size_t n_actions, uint16_t command, struct rule *rule) +static struct rule * +find_flow_strict(struct ofproto *p, const struct ofp_flow_mod *ofm) { - if (rule_is_hidden(rule)) { - return 0; - } - - if (command == OFPFC_DELETE) { - long long int now = time_msec(); - send_flow_removed(p, rule, now, OFPRR_DELETE); - rule_remove(p, rule); - } else { - size_t actions_len = n_actions * sizeof *rule->actions; - - if (n_actions == rule->n_actions - && !memcmp(ofm->actions, rule->actions, actions_len)) - { - return 0; - } - - free(rule->actions); - rule->actions = xmemdup(ofm->actions, actions_len); - rule->n_actions = n_actions; - rule->flow_cookie = ofm->cookie; - - if (rule->cr.wc.wildcards) { - COVERAGE_INC(ofproto_mod_wc_flow); - p->need_revalidate = true; - } else { - rule_update_actions(p, rule); - } - } + uint32_t wildcards; + flow_t flow; - return 0; + flow_from_match(&ofm->match, p->tun_id_from_cookie, ofm->cookie, + &flow, &wildcards); + return rule_from_cls_rule(classifier_find_rule_exactly( + &p->cls, &flow, wildcards, + ntohs(ofm->priority))); } static int -modify_flows_strict(struct ofproto *p, const struct ofp_flow_mod *ofm, - size_t n_actions, uint16_t command) +send_buffered_packet(struct ofproto *ofproto, struct ofconn *ofconn, + struct rule *rule, const struct ofp_flow_mod *ofm) { - struct rule *rule; - uint32_t wildcards; + struct ofpbuf *packet; + uint16_t in_port; flow_t flow; + int error; - flow_from_match(&flow, &wildcards, &ofm->match); - rule = rule_from_cls_rule(classifier_find_rule_exactly( - &p->cls, &flow, wildcards, - ntohs(ofm->priority))); - - if (rule) { - if (command == OFPFC_DELETE - && ofm->out_port != htons(OFPP_NONE) - && !rule_has_out_port(rule, ofm->out_port)) { - return 0; - } + if (ofm->buffer_id == htonl(UINT32_MAX)) { + return 0; + } - modify_flow(p, ofm, n_actions, command, rule); + error = pktbuf_retrieve(ofconn->pktbuf, ntohl(ofm->buffer_id), + &packet, &in_port); + if (error) { + return error; } + + flow_extract(packet, 0, in_port, &flow); + rule_execute(ofproto, rule, packet, &flow); + ofpbuf_delete(packet); + return 0; } + +/* OFPFC_MODIFY and OFPFC_MODIFY_STRICT. */ struct modify_flows_cbdata { struct ofproto *ofproto; const struct ofp_flow_mod *ofm; - uint16_t out_port; size_t n_actions; - uint16_t command; + struct rule *match; }; +static int modify_flow(struct ofproto *, const struct ofp_flow_mod *, + size_t n_actions, struct rule *); +static void modify_flows_cb(struct cls_rule *, void *cbdata_); + +/* 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 ofproto *p, struct ofconn *ofconn, + const struct ofp_flow_mod *ofm, size_t n_actions) +{ + struct modify_flows_cbdata cbdata; + struct cls_rule target; + + cbdata.ofproto = p; + cbdata.ofm = ofm; + cbdata.n_actions = n_actions; + cbdata.match = NULL; + + cls_rule_from_match(&ofm->match, 0, p->tun_id_from_cookie, ofm->cookie, + &target); + + classifier_for_each_match(&p->cls, &target, CLS_INC_ALL, + modify_flows_cb, &cbdata); + if (cbdata.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(p, ofconn, cbdata.match, ofm); + return 0; + } else { + return add_flow(p, ofconn, ofm, n_actions); + } +} + +/* 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 ofproto *p, struct ofconn *ofconn, + struct ofp_flow_mod *ofm, size_t n_actions) +{ + struct rule *rule = find_flow_strict(p, ofm); + if (rule && !rule_is_hidden(rule)) { + modify_flow(p, ofm, n_actions, rule); + return send_buffered_packet(p, ofconn, rule, ofm); + } else { + return add_flow(p, ofconn, ofm, n_actions); + } +} + +/* Callback for modify_flows_loose(). */ static void modify_flows_cb(struct cls_rule *rule_, void *cbdata_) { struct rule *rule = rule_from_cls_rule(rule_); struct modify_flows_cbdata *cbdata = cbdata_; - if (cbdata->out_port != htons(OFPP_NONE) - && !rule_has_out_port(rule, cbdata->out_port)) { - return; + if (!rule_is_hidden(rule)) { + cbdata->match = rule; + modify_flow(cbdata->ofproto, cbdata->ofm, cbdata->n_actions, rule); } - - modify_flow(cbdata->ofproto, cbdata->ofm, cbdata->n_actions, - cbdata->command, rule); } +/* 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_flows_loose(struct ofproto *p, const struct ofp_flow_mod *ofm, - size_t n_actions, uint16_t command) +modify_flow(struct ofproto *p, const struct ofp_flow_mod *ofm, + size_t n_actions, struct rule *rule) { - struct modify_flows_cbdata cbdata; + size_t actions_len = n_actions * sizeof *rule->actions; + + rule->flow_cookie = ofm->cookie; + + /* If the actions are the same, do nothing. */ + if (n_actions == rule->n_actions + && !memcmp(ofm->actions, rule->actions, actions_len)) + { + return 0; + } + + /* Replace actions. */ + free(rule->actions); + rule->actions = xmemdup(ofm->actions, actions_len); + rule->n_actions = n_actions; + + /* Make sure that the datapath gets updated properly. */ + if (rule->cr.wc.wildcards) { + COVERAGE_INC(ofproto_mod_wc_flow); + p->need_revalidate = true; + } else { + rule_update_actions(p, rule); + } + + return 0; +} + +/* OFPFC_DELETE implementation. */ + +struct delete_flows_cbdata { + struct ofproto *ofproto; + uint16_t out_port; +}; + +static void delete_flows_cb(struct cls_rule *, void *cbdata_); +static void delete_flow(struct ofproto *, struct rule *, uint16_t out_port); + +/* Implements OFPFC_DELETE. */ +static void +delete_flows_loose(struct ofproto *p, const struct ofp_flow_mod *ofm) +{ + struct delete_flows_cbdata cbdata; struct cls_rule target; cbdata.ofproto = p; - cbdata.ofm = ofm; - cbdata.out_port = (command == OFPFC_DELETE ? ofm->out_port - : htons(OFPP_NONE)); - cbdata.n_actions = n_actions; - cbdata.command = command; + cbdata.out_port = ofm->out_port; - cls_rule_from_match(&target, &ofm->match, 0); + cls_rule_from_match(&ofm->match, 0, p->tun_id_from_cookie, ofm->cookie, + &target); classifier_for_each_match(&p->cls, &target, CLS_INC_ALL, - modify_flows_cb, &cbdata); - return 0; + delete_flows_cb, &cbdata); +} + +/* Implements OFPFC_DELETE_STRICT. */ +static void +delete_flow_strict(struct ofproto *p, struct ofp_flow_mod *ofm) +{ + struct rule *rule = find_flow_strict(p, ofm); + if (rule) { + delete_flow(p, rule, ofm->out_port); + } +} + +/* Callback for delete_flows_loose(). */ +static void +delete_flows_cb(struct cls_rule *rule_, void *cbdata_) +{ + struct rule *rule = rule_from_cls_rule(rule_); + struct delete_flows_cbdata *cbdata = cbdata_; + + delete_flow(cbdata->ofproto, rule, cbdata->out_port); } +/* Implements core of OFPFC_DELETE and OFPFC_DELETE_STRICT where 'rule' has + * been identified as a flow to delete from 'p''s flow table, by deleting the + * flow and sending out a OFPT_FLOW_REMOVED message to any interested + * controller. + * + * Will not delete 'rule' if it is hidden. Will delete 'rule' only if + * 'out_port' is htons(OFPP_NONE) or if 'rule' actually outputs to the + * specified 'out_port'. */ +static void +delete_flow(struct ofproto *p, struct rule *rule, uint16_t out_port) +{ + if (rule_is_hidden(rule)) { + return; + } + + if (out_port != htons(OFPP_NONE) && !rule_has_out_port(rule, out_port)) { + return; + } + + send_flow_removed(p, rule, time_msec(), OFPRR_DELETE); + rule_remove(p, rule); +} + static int handle_flow_mod(struct ofproto *p, struct ofconn *ofconn, struct ofp_flow_mod *ofm) @@ -3057,22 +3212,38 @@ handle_flow_mod(struct ofproto *p, struct ofconn *ofconn, return add_flow(p, ofconn, ofm, n_actions); case OFPFC_MODIFY: - return modify_flows_loose(p, ofm, n_actions, OFPFC_MODIFY); + return modify_flows_loose(p, ofconn, ofm, n_actions); case OFPFC_MODIFY_STRICT: - return modify_flows_strict(p, ofm, n_actions, OFPFC_MODIFY); + return modify_flow_strict(p, ofconn, ofm, n_actions); case OFPFC_DELETE: - return modify_flows_loose(p, ofm, n_actions, OFPFC_DELETE); + delete_flows_loose(p, ofm); + return 0; case OFPFC_DELETE_STRICT: - return modify_flows_strict(p, ofm, n_actions, OFPFC_DELETE); + delete_flow_strict(p, ofm); + return 0; default: return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_COMMAND); } } +static int +handle_tun_id_from_cookie(struct ofproto *p, struct nxt_tun_id_cookie *msg) +{ + int error; + + error = check_ofp_message(&msg->header, OFPT_VENDOR, sizeof *msg); + if (error) { + return error; + } + + p->tun_id_from_cookie = !!msg->set; + return 0; +} + static int handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg) { @@ -3080,12 +3251,18 @@ handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg) struct nicira_header *nh; if (ntohs(ovh->header.length) < sizeof(struct ofp_vendor_header)) { + VLOG_WARN_RL(&rl, "received vendor message of length %zu " + "(expected at least %zu)", + ntohs(ovh->header.length), sizeof(struct ofp_vendor_header)); return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } if (ovh->vendor != htonl(NX_VENDOR_ID)) { return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR); } if (ntohs(ovh->header.length) < sizeof(struct nicira_header)) { + VLOG_WARN_RL(&rl, "received Nicira vendor message of length %zu " + "(expected at least %zu)", + ntohs(ovh->header.length), sizeof(struct nicira_header)); return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } @@ -3094,6 +3271,9 @@ handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg) case NXT_STATUS_REQUEST: return switch_status_handle_request(p->switch_status, ofconn->rconn, msg); + + case NXT_TUN_ID_FROM_COOKIE: + return handle_tun_id_from_cookie(p, msg); } return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE); @@ -3191,7 +3371,7 @@ handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet) payload.data = msg + 1; payload.size = msg->length - sizeof *msg; - flow_extract(&payload, msg->port, &flow); + flow_extract(&payload, msg->arg, msg->port, &flow); /* Check with in-band control to see if this packet should be sent * to the local port regardless of the flow table. */ @@ -3331,16 +3511,18 @@ revalidate_rule(struct ofproto *p, struct rule *rule) } static struct ofpbuf * -compose_flow_removed(const struct rule *rule, long long int now, uint8_t reason) +compose_flow_removed(struct ofproto *p, const struct rule *rule, + long long int now, uint8_t reason) { struct ofp_flow_removed *ofr; struct ofpbuf *buf; - long long int tdiff = time_msec() - rule->created; + long long int tdiff = now - rule->created; uint32_t sec = tdiff / 1000; uint32_t msec = tdiff - (sec * 1000); ofr = make_openflow(sizeof *ofr, OFPT_FLOW_REMOVED, &buf); - flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofr->match); + flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, p->tun_id_from_cookie, + &ofr->match); ofr->cookie = rule->flow_cookie; ofr->priority = htons(rule->cr.priority); ofr->reason = reason; @@ -3385,7 +3567,7 @@ send_flow_removed(struct ofproto *p, struct rule *rule, if (prev) { queue_tx(ofpbuf_clone(buf), prev, prev->reply_counter); } else { - buf = compose_flow_removed(rule, now, reason); + buf = compose_flow_removed(p, rule, now, reason); } prev = ofconn; } @@ -3568,7 +3750,7 @@ send_packet_in_miss(struct ofpbuf *packet, void *p_) ? pktbuf_get_null() : pktbuf_save(pb, &payload, msg->port)); int send_len = (buffer_id != UINT32_MAX ? ofconn->miss_send_len - : UINT32_MAX); + : INT_MAX); do_send_packet_in(ofconn, buffer_id, packet, send_len); } }