X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=e571bd4e2314d2113213ca83c769c7bb16e27334;hb=e4af561537cfea7d35d2075596b4474847876794;hp=a466c9caec46dbecc7fffc102e6500275ef28cba;hpb=7d674866d2c95d9027fc2e64d1acc2044e2c004a;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index a466c9ca..e571bd4e 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -50,7 +50,6 @@ #include "rconn.h" #include "shash.h" #include "status.h" -#include "stp.h" #include "stream-ssl.h" #include "svec.h" #include "tag.h" @@ -86,7 +85,7 @@ static int xlate_actions(const union ofp_action *in, size_t n_in, struct rule { struct cls_rule cr; - uint64_t flow_cookie; /* Controller-issued identifier. + uint64_t flow_cookie; /* Controller-issued identifier. (Kept in network-byte order.) */ uint16_t idle_timeout; /* In seconds from time of last use. */ uint16_t hard_timeout; /* In seconds from time of creation. */ @@ -900,18 +899,6 @@ ofproto_set_sflow(struct ofproto *ofproto, } } -int -ofproto_set_stp(struct ofproto *ofproto OVS_UNUSED, bool enable_stp) -{ - /* XXX */ - if (enable_stp) { - VLOG_WARN("STP is not yet implemented"); - return EINVAL; - } else { - return 0; - } -} - uint64_t ofproto_get_datapath_id(const struct ofproto *ofproto) { @@ -1084,7 +1071,6 @@ ofproto_run1(struct ofproto *p) for (i = 0; i < 50; i++) { struct ofpbuf *buf; - int error; error = dpif_recv(p->dpif, &buf); if (error) { @@ -1135,7 +1121,6 @@ ofproto_run1(struct ofproto *p) retval = pvconn_accept(ofservice->pvconn, OFP_VERSION, &vconn); if (!retval) { - struct ofconn *ofconn; struct rconn *rconn; char *name; @@ -1304,7 +1289,7 @@ ofproto_add_flow(struct ofproto *p, { struct rule *rule; rule = rule_create(p, NULL, actions, n_actions, - idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, + idle_timeout >= 0 ? idle_timeout : 5 /* XXX */, 0, 0, false); cls_rule_from_flow(flow, wildcards, priority, &rule->cr); rule_insert(p, rule, NULL, 0); @@ -1940,8 +1925,44 @@ rule_has_out_port(const struct rule *rule, uint16_t out_port) return false; } +/* Executes, within 'ofproto', the 'n_actions' actions in 'actions' on + * 'packet', which arrived on 'in_port'. + * + * Takes ownership of 'packet'. */ +static bool +execute_odp_actions(struct ofproto *ofproto, uint16_t in_port, + const union odp_action *actions, size_t n_actions, + struct ofpbuf *packet) +{ + if (n_actions == 1 && actions[0].type == ODPAT_CONTROLLER) { + /* 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; + + 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->reserved = 0; + msg->arg = actions[0].controller.arg; + + send_packet_in(ofproto, packet); + + return true; + } else { + int error; + + error = dpif_execute(ofproto->dpif, in_port, + actions, n_actions, packet); + ofpbuf_delete(packet); + return !error; + } +} + /* Executes the actions indicated by 'rule' on 'packet', which is in flow - * 'flow' and is considered to have arrived on ODP port 'in_port'. + * 'flow' and is considered to have arrived on ODP port 'in_port'. 'packet' + * must have at least sizeof(struct ofp_packet_in) bytes of headroom. * * The flow that 'packet' actually contains does not need to actually match * 'rule'; the actions in 'rule' will be applied to it either way. Likewise, @@ -1953,15 +1974,20 @@ rule_has_out_port(const struct rule *rule, uint16_t out_port) * 'packet' using rule_make_actions(). If 'rule' is a wildcard rule, or if * 'rule' is an exact-match rule but 'flow' is not the rule's flow, then this * function will compose a set of ODP actions based on 'rule''s OpenFlow - * actions and apply them to 'packet'. */ + * actions and apply them to 'packet'. + * + * Takes ownership of 'packet'. */ static void rule_execute(struct ofproto *ofproto, struct rule *rule, struct ofpbuf *packet, const flow_t *flow) { const union odp_action *actions; + struct odp_flow_stats stats; size_t n_actions; struct odp_actions a; + assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in)); + /* Grab or compose the ODP actions. * * The special case for an exact-match 'rule' where 'flow' is not the @@ -1972,6 +1998,7 @@ rule_execute(struct ofproto *ofproto, struct rule *rule, struct rule *super = rule->super ? rule->super : rule; if (xlate_actions(super->actions, super->n_actions, flow, ofproto, packet, &a, NULL, 0, NULL)) { + ofpbuf_delete(packet); return; } actions = a.actions; @@ -1982,16 +2009,21 @@ rule_execute(struct ofproto *ofproto, struct rule *rule, } /* Execute the ODP actions. */ - if (!dpif_execute(ofproto->dpif, flow->in_port, - actions, n_actions, packet)) { - struct odp_flow_stats stats; - flow_extract_stats(flow, packet, &stats); + flow_extract_stats(flow, packet, &stats); + if (execute_odp_actions(ofproto, flow->in_port, + actions, n_actions, packet)) { update_stats(ofproto, rule, &stats); rule->used = time_msec(); netflow_flow_update_time(ofproto->netflow, &rule->nf_flow, rule->used); } } +/* Inserts 'rule' into 'p''s flow table. + * + * If 'packet' is nonnull, takes ownership of 'packet', executes 'rule''s + * actions on it and credits the statistics for sending the packet to 'rule'. + * 'packet' must have at least sizeof(struct ofp_packet_in) bytes of + * headroom. */ static void rule_insert(struct ofproto *p, struct rule *rule, struct ofpbuf *packet, uint16_t in_port) @@ -2427,6 +2459,10 @@ struct action_xlate_ctx { uint16_t nf_output_iface; /* Output interface index for NetFlow. */ }; +/* Maximum depth of flow table recursion (due to NXAST_RESUBMIT actions) in a + * flow translation. */ +#define MAX_RESUBMIT_RECURSION 8 + static void do_xlate_actions(const union ofp_action *in, size_t n_in, struct action_xlate_ctx *ctx); @@ -2474,7 +2510,7 @@ lookup_valid_rule(struct ofproto *ofproto, const flow_t *flow) static void xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port) { - if (!ctx->recurse) { + if (ctx->recurse < MAX_RESUBMIT_RECURSION) { uint16_t old_in_port; struct rule *rule; @@ -2495,6 +2531,11 @@ xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port) do_xlate_actions(rule->actions, rule->n_actions, ctx); ctx->recurse--; } + } else { + 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); } } @@ -2635,6 +2676,12 @@ xlate_nicira_action(struct action_xlate_ctx *ctx, 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; + /* 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. */ @@ -2654,7 +2701,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in, 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, eth_addr_stp) ? OFPPC_NO_RECV_STP : OFPPC_NO_RECV)) { /* Drop this flow. */ return; @@ -2776,6 +2823,7 @@ xlate_actions(const union ofp_action *in, size_t n_in, *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); } @@ -3026,14 +3074,14 @@ handle_table_stats_request(struct ofproto *p, struct ofconn *ofconn, } static void -append_port_stat(struct ofport *port, uint16_t port_no, struct ofconn *ofconn, +append_port_stat(struct ofport *port, uint16_t port_no, 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 + /* 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); @@ -3072,7 +3120,7 @@ handle_port_stats_request(struct ofproto *p, struct ofconn *ofconn, msg = start_stats_reply(osr, sizeof *ops * 16); if (psr->port_no != htons(OFPP_NONE)) { - port = port_array_get(&p->ports, + port = port_array_get(&p->ports, ofp_port_to_odp_port(ntohs(psr->port_no))); if (port) { append_port_stat(port, ntohs(psr->port_no), ofconn, &msg); @@ -3257,7 +3305,7 @@ flow_stats_ds_cb(struct cls_rule *rule_, void *cbdata_) ds_put_cstr(results, "\n"); } -/* Adds a pretty-printed description of all flows to 'results', including +/* 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) @@ -3549,7 +3597,6 @@ add_flow(struct ofproto *p, struct ofconn *ofconn, } rule_insert(p, rule, packet, in_port); - ofpbuf_delete(packet); return error; } @@ -3587,7 +3634,6 @@ send_buffered_packet(struct ofproto *ofproto, struct ofconn *ofconn, flow_extract(packet, 0, in_port, &flow); rule_execute(ofproto, rule, packet, &flow); - ofpbuf_delete(packet); return 0; } @@ -4095,9 +4141,6 @@ handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet) } } - rule_execute(p, rule, &payload, &flow); - rule_reinstall(p, rule); - if (rule->super && rule->super->cr.priority == FAIL_OPEN_PRIORITY) { /* * Extra-special case for fail-open mode. @@ -4109,10 +4152,13 @@ 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, packet); - } else { - ofpbuf_delete(packet); + send_packet_in(p, ofpbuf_clone_with_headroom(packet, + DPIF_RECV_MSG_PADDING)); } + + ofpbuf_pull(packet, sizeof *msg); + rule_execute(p, rule, packet, &flow); + rule_reinstall(p, rule); } static void