X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=secchan%2Fofproto.c;h=4266cbf71a36886466b45f6b06ce063551b4a9e1;hb=0c0afbecaace0509d7b2e5b7dee4b4eac7b31e19;hp=105e43e6b72c2d658d21c0f4d66f045e47a9a614;hpb=431d8ad2a0a2e20d1719f77dda66da70acf0d38f;p=openvswitch diff --git a/secchan/ofproto.c b/secchan/ofproto.c index 105e43e6..4266cbf7 100644 --- a/secchan/ofproto.c +++ b/secchan/ofproto.c @@ -82,7 +82,7 @@ static int xlate_actions(const union ofp_action *in, size_t n_in, const flow_t *flow, struct ofproto *ofproto, const struct ofpbuf *packet, struct odp_actions *out, tag_type *tags, - bool *may_setup_flow); + bool *may_set_up_flow, uint16_t *nf_output_iface); struct rule { struct cls_rule cr; @@ -97,6 +97,7 @@ struct rule { uint8_t tcp_flags; /* Bitwise-OR of all TCP flags seen. */ uint8_t ip_tos; /* Last-seen IP type-of-service. */ tag_type tags; /* Tags (set only by hooks). */ + uint16_t nf_output_iface; /* Output interface index for NetFlow. */ /* If 'super' is non-NULL, this rule is a subrule, that is, it is an * exact-match rule (having cr.wc.wildcards of 0) generated from the @@ -811,9 +812,6 @@ ofproto_run1(struct ofproto *p) } } } - if (p->fail_open) { - fail_open_run(p->fail_open); - } pinsched_run(p->miss_sched, send_packet_in_miss, p); pinsched_run(p->action_sched, send_packet_in_action, p); if (p->executer) { @@ -825,6 +823,12 @@ ofproto_run1(struct ofproto *p) ofconn_run(ofconn, p); } + /* Fail-open maintenance. Do this after processing the ofconns since + * fail-open checks the status of the controller rconn. */ + if (p->fail_open) { + fail_open_run(p->fail_open); + } + for (i = 0; i < p->n_listeners; i++) { struct vconn *vconn; int retval; @@ -968,7 +972,7 @@ ofproto_send_packet(struct ofproto *p, const flow_t *flow, int error; error = xlate_actions(actions, n_actions, flow, p, packet, &odp_actions, - NULL, NULL); + NULL, NULL, NULL); if (error) { return error; } @@ -1352,6 +1356,9 @@ ofconn_run(struct ofconn *ofconn, struct ofproto *p) if (!of_msg) { break; } + if (p->fail_open) { + fail_open_maybe_recover(p->fail_open); + } handle_openflow(ofconn, p, of_msg); ofpbuf_delete(of_msg); } @@ -1480,7 +1487,7 @@ rule_execute(struct ofproto *ofproto, struct rule *rule, if (rule->cr.wc.wildcards || !flow_equal(flow, &rule->cr.flow)) { struct rule *super = rule->super ? rule->super : rule; if (xlate_actions(super->actions, super->n_actions, flow, ofproto, - packet, &a, NULL, 0)) { + packet, &a, NULL, 0, NULL)) { return; } actions = a.actions; @@ -1576,7 +1583,8 @@ rule_make_actions(struct ofproto *p, struct rule *rule, 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); + packet, &a, &rule->tags, &rule->may_install, + &rule->nf_output_iface); actions_len = a.n_actions * sizeof *a.actions; if (rule->n_odp_actions != a.n_actions @@ -1694,9 +1702,17 @@ static void rule_post_uninstall(struct ofproto *ofproto, struct rule *rule) { struct rule *super = rule->super; + bool controller_action; rule_account(ofproto, rule, 0); - if (ofproto->netflow && rule->byte_count) { + + /* If the only action is send to the controller then don't report + * NetFlow expiration messages since it is just part of the control + * logic for the network and not real traffic. */ + controller_action = rule->n_odp_actions == 1 && + rule->odp_actions[0].type == ODPAT_CONTROLLER; + + if (ofproto->netflow && rule->byte_count && !controller_action) { struct ofexpired expired; expired.flow = rule->cr.flow; expired.packet_count = rule->packet_count; @@ -1705,6 +1721,7 @@ rule_post_uninstall(struct ofproto *ofproto, struct rule *rule) expired.created = rule->created; expired.tcp_flags = rule->tcp_flags; expired.ip_tos = rule->ip_tos; + expired.output_iface = rule->nf_output_iface; netflow_expire(ofproto->netflow, &expired); } if (super) { @@ -1714,15 +1731,15 @@ rule_post_uninstall(struct ofproto *ofproto, struct rule *rule) if (rule->packet_count) { super->ip_tos = rule->ip_tos; } - } - /* Reset counters to prevent double counting if the rule ever gets - * reinstalled. */ - rule->packet_count = 0; - rule->byte_count = 0; - rule->accounted_bytes = 0; - rule->tcp_flags = 0; - rule->ip_tos = 0; + /* Reset counters to prevent double counting if the rule ever gets + * reinstalled. */ + rule->packet_count = 0; + rule->byte_count = 0; + rule->accounted_bytes = 0; + rule->tcp_flags = 0; + rule->ip_tos = 0; + } } static void @@ -1888,9 +1905,14 @@ handle_set_config(struct ofproto *p, struct ofconn *ofconn, } static void -add_output_group_action(struct odp_actions *actions, uint16_t group) +add_output_group_action(struct odp_actions *actions, uint16_t group, + uint16_t *nf_output_iface) { odp_actions_add(actions, ODPAT_OUTPUT_GROUP)->output_group.group = group; + + if (group == DP_GROUP_ALL || group == DP_GROUP_FLOOD) { + *nf_output_iface = NF_OUT_FLOOD; + } } static void @@ -1913,8 +1935,9 @@ struct action_xlate_ctx { /* Output. */ struct odp_actions *out; /* Datapath actions. */ tag_type *tags; /* Tags associated with OFPP_NORMAL actions. */ - bool may_setup_flow; /* True ordinarily; false if the actions must + 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. */ }; static void do_xlate_actions(const union ofp_action *in, size_t n_in, @@ -1924,9 +1947,22 @@ static void add_output_action(struct action_xlate_ctx *ctx, uint16_t port) { const struct ofport *ofport = port_array_get(&ctx->ofproto->ports, port); - if (!ofport || !(ofport->opp.config & OFPPC_NO_FWD)) { - odp_actions_add(ctx->out, ODPAT_OUTPUT)->output.port = port; + + if (ofport) { + if (ofport->opp.config & OFPPC_NO_FWD) { + /* Forwarding disabled on port. */ + return; + } + } else { + /* + * We don't have an ofport record for this port, but it doesn't hurt to + * allow forwarding to it anyhow. Maybe such a port will appear later + * and we're pre-populating the flow table. + */ } + + odp_actions_add(ctx->out, ODPAT_OUTPUT)->output.port = port; + ctx->nf_output_iface = port; } static struct rule * @@ -1976,6 +2012,9 @@ xlate_output_action(struct action_xlate_ctx *ctx, const struct ofp_action_output *oao) { uint16_t odp_port; + uint16_t prev_nf_output_iface = ctx->nf_output_iface; + + ctx->nf_output_iface = NF_OUT_DROP; switch (ntohs(oao->port)) { case OFPP_IN_PORT: @@ -1987,16 +2026,18 @@ xlate_output_action(struct action_xlate_ctx *ctx, case OFPP_NORMAL: if (!ctx->ofproto->ofhooks->normal_cb(ctx->flow, ctx->packet, ctx->out, ctx->tags, + &ctx->nf_output_iface, ctx->ofproto->aux)) { COVERAGE_INC(ofproto_uninstallable); - ctx->may_setup_flow = false; + ctx->may_set_up_flow = false; } break; case OFPP_FLOOD: - add_output_group_action(ctx->out, DP_GROUP_FLOOD); + add_output_group_action(ctx->out, DP_GROUP_FLOOD, + &ctx->nf_output_iface); break; case OFPP_ALL: - add_output_group_action(ctx->out, DP_GROUP_ALL); + add_output_group_action(ctx->out, DP_GROUP_ALL, &ctx->nf_output_iface); break; case OFPP_CONTROLLER: add_controller_action(ctx->out, oao); @@ -2011,6 +2052,15 @@ xlate_output_action(struct action_xlate_ctx *ctx, } break; } + + if (prev_nf_output_iface == NF_OUT_FLOOD) { + ctx->nf_output_iface = NF_OUT_FLOOD; + } else if (ctx->nf_output_iface == NF_OUT_DROP) { + ctx->nf_output_iface = prev_nf_output_iface; + } else if (prev_nf_output_iface != NF_OUT_DROP && + ctx->nf_output_iface != NF_OUT_FLOOD) { + ctx->nf_output_iface = NF_OUT_MULTI; + } } static void @@ -2109,7 +2159,8 @@ static int xlate_actions(const union ofp_action *in, size_t n_in, const flow_t *flow, struct ofproto *ofproto, const struct ofpbuf *packet, - struct odp_actions *out, tag_type *tags, bool *may_setup_flow) + 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; @@ -2121,17 +2172,21 @@ xlate_actions(const union ofp_action *in, size_t n_in, ctx.packet = packet; ctx.out = out; ctx.tags = tags ? tags : &no_tags; - ctx.may_setup_flow = true; + ctx.may_set_up_flow = true; + ctx.nf_output_iface = NF_OUT_DROP; do_xlate_actions(in, n_in, &ctx); - /* Check with in-band control to see if we're allowed to setup this + /* 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_setup_flow = false; + ctx.may_set_up_flow = false; } - if (may_setup_flow) { - *may_setup_flow = ctx.may_setup_flow; + 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)) { odp_actions_init(out); @@ -2162,7 +2217,7 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn, if (opo->buffer_id != htonl(UINT32_MAX)) { error = pktbuf_retrieve(ofconn->pktbuf, ntohl(opo->buffer_id), &buffer, &in_port); - if (error) { + if (error || !buffer) { return error; } payload = *buffer; @@ -2172,7 +2227,7 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn, flow_extract(&payload, 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); + &flow, p, &payload, &actions, NULL, NULL, NULL); if (error) { return error; } @@ -2402,19 +2457,22 @@ query_stats(struct ofproto *p, struct rule *rule, struct odp_flow *odp_flows; size_t n_odp_flows; + packet_count = rule->packet_count; + byte_count = rule->byte_count; + n_odp_flows = rule->cr.wc.wildcards ? list_size(&rule->list) : 1; odp_flows = xcalloc(1, n_odp_flows * sizeof *odp_flows); if (rule->cr.wc.wildcards) { size_t i = 0; LIST_FOR_EACH (subrule, struct rule, list, &rule->list) { odp_flows[i++].key = subrule->cr.flow; + packet_count += subrule->packet_count; + byte_count += subrule->byte_count; } } else { odp_flows[0].key = rule->cr.flow; } - packet_count = rule->packet_count; - byte_count = rule->byte_count; if (!dpif_flow_get_multiple(&p->dpif, odp_flows, n_odp_flows)) { size_t i; for (i = 0; i < n_odp_flows; i++) { @@ -3078,7 +3136,23 @@ handle_odp_msg(struct ofproto *p, struct ofpbuf *packet) rule_execute(p, rule, &payload, &flow); rule_reinstall(p, rule); - ofpbuf_delete(packet); + + if (rule->super && rule->super->cr.priority == FAIL_OPEN_PRIORITY + && rconn_is_connected(p->controller->rconn)) { + /* + * Extra-special case for fail-open mode. + * + * We are in fail-open mode and the packet matched the fail-open rule, + * but we are connected to a controller too. We should send the packet + * up to the controller in the hope that it will try to set up a flow + * and thereby allow us to exit fail-open. + * + * See the top-level comment in fail-open.c for more information. + */ + pinsched_send(p->miss_sched, in_port, packet, send_packet_in_miss, p); + } else { + ofpbuf_delete(packet); + } } static void @@ -3132,9 +3206,9 @@ compose_flow_exp(const struct rule *rule, long long int now, uint8_t reason) flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &ofe->match); ofe->priority = htons(rule->cr.priority); ofe->reason = reason; - ofe->duration = (now - rule->created) / 1000; - ofe->packet_count = rule->packet_count; - ofe->byte_count = rule->byte_count; + ofe->duration = htonl((now - rule->created) / 1000); + ofe->packet_count = htonll(rule->packet_count); + ofe->byte_count = htonll(rule->byte_count); return buf; } @@ -3264,25 +3338,22 @@ static void do_send_packet_in(struct ofconn *ofconn, uint32_t buffer_id, const struct ofpbuf *packet, int send_len) { - struct ofp_packet_in *opi; - struct ofpbuf payload, *buf; - struct odp_msg *msg; + struct odp_msg *msg = packet->data; + struct ofpbuf payload; + struct ofpbuf *opi; + uint8_t reason; - msg = packet->data; + /* Extract packet payload from 'msg'. */ payload.data = msg + 1; payload.size = msg->length - sizeof *msg; - send_len = MIN(send_len, payload.size); - buf = ofpbuf_new(sizeof *opi + send_len); - opi = put_openflow_xid(offsetof(struct ofp_packet_in, data), - OFPT_PACKET_IN, 0, buf); - opi->buffer_id = htonl(buffer_id); - opi->total_len = htons(payload.size); - opi->in_port = htons(odp_port_to_ofp_port(msg->port)); - opi->reason = msg->type == _ODPL_ACTION_NR ? OFPR_ACTION : OFPR_NO_MATCH; - ofpbuf_put(buf, payload.data, MIN(send_len, payload.size)); - update_openflow_length(buf); - rconn_send_with_limit(ofconn->rconn, buf, ofconn->packet_in_counter, 100); + /* Construct ofp_packet_in message. */ + reason = msg->type == _ODPL_ACTION_NR ? OFPR_ACTION : OFPR_NO_MATCH; + opi = make_packet_in(buffer_id, odp_port_to_ofp_port(msg->port), reason, + &payload, send_len); + + /* Send. */ + rconn_send_with_limit(ofconn->rconn, opi, ofconn->packet_in_counter, 100); } static void @@ -3305,6 +3376,7 @@ static void send_packet_in_miss(struct ofpbuf *packet, void *p_) { struct ofproto *p = p_; + bool in_fail_open = p->fail_open && fail_open_is_active(p->fail_open); struct ofconn *ofconn; struct ofpbuf payload; struct odp_msg *msg; @@ -3314,8 +3386,10 @@ send_packet_in_miss(struct ofpbuf *packet, void *p_) payload.size = msg->length - sizeof *msg; LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) { if (ofconn->miss_send_len) { - uint32_t buffer_id = pktbuf_save(ofconn->pktbuf, &payload, - msg->port); + struct pktbuf *pb = ofconn->pktbuf; + uint32_t buffer_id = (in_fail_open + ? pktbuf_get_null() + : pktbuf_save(pb, &payload, msg->port)); int send_len = (buffer_id != UINT32_MAX ? ofconn->miss_send_len : UINT32_MAX); do_send_packet_in(ofconn, buffer_id, packet, send_len); @@ -3358,7 +3432,7 @@ pick_fallback_dpid(void) static bool default_normal_ofhook_cb(const flow_t *flow, const struct ofpbuf *packet, struct odp_actions *actions, tag_type *tags, - void *ofproto_) + uint16_t *nf_output_iface, void *ofproto_) { struct ofproto *ofproto = ofproto_; int out_port; @@ -3385,9 +3459,10 @@ default_normal_ofhook_cb(const flow_t *flow, const struct ofpbuf *packet, /* Determine output port. */ out_port = mac_learning_lookup_tag(ofproto->ml, flow->dl_dst, 0, tags); if (out_port < 0) { - add_output_group_action(actions, DP_GROUP_FLOOD); + add_output_group_action(actions, DP_GROUP_FLOOD, nf_output_iface); } else if (out_port != flow->in_port) { odp_actions_add(actions, ODPAT_OUTPUT)->output.port = out_port; + *nf_output_iface = out_port; } else { /* Drop. */ }