X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif-xlate.c;h=6e928da626edec7bd666f9d6a56fb6e86416d8b0;hb=6b1c573408f8771e428707278f86c5b3b076982a;hp=36a2f662ce83800017a0511cb0789ea3c58680bf;hpb=0b41113701e9d2c80e8621f3b98641402ba39b2b;p=cascardo%2Fovs.git diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 36a2f662c..6e928da62 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. +/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,6 +54,7 @@ #include "ofproto/ofproto-dpif-sflow.h" #include "ofproto/ofproto-dpif.h" #include "ofproto/ofproto-provider.h" +#include "packets.h" #include "ovs-router.h" #include "tnl-ports.h" #include "tunnel.h" @@ -505,6 +506,8 @@ static void compose_output_action(struct xlate_ctx *, ofp_port_t ofp_port, static struct xbridge *xbridge_lookup(struct xlate_cfg *, const struct ofproto_dpif *); +static struct xbridge *xbridge_lookup_by_uuid(struct xlate_cfg *, + const struct uuid *); static struct xbundle *xbundle_lookup(struct xlate_cfg *, const struct ofbundle *); static struct xport *xport_lookup(struct xlate_cfg *, @@ -1232,6 +1235,19 @@ xbridge_lookup(struct xlate_cfg *xcfg, const struct ofproto_dpif *ofproto) return NULL; } +static struct xbridge * +xbridge_lookup_by_uuid(struct xlate_cfg *xcfg, const struct uuid *uuid) +{ + struct xbridge *xbridge; + + HMAP_FOR_EACH (xbridge, hmap_node, &xcfg->xbridges) { + if (uuid_equals(ofproto_dpif_get_uuid(xbridge->ofproto), uuid)) { + return xbridge; + } + } + return NULL; +} + static struct xbundle * xbundle_lookup(struct xlate_cfg *xcfg, const struct ofbundle *ofbundle) { @@ -2698,21 +2714,24 @@ process_special(struct xlate_ctx *ctx, const struct xport *xport) static int tnl_route_lookup_flow(const struct flow *oflow, - ovs_be32 *ip, struct xport **out_port) + struct in6_addr *ip, struct xport **out_port) { char out_dev[IFNAMSIZ]; struct xbridge *xbridge; struct xlate_cfg *xcfg; - ovs_be32 gw; + struct in6_addr gw; + struct in6_addr dst; - if (!ovs_router_lookup4(oflow->tunnel.ip_dst, out_dev, &gw)) { + dst = flow_tnl_dst(&oflow->tunnel); + if (!ovs_router_lookup(&dst, out_dev, &gw)) { return -ENOENT; } - if (gw) { + if (ipv6_addr_is_set(&gw) && + (!IN6_IS_ADDR_V4MAPPED(&gw) || in6_addr_get_mapped_ipv4(&gw))) { *ip = gw; } else { - *ip = oflow->tunnel.ip_dst; + *ip = dst; } xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp); @@ -2752,6 +2771,19 @@ compose_table_xlate(struct xlate_ctx *ctx, const struct xport *out_dev, ctx->recurse, ctx->resubmits, packet); } +static void +tnl_send_nd_request(struct xlate_ctx *ctx, const struct xport *out_dev, + const struct eth_addr eth_src, + struct in6_addr * ipv6_src, struct in6_addr * ipv6_dst) +{ + struct dp_packet packet; + + dp_packet_init(&packet, 0); + compose_nd(&packet, eth_src, ipv6_src, ipv6_dst); + compose_table_xlate(ctx, out_dev, &packet); + dp_packet_uninit(&packet); +} + static void tnl_send_arp_request(struct xlate_ctx *ctx, const struct xport *out_dev, const struct eth_addr eth_src, @@ -2773,18 +2805,24 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport, { struct ovs_action_push_tnl tnl_push_data; struct xport *out_dev = NULL; - ovs_be32 s_ip, d_ip = 0; + ovs_be32 s_ip = 0, d_ip = 0; + struct in6_addr s_ip6 = in6addr_any; + struct in6_addr d_ip6 = in6addr_any; struct eth_addr smac; struct eth_addr dmac; int err; + char buf_sip6[INET6_ADDRSTRLEN]; + char buf_dip6[INET6_ADDRSTRLEN]; - err = tnl_route_lookup_flow(flow, &d_ip, &out_dev); + err = tnl_route_lookup_flow(flow, &d_ip6, &out_dev); if (err) { xlate_report(ctx, "native tunnel routing failed"); return err; } - xlate_report(ctx, "tunneling to "IP_FMT" via %s", - IP_ARGS(d_ip), netdev_get_name(out_dev->netdev)); + + xlate_report(ctx, "tunneling to %s via %s", + ipv6_string_mapped(buf_dip6, &d_ip6), + netdev_get_name(out_dev->netdev)); /* Use mac addr of bridge port of the peer. */ err = netdev_get_etheraddr(out_dev->netdev, &smac); @@ -2793,35 +2831,51 @@ build_tunnel_send(struct xlate_ctx *ctx, const struct xport *xport, return err; } - err = netdev_get_in4(out_dev->netdev, (struct in_addr *) &s_ip, NULL); - if (err) { - xlate_report(ctx, "tunnel output device lacks IPv4 address"); - return err; + d_ip = in6_addr_get_mapped_ipv4(&d_ip6); + if (d_ip) { + err = netdev_get_in4(out_dev->netdev, (struct in_addr *) &s_ip, NULL); + if (err) { + xlate_report(ctx, "tunnel output device lacks IPv4 address"); + return err; + } + in6_addr_set_mapped_ipv4(&s_ip6, s_ip); + } else { + err = netdev_get_in6(out_dev->netdev, &s_ip6); + if (err) { + xlate_report(ctx, "tunnel output device lacks IPv6 address"); + return err; + } } - err = tnl_arp_lookup(out_dev->xbridge->name, d_ip, &dmac); + err = tnl_neigh_lookup(out_dev->xbridge->name, &d_ip6, &dmac); if (err) { - xlate_report(ctx, "ARP cache miss for "IP_FMT" on bridge %s, " - "sending ARP request", - IP_ARGS(d_ip), out_dev->xbridge->name); - tnl_send_arp_request(ctx, out_dev, smac, s_ip, d_ip); + xlate_report(ctx, "neighbor cache miss for %s on bridge %s, " + "sending %s request", + buf_dip6, out_dev->xbridge->name, d_ip ? "ARP" : "ND"); + if (d_ip) { + tnl_send_arp_request(ctx, out_dev, smac, s_ip, d_ip); + } else { + tnl_send_nd_request(ctx, out_dev, smac, &s_ip6, &d_ip6); + } return err; } + if (ctx->xin->xcache) { struct xc_entry *entry; entry = xlate_cache_add_entry(ctx->xin->xcache, XC_TNL_NEIGH); ovs_strlcpy(entry->u.tnl_neigh_cache.br_name, out_dev->xbridge->name, sizeof entry->u.tnl_neigh_cache.br_name); - in6_addr_set_mapped_ipv4(&entry->u.tnl_neigh_cache.d_ipv6, d_ip); + entry->u.tnl_neigh_cache.d_ipv6 = d_ip6; } - xlate_report(ctx, "tunneling from "ETH_ADDR_FMT" "IP_FMT - " to "ETH_ADDR_FMT" "IP_FMT, - ETH_ADDR_ARGS(smac), IP_ARGS(s_ip), - ETH_ADDR_ARGS(dmac), IP_ARGS(d_ip)); + xlate_report(ctx, "tunneling from "ETH_ADDR_FMT" %s" + " to "ETH_ADDR_FMT" %s", + ETH_ADDR_ARGS(smac), ipv6_string_mapped(buf_sip6, &s_ip6), + ETH_ADDR_ARGS(dmac), buf_dip6); + err = tnl_port_build_header(xport->ofport, flow, - dmac, smac, s_ip, &tnl_push_data); + dmac, smac, &s_ip6, &tnl_push_data); if (err) { return err; } @@ -3023,7 +3077,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, } if (xport->is_tunnel) { - ovs_be32 dst; + struct in6_addr dst; /* Save tunnel metadata so that changes made due to * the Logical (tunnel) Port are not visible for any further * matches, while explicit set actions on tunnel metadata are. @@ -3034,8 +3088,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, xlate_report(ctx, "Tunneling decided against output"); goto out; /* restore flow_nw_tos */ } - dst = in6_addr_get_mapped_ipv4(&ctx->orig_tunnel_ipv6_dst); - if (flow->tunnel.ip_dst == dst) { + dst = flow_tnl_dst(&flow->tunnel); + if (ipv6_addr_equals(&dst, &ctx->orig_tunnel_ipv6_dst)) { xlate_report(ctx, "Not tunneling to our own address"); goto out; /* restore flow_nw_tos */ } @@ -3529,49 +3583,47 @@ execute_controller_action(struct xlate_ctx *ctx, int len, enum ofp_packet_in_reason reason, uint16_t controller_id) { - struct ofproto_packet_in *pin; struct dp_packet *packet; ctx->xout->slow |= SLOW_CONTROLLER; + xlate_commit_actions(ctx); if (!ctx->xin->packet) { return; } packet = dp_packet_clone(ctx->xin->packet); - xlate_commit_actions(ctx); - odp_execute_actions(NULL, &packet, 1, false, ctx->odp_actions->data, ctx->odp_actions->size, NULL); - pin = xmalloc(sizeof *pin); - pin->up.packet_len = dp_packet_size(packet); - pin->up.packet = dp_packet_steal_data(packet); - pin->up.reason = reason; - pin->up.table_id = ctx->table_id; - pin->up.cookie = ctx->rule_cookie; - - flow_get_metadata(&ctx->xin->flow, &pin->up.flow_metadata); + /* A packet sent by an action in a table-miss rule is considered an + * explicit table miss. OpenFlow before 1.3 doesn't have that concept so + * it will get translated back to OFPR_ACTION for those versions. */ + if (reason == OFPR_ACTION + && ctx->rule && rule_dpif_is_table_miss(ctx->rule)) { + reason = OFPR_EXPLICIT_MISS; + } + + size_t packet_len = dp_packet_size(packet); + + struct ofproto_async_msg *am = xmalloc(sizeof *am); + *am = (struct ofproto_async_msg) { + .controller_id = controller_id, + .oam = OAM_PACKET_IN, + .pin = { + .up = { + .packet = dp_packet_steal_data(packet), + .len = packet_len, + .reason = reason, + .table_id = ctx->table_id, + .cookie = ctx->rule_cookie, + }, + .max_len = len, + }, + }; + flow_get_metadata(&ctx->xin->flow, &am->pin.up.flow_metadata); - pin->controller_id = controller_id; - pin->send_len = len; - /* If a rule is a table-miss rule then this is - * a table-miss handled by a table-miss rule. - * - * Else, if rule is internal and has a controller action, - * the later being implied by the rule being processed here, - * then this is a table-miss handled without a table-miss rule. - * - * Otherwise this is not a table-miss. */ - pin->miss_type = OFPROTO_PACKET_IN_NO_MISS; - if (ctx->rule) { - if (rule_dpif_is_table_miss(ctx->rule)) { - pin->miss_type = OFPROTO_PACKET_IN_MISS_FLOW; - } else if (rule_dpif_is_internal(ctx->rule)) { - pin->miss_type = OFPROTO_PACKET_IN_MISS_WITHOUT_FLOW; - } - } - ofproto_dpif_send_packet_in(ctx->xbridge->ofproto, pin); + ofproto_dpif_send_async_msg(ctx->xbridge->ofproto, am); dp_packet_delete(packet); } @@ -3587,14 +3639,17 @@ compose_recirculate_action__(struct xlate_ctx *ctx, uint8_t table) struct recirc_state state = { .table_id = table, - .ofproto = ctx->xbridge->ofproto, + .ofproto_uuid = *ofproto_dpif_get_uuid(ctx->xbridge->ofproto), .metadata = md, - .stack = &ctx->stack, + .stack = ctx->stack.data, + .n_stack = ctx->stack.size / sizeof(union mf_subvalue), .mirrors = ctx->mirrors, .conntracked = ctx->conntracked, + .ofpacts = ((struct ofpact *) ctx->action_set.data + + ctx->recirc_action_offset / sizeof(struct ofpact)), + .ofpacts_len = ctx->action_set.size - ctx->recirc_action_offset, + .action_set = ctx->action_set.data, .action_set_len = ctx->recirc_action_offset, - .ofpacts_len = ctx->action_set.size, - .ofpacts = ctx->action_set.data, }; /* Allocate a unique recirc id for the given metadata state in the @@ -4034,12 +4089,9 @@ may_receive(const struct xport *xport, struct xlate_ctx *ctx) } static void -xlate_write_actions(struct xlate_ctx *ctx, const struct ofpact *a) +xlate_write_actions__(struct xlate_ctx *ctx, + const struct ofpact *ofpacts, size_t ofpacts_len) { - const struct ofpact_nest *on = ofpact_get_WRITE_ACTIONS(a); - size_t on_len = ofpact_nest_get_action_len(on); - const struct ofpact *inner; - /* Maintain actset_output depending on the contents of the action set: * * - OFPP_UNSET, if there is no "output" action. @@ -4050,10 +4102,11 @@ xlate_write_actions(struct xlate_ctx *ctx, const struct ofpact *a) * - OFPP_UNSET, if there is a "group" action. */ if (!ctx->action_set_has_group) { - OFPACT_FOR_EACH (inner, on->actions, on_len) { - if (inner->type == OFPACT_OUTPUT) { - ctx->xin->flow.actset_output = ofpact_get_OUTPUT(inner)->port; - } else if (inner->type == OFPACT_GROUP) { + const struct ofpact *a; + OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { + if (a->type == OFPACT_OUTPUT) { + ctx->xin->flow.actset_output = ofpact_get_OUTPUT(a)->port; + } else if (a->type == OFPACT_GROUP) { ctx->xin->flow.actset_output = OFPP_UNSET; ctx->action_set_has_group = true; break; @@ -4061,8 +4114,13 @@ xlate_write_actions(struct xlate_ctx *ctx, const struct ofpact *a) } } - ofpbuf_put(&ctx->action_set, on->actions, on_len); - ofpact_pad(&ctx->action_set); + ofpbuf_put(&ctx->action_set, ofpacts, ofpacts_len); +} + +static void +xlate_write_actions(struct xlate_ctx *ctx, const struct ofpact_nest *a) +{ + xlate_write_actions__(ctx, a->actions, ofpact_nest_get_action_len(a)); } static void @@ -4107,8 +4165,7 @@ recirc_put_unroll_xlate(struct xlate_ctx *ctx) /* Copy remaining actions to the action_set to be executed after recirculation. * UNROLL_XLATE action is inserted, if not already done so, before actions that - * may generate PACKET_INs from the current table and without matching another - * rule. */ + * may depend on the current table ID or flow cookie. */ static void recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len, struct xlate_ctx *ctx) @@ -4117,17 +4174,25 @@ recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len, OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { switch (a->type) { - /* May generate PACKET INs. */ case OFPACT_OUTPUT_REG: case OFPACT_GROUP: case OFPACT_OUTPUT: case OFPACT_CONTROLLER: case OFPACT_DEC_MPLS_TTL: case OFPACT_DEC_TTL: + /* These actions may generate asynchronous messages, which include + * table ID and flow cookie information. */ recirc_put_unroll_xlate(ctx); break; - /* These may not generate PACKET INs. */ + case OFPACT_RESUBMIT: + if (ofpact_get_RESUBMIT(a)->table_id == 0xff) { + /* This resubmit action is relative to the current table, so we + * need to track what table that is.*/ + recirc_put_unroll_xlate(ctx); + } + break; + case OFPACT_SET_TUNNEL: case OFPACT_REG_MOVE: case OFPACT_SET_FIELD: @@ -4135,8 +4200,7 @@ recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_STACK_POP: case OFPACT_LEARN: case OFPACT_WRITE_METADATA: - case OFPACT_RESUBMIT: /* May indirectly generate PACKET INs, */ - case OFPACT_GOTO_TABLE: /* but from a different table and rule. */ + case OFPACT_GOTO_TABLE: case OFPACT_ENQUEUE: case OFPACT_SET_VLAN_VID: case OFPACT_SET_VLAN_PCP: @@ -4170,11 +4234,12 @@ recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_DEBUG_RECIRC: case OFPACT_CT: case OFPACT_NAT: + /* These may not generate PACKET INs. */ break; - /* These need not be copied for restoration. */ case OFPACT_NOTE: case OFPACT_CONJUNCTION: + /* These need not be copied for restoration. */ continue; } /* Copy the action over. */ @@ -4510,8 +4575,30 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_RESUBMIT: + /* Recirculation complicates resubmit. There are two cases: + * + * - If mpls_pop has been executed, then the flow table lookup + * as part of resubmit might depend on fields that can only + * be obtained via recirculation, so the resubmit itself + * triggers recirculation and we need to make sure that the + * resubmit is executed again after recirculation. + * Therefore, in this case we trigger recirculation and let + * the code following this "switch" append the resubmit to + * the post-recirculation actions. + * + * - Otherwise, some action in the flow entry found by resubmit + * might trigger recirculation. If that happens, then we do + * not want to execute the resubmit again after + * recirculation, so we want to skip back to the head of the + * loop to avoid that, only adding any actions that follow + * the resubmit to the post-recirculation actions. + */ + if (ctx->was_mpls) { + ctx_trigger_recirculation(ctx); + break; + } xlate_ofpact_resubmit(ctx, ofpact_get_RESUBMIT(a)); - break; + continue; case OFPACT_SET_TUNNEL: flow->tunnel.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id); @@ -4684,7 +4771,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_WRITE_ACTIONS: - xlate_write_actions(ctx, a); + xlate_write_actions(ctx, ofpact_get_WRITE_ACTIONS(a)); break; case OFPACT_WRITE_METADATA: @@ -4770,9 +4857,14 @@ xlate_in_init(struct xlate_in *xin, struct ofproto_dpif *ofproto, xin->odp_actions = odp_actions; /* Do recirc lookup. */ - xin->recirc = flow->recirc_id - ? recirc_id_node_find(flow->recirc_id) - : NULL; + xin->recirc = NULL; + if (flow->recirc_id) { + const struct recirc_id_node *node + = recirc_id_node_find(flow->recirc_id); + if (node) { + xin->recirc = &node->state; + } + } } void @@ -4996,7 +5088,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) { *xout = (struct xlate_out) { .slow = 0, - .fail_open = false, .recircs = RECIRC_REFS_EMPTY_INITIALIZER, }; @@ -5017,6 +5108,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) .xin = xin, .xout = xout, .base_flow = *flow, + .orig_tunnel_ipv6_dst = flow_tnl_dst(&flow->tunnel), .xbridge = xbridge, .stack = OFPBUF_STUB_INITIALIZER(stack_stub), .rule = xin->rule, @@ -5049,7 +5141,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) .action_set_has_group = false, .action_set = OFPBUF_STUB_INITIALIZER(action_set_stub), }; - in6_addr_set_mapped_ipv4(&ctx.orig_tunnel_ipv6_dst, flow->tunnel.ip_dst); /* 'base_flow' reflects the packet as it came in, but we need it to reflect * the packet as the datapath will treat it for output actions: @@ -5081,7 +5172,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) COVERAGE_INC(xlate_actions); if (xin->recirc) { - const struct recirc_state *state = &xin->recirc->state; + const struct recirc_state *state = xin->recirc; xlate_report(&ctx, "Restoring state post-recirculation:"); @@ -5096,10 +5187,11 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) } /* Set the bridge for post-recirculation processing if needed. */ - if (ctx.xbridge->ofproto != state->ofproto) { + if (!uuid_equals(ofproto_dpif_get_uuid(ctx.xbridge->ofproto), + &state->ofproto_uuid)) { struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp); const struct xbridge *new_bridge - = xbridge_lookup(xcfg, state->ofproto); + = xbridge_lookup_by_uuid(xcfg, &state->ofproto_uuid); if (OVS_UNLIKELY(!new_bridge)) { /* Drop the packet if the bridge cannot be found. */ @@ -5128,7 +5220,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) /* Restore stack, if any. */ if (state->stack) { - ofpbuf_put(&ctx.stack, state->stack->data, state->stack->size); + ofpbuf_put(&ctx.stack, state->stack, + state->n_stack * sizeof *state->stack); } /* Restore mirror state. */ @@ -5136,28 +5229,19 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) /* Restore action set, if any. */ if (state->action_set_len) { - const struct ofpact *a; - xlate_report_actions(&ctx, "- Restoring action set", - state->ofpacts, state->action_set_len); - - ofpbuf_put(&ctx.action_set, state->ofpacts, state->action_set_len); + state->action_set, state->action_set_len); - OFPACT_FOR_EACH(a, state->ofpacts, state->action_set_len) { - if (a->type == OFPACT_GROUP) { - ctx.action_set_has_group = true; - break; - } - } + flow->actset_output = OFPP_UNSET; + xlate_write_actions__(&ctx, state->action_set, + state->action_set_len); } /* Restore recirculation actions. If there are no actions, processing * will start with a lookup in the table set above. */ - if (state->ofpacts_len > state->action_set_len) { - xin->ofpacts_len = state->ofpacts_len - state->action_set_len; - xin->ofpacts = state->ofpacts + - state->action_set_len / sizeof *state->ofpacts; - + xin->ofpacts = state->ofpacts; + xin->ofpacts_len = state->ofpacts_len; + if (state->ofpacts_len) { xlate_report_actions(&ctx, "- Restoring actions", xin->ofpacts, xin->ofpacts_len); } @@ -5192,7 +5276,6 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) ctx.xin->resubmit_hook(ctx.xin, ctx.rule, 0); } } - xout->fail_open = ctx.rule && rule_dpif_is_fail_open(ctx.rule); /* Get the proximate input port of the packet. (If xin->recirc, * flow->in_port is the ultimate input port of the packet.) */