X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif-xlate.c;h=aa102178e5d60fa7693ba9a5bad0cd3a4daed6b7;hb=3293cb856802f8f7371e5d982e4083f6aec98eb0;hp=ab4d52fb3a0e0cae9f6c4509fb951ecff9efce62;hpb=9ac0aadab9f99c5f9cbe8b30cc095ce9be4be4e9;p=cascardo%2Fovs.git diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index ab4d52fb3..aa102178e 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. @@ -22,7 +22,7 @@ #include #include -#include "tnl-arp-cache.h" +#include "tnl-neigh-cache.h" #include "bfd.h" #include "bitmap.h" #include "bond.h" @@ -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" @@ -171,7 +172,7 @@ struct xlate_ctx { * which might lead to an infinite loop. This could happen easily * if a tunnel is marked as 'ip_remote=flow', and the flow does not * actually set the tun_dst field. */ - ovs_be32 orig_tunnel_ip_dst; + struct in6_addr orig_tunnel_ipv6_dst; /* Stack for the push and pop actions. Each stack element is of type * "union mf_subvalue". */ @@ -367,6 +368,16 @@ exit_recirculates(const struct xlate_ctx *ctx) return ctx->recirc_action_offset >= 0; } +static void +ctx_cancel_recirculation(struct xlate_ctx *ctx) +{ + if (exit_recirculates(ctx)) { + ctx->action_set.size = ctx->recirc_action_offset; + ctx->recirc_action_offset = -1; + ctx->last_unroll_offset = -1; + } +} + static void compose_recirculate_action(struct xlate_ctx *ctx); /* A controller may use OFPP_NONE as the ingress port to indicate that @@ -399,7 +410,7 @@ enum xc_type { XC_NORMAL, XC_FIN_TIMEOUT, XC_GROUP, - XC_TNL_ARP, + XC_TNL_NEIGH, }; /* xlate_cache entries hold enough information to perform the side effects of @@ -451,16 +462,16 @@ struct xc_entry { } group; struct { char br_name[IFNAMSIZ]; - ovs_be32 d_ip; - } tnl_arp_cache; + struct in6_addr d_ipv6; + } tnl_neigh_cache; } u; }; -#define XC_ENTRY_FOR_EACH(entry, entries, xcache) \ - entries = xcache->entries; \ - for (entry = ofpbuf_try_pull(&entries, sizeof *entry); \ - entry; \ - entry = ofpbuf_try_pull(&entries, sizeof *entry)) +#define XC_ENTRY_FOR_EACH(ENTRY, ENTRIES, XCACHE) \ + ENTRIES = XCACHE->entries; \ + for (ENTRY = ofpbuf_try_pull(&ENTRIES, sizeof *ENTRY); \ + ENTRY; \ + ENTRY = ofpbuf_try_pull(&ENTRIES, sizeof *ENTRY)) struct xlate_cache { struct ofpbuf entries; @@ -505,6 +516,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 +1245,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 +2724,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 +2781,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 +2815,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 +2841,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_ARP); - ovs_strlcpy(entry->u.tnl_arp_cache.br_name, out_dev->xbridge->name, - sizeof entry->u.tnl_arp_cache.br_name); - entry->u.tnl_arp_cache.d_ip = d_ip; + 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); + 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; } @@ -2867,7 +2931,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, /* If 'struct flow' gets additional metadata, we'll need to zero it out * before traversing a patch port. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 34); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35); memset(&flow_tnl, 0, sizeof flow_tnl); if (!xport) { @@ -2955,11 +3019,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, ctx->odp_actions->size = old_size; /* Undo changes that may have been done for recirculation. */ - if (exit_recirculates(ctx)) { - ctx->action_set.size = ctx->recirc_action_offset; - ctx->recirc_action_offset = -1; - ctx->last_unroll_offset = -1; - } + ctx_cancel_recirculation(ctx); } } @@ -3023,6 +3083,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, } if (xport->is_tunnel) { + 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. @@ -3033,7 +3094,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 */ } - if (flow->tunnel.ip_dst == ctx->orig_tunnel_ip_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 */ } @@ -3527,49 +3589,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); } @@ -3585,14 +3645,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 @@ -3611,9 +3674,7 @@ compose_recirculate_action__(struct xlate_ctx *ctx, uint8_t table) nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_RECIRC, id); /* Undo changes done by recirculation. */ - ctx->action_set.size = ctx->recirc_action_offset; - ctx->recirc_action_offset = -1; - ctx->last_unroll_offset = -1; + ctx_cancel_recirculation(ctx); } /* Called only when ctx->recirc_action_offset is set. */ @@ -4032,12 +4093,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. @@ -4048,10 +4106,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; @@ -4059,8 +4118,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 @@ -4103,29 +4167,34 @@ 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. */ +/* Copy actions 'a' through 'end' to the action_set to be executed after + * recirculation. UNROLL_XLATE action is inserted, if not already done so, + * before actions that may depend on the current table ID or flow cookie. */ static void -recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +recirc_unroll_actions(const struct ofpact *a, const struct ofpact *end, struct xlate_ctx *ctx) { - const struct ofpact *a; - - OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { + for (; a < end; a = ofpact_next(a)) { 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: @@ -4133,8 +4202,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: @@ -4168,11 +4236,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. */ @@ -4262,12 +4331,13 @@ put_ct_nat(struct xlate_ctx *ctx) nl_msg_put_flag(ctx->odp_actions, OVS_NAT_ATTR_PROTO_RANDOM); } if (ofn->range_af == AF_INET) { - nl_msg_put_u32(ctx->odp_actions, OVS_NAT_ATTR_IP_MIN, + nl_msg_put_be32(ctx->odp_actions, OVS_NAT_ATTR_IP_MIN, ofn->range.addr.ipv4.min); if (ofn->range.addr.ipv4.max && - ofn->range.addr.ipv4.max > ofn->range.addr.ipv4.min) { - nl_msg_put_u32(ctx->odp_actions, OVS_NAT_ATTR_IP_MAX, - ofn->range.addr.ipv4.max); + (ntohl(ofn->range.addr.ipv4.max) + > ntohl(ofn->range.addr.ipv4.min))) { + nl_msg_put_be32(ctx->odp_actions, OVS_NAT_ATTR_IP_MAX, + ofn->range.addr.ipv4.max); } } else if (ofn->range_af == AF_INET6) { nl_msg_put_unspec(ctx->odp_actions, OVS_NAT_ATTR_IP_MIN, @@ -4353,8 +4423,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, const struct ofpact *a; if (ovs_native_tunneling_is_on(ctx->xbridge->ofproto)) { - tnl_arp_snoop(flow, wc, ctx->xbridge->name); - tnl_nd_snoop(flow, wc, ctx->xbridge->name); + tnl_neigh_snoop(flow, wc, ctx->xbridge->name); } /* dl_type already in the mask, not set below. */ @@ -4372,9 +4441,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, /* Check if need to store the remaining actions for later * execution. */ if (exit_recirculates(ctx)) { - recirc_unroll_actions(a, OFPACT_ALIGN(ofpacts_len - - ((uint8_t *)a - - (uint8_t *)ofpacts)), + recirc_unroll_actions(a, ofpact_end(ofpacts, ofpacts_len), ctx); } break; @@ -4508,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); @@ -4682,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: @@ -4698,12 +4787,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_GOTO_TABLE: { struct ofpact_goto_table *ogt = ofpact_get_GOTO_TABLE(a); - /* Allow ctx->table_id == TBL_INTERNAL, which will be greater - * than ogt->table_id. This is to allow goto_table actions that - * triggered recirculation: ctx->table_id will be TBL_INTERNAL - * after recirculation. */ - ovs_assert(ctx->table_id == TBL_INTERNAL - || ctx->table_id < ogt->table_id); + ovs_assert(ctx->table_id < ogt->table_id); + xlate_table_action(ctx, ctx->xin->flow.in_port.ofp_port, ogt->table_id, true, true); break; @@ -4732,10 +4817,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, /* Check if need to store this and the remaining actions for later * execution. */ if (!ctx->error && ctx->exit && ctx_first_recirculation_action(ctx)) { - recirc_unroll_actions(a, OFPACT_ALIGN(ofpacts_len - - ((uint8_t *)a - - (uint8_t *)ofpacts)), - ctx); + recirc_unroll_actions(a, ofpact_end(ofpacts, ofpacts_len), ctx); break; } } @@ -4768,9 +4850,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 @@ -4994,7 +5081,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, }; @@ -5015,7 +5101,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) .xin = xin, .xout = xout, .base_flow = *flow, - .orig_tunnel_ip_dst = flow->tunnel.ip_dst, + .orig_tunnel_ipv6_dst = flow_tnl_dst(&flow->tunnel), .xbridge = xbridge, .stack = OFPBUF_STUB_INITIALIZER(stack_stub), .rule = xin->rule, @@ -5079,7 +5165,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:"); @@ -5094,10 +5180,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. */ @@ -5126,7 +5213,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. */ @@ -5134,28 +5222,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); } @@ -5190,7 +5269,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.) */ @@ -5268,11 +5346,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) ctx.odp_actions->size = sample_actions_len; /* Undo changes that may have been done for recirculation. */ - if (exit_recirculates(&ctx)) { - ctx.action_set.size = ctx.recirc_action_offset; - ctx.recirc_action_offset = -1; - ctx.last_unroll_offset = -1; - } + ctx_cancel_recirculation(&ctx); } else if (ctx.action_set.size) { /* Translate action set only if not dropping the packet and * not recirculating. */ @@ -5482,10 +5556,10 @@ xlate_push_stats(struct xlate_cache *xcache, group_dpif_credit_stats(entry->u.group.group, entry->u.group.bucket, stats); break; - case XC_TNL_ARP: - /* Lookup arp to avoid arp timeout. */ - tnl_arp_lookup(entry->u.tnl_arp_cache.br_name, - entry->u.tnl_arp_cache.d_ip, &dmac); + case XC_TNL_NEIGH: + /* Lookup neighbor to avoid timeout. */ + tnl_neigh_lookup(entry->u.tnl_neigh_cache.br_name, + &entry->u.tnl_neigh_cache.d_ipv6, &dmac); break; default: OVS_NOT_REACHED(); @@ -5557,7 +5631,7 @@ xlate_cache_clear(struct xlate_cache *xcache) case XC_GROUP: group_dpif_unref(entry->u.group.group); break; - case XC_TNL_ARP: + case XC_TNL_NEIGH: break; default: OVS_NOT_REACHED();