X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto-dpif.c;h=1ffe36a90a48020a2e61308902bfaa7616d1b4cf;hb=0e70cdcb8ddeb20417e682fd63769f9d16601b07;hp=0459e961b2c50e5eec09398db638d1234569d437;hpb=dc155bff1bf6045c4eccbb5443b24d19448a4f7d;p=openvswitch diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 0459e961..1ffe36a9 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -138,6 +138,7 @@ struct ofbundle { /* Configuration. */ struct list ports; /* Contains "struct ofport"s. */ + enum port_vlan_mode vlan_mode; /* VLAN mode */ int vlan; /* -1=trunk port, else a 12-bit VLAN ID. */ unsigned long *trunks; /* Bitmap of trunked VLANs, if 'vlan' == -1. * NULL if all VLANs are trunked. */ @@ -204,6 +205,9 @@ struct action_xlate_ctx { struct flow base_flow; /* Flow at the last commit. */ uint32_t base_priority; /* Priority at the last commit. */ uint8_t table_id; /* OpenFlow table ID where flow was found. */ + uint32_t sflow_n_outputs; /* Number of output ports. */ + uint16_t sflow_odp_port; /* Output port for composing sFlow action. */ + uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */ }; static void action_xlate_ctx_init(struct action_xlate_ctx *, @@ -400,7 +404,9 @@ static int expire(struct ofproto_dpif *); /* Utilities. */ static int send_packet(struct ofproto_dpif *, uint32_t odp_port, const struct ofpbuf *packet); - +static size_t +compose_sflow_action(const struct ofproto_dpif *, struct ofpbuf *odp_actions, + const struct flow *, uint32_t odp_port); /* Global variables. */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); @@ -470,8 +476,7 @@ construct(struct ofproto *ofproto_, int *n_tablesp) error = dpif_recv_set_mask(ofproto->dpif, ((1u << DPIF_UC_MISS) | - (1u << DPIF_UC_ACTION) | - (1u << DPIF_UC_SAMPLE))); + (1u << DPIF_UC_ACTION))); if (error) { VLOG_ERR("failed to listen on datapath %s: %s", name, strerror(error)); dpif_close(ofproto->dpif); @@ -705,7 +710,7 @@ static void get_tables(struct ofproto *ofproto_, struct ofp_table_stats *ots) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); - struct ovs_dp_stats s; + struct dpif_dp_stats s; strcpy(ots->name, "classifier"); @@ -753,6 +758,7 @@ port_construct(struct ofport *port_) struct ofport_dpif *port = ofport_dpif_cast(port_); struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto); + ofproto->need_revalidate = true; port->odp_port = ofp_port_to_odp_port(port->up.ofp_port); port->bundle = NULL; port->cfm = NULL; @@ -773,6 +779,7 @@ port_destruct(struct ofport *port_) struct ofport_dpif *port = ofport_dpif_cast(port_); struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto); + ofproto->need_revalidate = true; bundle_remove(port_); set_cfm(port_, NULL); if (ofproto->sflow) { @@ -809,6 +816,7 @@ set_sflow(struct ofproto *ofproto_, { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); struct dpif_sflow *ds = ofproto->sflow; + if (sflow_options) { if (!ds) { struct ofport_dpif *ofport; @@ -818,11 +826,15 @@ set_sflow(struct ofproto *ofproto_, dpif_sflow_add_port(ds, ofport->odp_port, netdev_get_name(ofport->up.netdev)); } + ofproto->need_revalidate = true; } dpif_sflow_set_options(ds, sflow_options); } else { - dpif_sflow_destroy(ds); - ofproto->sflow = NULL; + if (ds) { + dpif_sflow_destroy(ds); + ofproto->need_revalidate = true; + ofproto->sflow = NULL; + } } return 0; } @@ -978,6 +990,7 @@ bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port, } } if (lacp) { + port->bundle->ofproto->need_revalidate = true; lacp_slave_register(bundle->lacp, port, lacp); } @@ -1029,9 +1042,10 @@ bundle_set(struct ofproto *ofproto_, void *aux, { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); bool need_flush = false; - const unsigned long *trunks; struct ofport_dpif *port; struct ofbundle *bundle; + unsigned long *trunks; + int vlan; size_t i; bool ok; @@ -1054,6 +1068,7 @@ bundle_set(struct ofproto *ofproto_, void *aux, bundle->name = NULL; list_init(&bundle->ports); + bundle->vlan_mode = PORT_VLAN_TRUNK; bundle->vlan = -1; bundle->trunks = NULL; bundle->lacp = NULL; @@ -1113,19 +1128,65 @@ bundle_set(struct ofproto *ofproto_, void *aux, return EINVAL; } + /* Set VLAN tagging mode */ + if (s->vlan_mode != bundle->vlan_mode) { + bundle->vlan_mode = s->vlan_mode; + need_flush = true; + } + /* Set VLAN tag. */ - if (s->vlan != bundle->vlan) { - bundle->vlan = s->vlan; + vlan = (s->vlan_mode == PORT_VLAN_TRUNK ? -1 + : s->vlan >= 0 && s->vlan <= 4095 ? s->vlan + : 0); + if (vlan != bundle->vlan) { + bundle->vlan = vlan; need_flush = true; } /* Get trunked VLANs. */ - trunks = s->vlan == -1 ? s->trunks : NULL; + switch (s->vlan_mode) { + case PORT_VLAN_ACCESS: + trunks = NULL; + break; + + case PORT_VLAN_TRUNK: + trunks = (unsigned long *) s->trunks; + break; + + case PORT_VLAN_NATIVE_UNTAGGED: + case PORT_VLAN_NATIVE_TAGGED: + if (vlan != 0 && (!s->trunks + || !bitmap_is_set(s->trunks, vlan) + || bitmap_is_set(s->trunks, 0))) { + /* Force trunking the native VLAN and prohibit trunking VLAN 0. */ + if (s->trunks) { + trunks = bitmap_clone(s->trunks, 4096); + } else { + trunks = bitmap_allocate1(4096); + } + bitmap_set1(trunks, vlan); + bitmap_set0(trunks, 0); + } else { + trunks = (unsigned long *) s->trunks; + } + break; + + default: + NOT_REACHED(); + } if (!vlan_bitmap_equal(trunks, bundle->trunks)) { free(bundle->trunks); - bundle->trunks = vlan_bitmap_clone(trunks); + if (trunks == s->trunks) { + bundle->trunks = vlan_bitmap_clone(trunks); + } else { + bundle->trunks = trunks; + trunks = NULL; + } need_flush = true; } + if (trunks != s->trunks) { + free(trunks); + } /* Bonding. */ if (!list_is_short(&bundle->ports)) { @@ -1507,7 +1568,8 @@ port_run(struct ofport_dpif *ofport) ofpbuf_uninit(&packet); } - enable = enable && !cfm_get_fault(ofport->cfm); + enable = enable && !cfm_get_fault(ofport->cfm) + && cfm_get_opup(ofport->cfm); } if (ofport->bundle) { @@ -1664,12 +1726,15 @@ send_packet_in(struct ofproto_dpif *ofproto, struct dpif_upcall *upcall, const struct flow *flow, bool clone) { struct ofputil_packet_in pin; + struct user_action_cookie cookie; pin.packet = upcall->packet; pin.in_port = flow->in_port; pin.reason = upcall->type == DPIF_UC_MISS ? OFPR_NO_MATCH : OFPR_ACTION; pin.buffer_id = 0; /* not yet known */ - pin.send_len = upcall->userdata; + + memcpy(&cookie, &upcall->userdata, sizeof(cookie)); + pin.send_len = cookie.data; connmgr_send_packet_in(ofproto->up.connmgr, &pin, flow, clone ? NULL : upcall->packet); } @@ -1773,23 +1838,36 @@ handle_miss_upcall(struct ofproto_dpif *ofproto, struct dpif_upcall *upcall) } static void -handle_upcall(struct ofproto_dpif *ofproto, struct dpif_upcall *upcall) +handle_userspace_upcall(struct ofproto_dpif *ofproto, + struct dpif_upcall *upcall) { struct flow flow; + struct user_action_cookie cookie; - switch (upcall->type) { - case DPIF_UC_ACTION: - COVERAGE_INC(ofproto_dpif_ctlr_action); - odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow); - send_packet_in(ofproto, upcall, &flow, false); - break; + memcpy(&cookie, &upcall->userdata, sizeof(cookie)); - case DPIF_UC_SAMPLE: + if (cookie.type == USER_ACTION_COOKIE_SFLOW) { if (ofproto->sflow) { odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow); - dpif_sflow_received(ofproto->sflow, upcall, &flow); + dpif_sflow_received(ofproto->sflow, upcall->packet, &flow, &cookie); } ofpbuf_delete(upcall->packet); + + } else if (cookie.type == USER_ACTION_COOKIE_CONTROLLER) { + COVERAGE_INC(ofproto_dpif_ctlr_action); + odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow); + send_packet_in(ofproto, upcall, &flow, false); + } else { + VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64, upcall->userdata); + } +} + +static void +handle_upcall(struct ofproto_dpif *ofproto, struct dpif_upcall *upcall) +{ + switch (upcall->type) { + case DPIF_UC_ACTION: + handle_userspace_upcall(ofproto, upcall); break; case DPIF_UC_MISS: @@ -2125,39 +2203,43 @@ execute_odp_actions(struct ofproto_dpif *ofproto, const struct flow *flow, const struct nlattr *odp_actions, size_t actions_len, struct ofpbuf *packet) { + struct odputil_keybuf keybuf; + struct ofpbuf key; + int error; + if (actions_len == NLA_ALIGN(NLA_HDRLEN + sizeof(uint64_t)) && odp_actions->nla_type == OVS_ACTION_ATTR_USERSPACE) { - /* 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. */ + const struct user_action_cookie *cookie; struct dpif_upcall upcall; - upcall.type = DPIF_UC_ACTION; - upcall.packet = packet; - upcall.key = NULL; - upcall.key_len = 0; - upcall.userdata = nl_attr_get_u64(odp_actions); - upcall.sample_pool = 0; - upcall.actions = NULL; - upcall.actions_len = 0; - - send_packet_in(ofproto, &upcall, flow, false); - - return true; - } else { - struct odputil_keybuf keybuf; - struct ofpbuf key; - int error; + cookie = nl_attr_get_unspec(odp_actions, sizeof(*cookie)); + if (cookie->type == USER_ACTION_COOKIE_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. + * This optimization does not work in case of sFlow is turned ON. + * Since first action would be sFlow SAMPLE action followed by + * Controller action. */ + + upcall.type = DPIF_UC_ACTION; + upcall.packet = packet; + upcall.key = NULL; + upcall.key_len = 0; + upcall.userdata = nl_attr_get_u64(odp_actions); + + send_packet_in(ofproto, &upcall, flow, false); + return true; + } + } - ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); - odp_flow_key_from_flow(&key, flow); + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, flow); - error = dpif_execute(ofproto->dpif, key.data, key.size, - odp_actions, actions_len, packet); + error = dpif_execute(ofproto->dpif, key.data, key.size, + odp_actions, actions_len, packet); - ofpbuf_delete(packet); - return !error; - } + ofpbuf_delete(packet); + return !error; } /* Executes the actions indicated by 'facet' on 'packet' and credits 'facet''s @@ -2180,7 +2262,7 @@ facet_execute(struct ofproto_dpif *ofproto, struct facet *facet, assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in)); - flow_extract_stats(&facet->flow, packet, &stats); + dpif_flow_stats_extract(&facet->flow, packet, &stats); stats.used = time_msec(); if (execute_odp_actions(ofproto, &facet->flow, facet->actions, facet->actions_len, packet)) { @@ -2845,7 +2927,7 @@ rule_modify_actions(struct rule *rule_) complete_operation(rule); } -/* Sends 'packet' out of port 'odp_port' within 'p'. +/* Sends 'packet' out of port 'odp_port' within 'ofproto'. * Returns 0 if successful, otherwise a positive errno value. */ static int send_packet(struct ofproto_dpif *ofproto, uint32_t odp_port, @@ -2861,6 +2943,8 @@ send_packet(struct ofproto_dpif *ofproto, uint32_t odp_port, odp_flow_key_from_flow(&key, &flow); ofpbuf_init(&odp_actions, 32); + compose_sflow_action(ofproto, &odp_actions, &flow, odp_port); + nl_msg_put_u32(&odp_actions, OVS_ACTION_ATTR_OUTPUT, odp_port); error = dpif_execute(ofproto->dpif, key.data, key.size, @@ -2881,6 +2965,95 @@ static void do_xlate_actions(const union ofp_action *in, size_t n_in, struct action_xlate_ctx *ctx); static void xlate_normal(struct action_xlate_ctx *); +/* Compose SAMPLE action for sFlow. */ +static size_t +compose_sflow_action(const struct ofproto_dpif *ofproto, + struct ofpbuf *odp_actions, + const struct flow *flow, + uint32_t odp_port) +{ + uint32_t port_ifindex; + uint32_t probability; + struct user_action_cookie *cookie; + size_t sample_offset, actions_offset; + int user_cookie_offset, n_output; + + if (!ofproto->sflow || flow->in_port == OFPP_NONE) { + return 0; + } + + if (odp_port == OVSP_NONE) { + port_ifindex = 0; + n_output = 0; + } else { + port_ifindex = dpif_sflow_odp_port_to_ifindex(ofproto->sflow, odp_port); + n_output = 1; + } + + sample_offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SAMPLE); + + /* Number of packets out of UINT_MAX to sample. */ + probability = dpif_sflow_get_probability(ofproto->sflow); + nl_msg_put_u32(odp_actions, OVS_SAMPLE_ATTR_PROBABILITY, probability); + + actions_offset = nl_msg_start_nested(odp_actions, OVS_SAMPLE_ATTR_ACTIONS); + + cookie = nl_msg_put_unspec_uninit(odp_actions, OVS_ACTION_ATTR_USERSPACE, + sizeof(*cookie)); + cookie->type = USER_ACTION_COOKIE_SFLOW; + cookie->data = port_ifindex; + cookie->n_output = n_output; + cookie->vlan_tci = 0; + user_cookie_offset = (char *) cookie - (char *) odp_actions->data; + + nl_msg_end_nested(odp_actions, actions_offset); + nl_msg_end_nested(odp_actions, sample_offset); + return user_cookie_offset; +} + +/* SAMPLE action must be first action in any given list of actions. + * At this point we do not have all information required to build it. So try to + * build sample action as complete as possible. */ +static void +add_sflow_action(struct action_xlate_ctx *ctx) +{ + ctx->user_cookie_offset = compose_sflow_action(ctx->ofproto, + ctx->odp_actions, + &ctx->flow, OVSP_NONE); + ctx->sflow_odp_port = 0; + ctx->sflow_n_outputs = 0; +} + +/* Fix SAMPLE action according to data collected while composing ODP actions. + * We need to fix SAMPLE actions OVS_SAMPLE_ATTR_ACTIONS attribute, i.e. nested + * USERSPACE action's user-cookie which is required for sflow. */ +static void +fix_sflow_action(struct action_xlate_ctx *ctx) +{ + const struct flow *base = &ctx->base_flow; + struct user_action_cookie *cookie; + + if (!ctx->user_cookie_offset) { + return; + } + + cookie = ofpbuf_at(ctx->odp_actions, ctx->user_cookie_offset, + sizeof(*cookie)); + assert(cookie != NULL); + assert(cookie->type == USER_ACTION_COOKIE_SFLOW); + + if (ctx->sflow_n_outputs) { + cookie->data = dpif_sflow_odp_port_to_ifindex(ctx->ofproto->sflow, + ctx->sflow_odp_port); + } + if (ctx->sflow_n_outputs >= 255) { + cookie->n_output = 255; + } else { + cookie->n_output = ctx->sflow_n_outputs; + } + cookie->vlan_tci = base->vlan_tci; +} + static void commit_vlan_tci(struct action_xlate_ctx *ctx, ovs_be16 vlan_tci) { @@ -2963,6 +3136,14 @@ commit_odp_actions(struct action_xlate_ctx *ctx) } } +static void +compose_output_action(struct action_xlate_ctx *ctx, uint16_t odp_port) +{ + nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_OUTPUT, odp_port); + ctx->sflow_odp_port = odp_port; + ctx->sflow_n_outputs++; +} + static void add_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port) { @@ -2983,7 +3164,7 @@ add_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port) } commit_odp_actions(ctx); - nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_OUTPUT, odp_port); + compose_output_action(ctx, odp_port); ctx->nf_output_iface = ofp_port; } @@ -3064,14 +3245,27 @@ flood_packets(struct action_xlate_ctx *ctx, ovs_be32 mask) HMAP_FOR_EACH (ofport, up.hmap_node, &ctx->ofproto->up.ports) { uint16_t ofp_port = ofport->up.ofp_port; if (ofp_port != ctx->flow.in_port && !(ofport->up.opp.config & mask)) { - nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_OUTPUT, - ofport->odp_port); + compose_output_action(ctx, ofport->odp_port); } } ctx->nf_output_iface = NF_OUT_FLOOD; } +static void +compose_controller_action(struct ofpbuf *odp_actions, int len) +{ + struct user_action_cookie cookie; + + cookie.type = USER_ACTION_COOKIE_CONTROLLER; + cookie.data = len; + cookie.n_output = 0; + cookie.vlan_tci = 0; + + nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_USERSPACE, + &cookie, sizeof(cookie)); +} + static void xlate_output_action__(struct action_xlate_ctx *ctx, uint16_t port, uint16_t max_len) @@ -3098,7 +3292,7 @@ xlate_output_action__(struct action_xlate_ctx *ctx, break; case OFPP_CONTROLLER: commit_odp_actions(ctx); - nl_msg_put_u64(ctx->odp_actions, OVS_ACTION_ATTR_USERSPACE, max_len); + compose_controller_action(ctx->odp_actions, max_len); break; case OFPP_LOCAL: add_output_action(ctx, OFPP_LOCAL); @@ -3466,7 +3660,9 @@ xlate_actions(struct action_xlate_ctx *ctx, if (process_special(ctx->ofproto, &ctx->flow, ctx->packet)) { ctx->may_set_up_flow = false; } else { + add_sflow_action(ctx); do_xlate_actions(in, n_in, ctx); + fix_sflow_action(ctx); } /* Check with in-band control to see if we're allowed to set up this @@ -3499,20 +3695,71 @@ static void dst_set_free(struct dst_set *); static struct ofport_dpif *ofbundle_get_a_port(const struct ofbundle *); +/* Given 'vid', the VID obtained from the 802.1Q header that was received as + * part of a packet (specify 0 if there was no 802.1Q header), and 'in_bundle', + * the bundle on which the packet was received, returns the VLAN to which the + * packet belongs. + * + * Both 'vid' and the return value are in the range 0...4095. */ +static uint16_t +input_vid_to_vlan(const struct ofbundle *in_bundle, uint16_t vid) +{ + switch (in_bundle->vlan_mode) { + case PORT_VLAN_ACCESS: + return in_bundle->vlan; + break; + + case PORT_VLAN_TRUNK: + return vid; + + case PORT_VLAN_NATIVE_UNTAGGED: + case PORT_VLAN_NATIVE_TAGGED: + return vid ? vid : in_bundle->vlan; + + default: + NOT_REACHED(); + } +} + +/* Given 'vlan', the VLAN that a packet belongs to, and + * 'out_bundle', a bundle on which the packet is to be output, returns the VID + * that should be included in the 802.1Q header. (If the return value is 0, + * then the 802.1Q header should only be included in the packet if there is a + * nonzero PCP.) + * + * Both 'vlan' and the return value are in the range 0...4095. */ +static uint16_t +output_vlan_to_vid(const struct ofbundle *out_bundle, uint16_t vlan) +{ + switch (out_bundle->vlan_mode) { + case PORT_VLAN_ACCESS: + return 0; + + case PORT_VLAN_TRUNK: + case PORT_VLAN_NATIVE_TAGGED: + return vlan; + + case PORT_VLAN_NATIVE_UNTAGGED: + return vlan == out_bundle->vlan ? 0 : vlan; + + default: + NOT_REACHED(); + } +} + static bool set_dst(struct action_xlate_ctx *ctx, struct dst *dst, const struct ofbundle *in_bundle, const struct ofbundle *out_bundle) { - dst->vid = (out_bundle->vlan >= 0 ? 0 - : in_bundle->vlan >= 0 ? in_bundle->vlan - : ctx->flow.vlan_tci == 0 ? 0 - : vlan_tci_to_vid(ctx->flow.vlan_tci)); + uint16_t vlan; + + vlan = input_vid_to_vlan(in_bundle, vlan_tci_to_vid(ctx->flow.vlan_tci)); + dst->vid = output_vlan_to_vid(out_bundle, vlan); dst->port = (!out_bundle->bond ? ofbundle_get_a_port(out_bundle) : bond_choose_output_slave(out_bundle->bond, &ctx->flow, dst->vid, &ctx->tags)); - return dst->port != NULL; } @@ -3574,7 +3821,7 @@ dst_is_duplicate(const struct dst_set *set, const struct dst *test) static bool ofbundle_trunks_vlan(const struct ofbundle *bundle, uint16_t vlan) { - return (bundle->vlan < 0 + return (bundle->vlan_mode != PORT_VLAN_ACCESS && (!bundle->trunks || bitmap_is_set(bundle->trunks, vlan))); } @@ -3702,19 +3949,14 @@ compose_mirror_dsts(struct action_xlate_ctx *ctx, if (ofbundle_includes_vlan(bundle, m->out_vlan) && set_dst(ctx, &dst, in_bundle, bundle)) { - if (bundle->vlan < 0) { - dst.vid = m->out_vlan; - } + /* set_dst() got dst->vid from the input packet's VLAN, + * not from m->out_vlan, so recompute it. */ + dst.vid = output_vlan_to_vid(bundle, m->out_vlan); + if (dst_is_duplicate(set, &dst)) { continue; } - /* Use the vlan tag on the original flow instead of - * the one passed in the vlan parameter. This ensures - * that we compare the vlan from before any implicit - * tagging tags place. This is necessary because - * dst->vlan is the final vlan, after removing implicit - * tags. */ if (bundle == in_bundle && dst.vid == flow_vid) { /* Don't send out input port on same VLAN. */ continue; @@ -3752,8 +3994,7 @@ compose_actions(struct action_xlate_ctx *ctx, uint16_t vlan, if (dst->vid != initial_vid) { continue; } - nl_msg_put_u32(ctx->odp_actions, - OVS_ACTION_ATTR_OUTPUT, dst->port->odp_port); + compose_output_action(ctx, dst->port->odp_port); } /* Then output the rest. */ @@ -3774,8 +4015,7 @@ compose_actions(struct action_xlate_ctx *ctx, uint16_t vlan, cur_vid = dst->vid; } - nl_msg_put_u32(ctx->odp_actions, - OVS_ACTION_ATTR_OUTPUT, dst->port->odp_port); + compose_output_action(ctx, dst->port->odp_port); } dst_set_free(&set); @@ -3790,8 +4030,9 @@ flow_get_vlan(struct ofproto_dpif *ofproto, const struct flow *flow, struct ofbundle *in_bundle, bool have_packet) { int vlan = vlan_tci_to_vid(flow->vlan_tci); - if (in_bundle->vlan >= 0) { - if (vlan) { + if (vlan) { + if (in_bundle->vlan_mode == PORT_VLAN_ACCESS) { + /* Drop tagged packet on access port */ if (have_packet) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "bridge %s: dropping VLAN %d tagged " @@ -3801,10 +4042,10 @@ flow_get_vlan(struct ofproto_dpif *ofproto, const struct flow *flow, in_bundle->name, in_bundle->vlan); } return -1; - } - vlan = in_bundle->vlan; - } else { - if (!ofbundle_includes_vlan(in_bundle, vlan)) { + } else if (ofbundle_includes_vlan(in_bundle, vlan)) { + return vlan; + } else { + /* Drop packets from a VLAN not member of the trunk */ if (have_packet) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "bridge %s: dropping VLAN %d tagged " @@ -3814,9 +4055,13 @@ flow_get_vlan(struct ofproto_dpif *ofproto, const struct flow *flow, } return -1; } + } else { + if (in_bundle->vlan_mode != PORT_VLAN_TRUNK) { + return in_bundle->vlan; + } else { + return ofbundle_includes_vlan(in_bundle, 0) ? 0 : -1; + } } - - return vlan; } /* A VM broadcasts a gratuitous ARP to indicate that it has resumed after @@ -4446,11 +4691,13 @@ ofproto_dpif_unixctl_init(void) } registered = true; - unixctl_command_register("ofproto/trace", ofproto_unixctl_trace, NULL); - unixctl_command_register("fdb/show", ofproto_unixctl_fdb_show, NULL); - - unixctl_command_register("ofproto/clog", ofproto_dpif_clog, NULL); - unixctl_command_register("ofproto/unclog", ofproto_dpif_unclog, NULL); + unixctl_command_register("ofproto/trace", + "bridge {tun_id in_port packet | odp_flow [-generate]}", + ofproto_unixctl_trace, NULL); + unixctl_command_register("fdb/show", "bridge", ofproto_unixctl_fdb_show, + NULL); + unixctl_command_register("ofproto/clog", "", ofproto_dpif_clog, NULL); + unixctl_command_register("ofproto/unclog", "", ofproto_dpif_unclog, NULL); } const struct ofproto_class ofproto_dpif_class = {