X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=vswitchd%2Fbridge.c;h=07daacdb6ac7ce3471da5a491c11896ae3424599;hb=00c08589876b7c1cd8f57e5ebb3e66bb164c5a3d;hp=115c498e82a0db9c9d8b197cd0fa7775e27189e4;hpb=d55c25660b7dbedda886207a303895609c8407ef;p=openvswitch diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 115c498e..07daacdb 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -2098,51 +2098,6 @@ set_dst(struct dst *dst, const struct flow *flow, return dst->iface != NULL; } -static void -swap_dst(struct dst *p, struct dst *q) -{ - struct dst tmp = *p; - *p = *q; - *q = tmp; -} - -/* Moves all the dsts with vlan == 'vlan' to the front of the 'n_dsts' in - * 'dsts'. (This may help performance by reducing the number of VLAN changes - * that we push to the datapath. We could in fact fully sort the array by - * vlan, but in most cases there are at most two different vlan tags so that's - * possibly overkill.) */ -static void -partition_dsts(struct dst_set *set, int vlan) -{ - struct dst *first = set->dsts; - struct dst *last = set->dsts + set->n; - - while (first != last) { - /* Invariants: - * - All dsts < first have vlan == 'vlan'. - * - All dsts >= last have vlan != 'vlan'. - * - first < last. */ - while (first->vlan == vlan) { - if (++first == last) { - return; - } - } - - /* Same invariants, plus one additional: - * - first->vlan != vlan. - */ - while (last[-1].vlan != vlan) { - if (--last == first) { - return; - } - } - - /* Same invariants, plus one additional: - * - last[-1].vlan == vlan.*/ - swap_dst(first++, --last); - } -} - static int mirror_mask_ffs(mirror_mask_t mask) { @@ -2237,14 +2192,7 @@ compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan, const struct port *in_port, const struct port *out_port, struct dst_set *set, tag_type *tags, uint16_t *nf_output_iface) { - mirror_mask_t mirrors = in_port->src_mirrors; struct dst dst; - int flow_vlan; - - flow_vlan = vlan_tci_to_vid(flow->vlan_tci); - if (flow_vlan == 0) { - flow_vlan = OFP_VLAN_NONE; - } if (out_port == FLOOD_PORT) { struct port *port; @@ -2255,7 +2203,6 @@ compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan, && port_includes_vlan(port, vlan) && !port->is_mirror_output_port && set_dst(&dst, flow, in_port, port, tags)) { - mirrors |= port->dst_mirrors; dst_set_add(set, &dst); } } @@ -2263,12 +2210,37 @@ compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan, } else if (out_port && set_dst(&dst, flow, in_port, out_port, tags)) { dst_set_add(set, &dst); *nf_output_iface = dst.iface->dp_ifidx; - mirrors |= out_port->dst_mirrors; + } +} + +static void +compose_mirror_dsts(const struct bridge *br, const struct flow *flow, + uint16_t vlan, const struct port *in_port, + struct dst_set *set, tag_type *tags) +{ + mirror_mask_t mirrors; + int flow_vlan; + size_t i; + + mirrors = in_port->src_mirrors; + for (i = 0; i < set->n; i++) { + mirrors |= set->dsts[i].iface->port->dst_mirrors; + } + + if (!mirrors) { + return; + } + + flow_vlan = vlan_tci_to_vid(flow->vlan_tci); + if (flow_vlan == 0) { + flow_vlan = OFP_VLAN_NONE; } while (mirrors) { struct mirror *m = br->mirrors[mirror_mask_ffs(mirrors) - 1]; if (!m->n_vlans || vlan_is_mirrored(m, vlan)) { + struct dst dst; + if (m->out_port) { if (set_dst(&dst, flow, in_port, m->out_port, tags) && !dst_is_duplicate(set, &dst)) { @@ -2305,8 +2277,6 @@ compose_dsts(const struct bridge *br, const struct flow *flow, uint16_t vlan, } mirrors &= mirrors - 1; } - - partition_dsts(set, flow_vlan); } static void @@ -2315,20 +2285,33 @@ compose_actions(struct bridge *br, const struct flow *flow, uint16_t vlan, tag_type *tags, struct ofpbuf *actions, uint16_t *nf_output_iface) { + uint16_t initial_vlan, cur_vlan; + const struct dst *dst; struct dst_set set; - uint16_t cur_vlan; - size_t i; dst_set_init(&set); compose_dsts(br, flow, vlan, in_port, out_port, &set, tags, nf_output_iface); + compose_mirror_dsts(br, flow, vlan, in_port, &set, tags); - cur_vlan = vlan_tci_to_vid(flow->vlan_tci); - if (cur_vlan == 0) { - cur_vlan = OFP_VLAN_NONE; + /* Output all the packets we can without having to change the VLAN. */ + initial_vlan = vlan_tci_to_vid(flow->vlan_tci); + if (initial_vlan == 0) { + initial_vlan = OFP_VLAN_NONE; + } + for (dst = set.dsts; dst < &set.dsts[set.n]; dst++) { + if (dst->vlan != initial_vlan) { + continue; + } + nl_msg_put_u32(actions, ODP_ACTION_ATTR_OUTPUT, dst->iface->dp_ifidx); } - for (i = 0; i < set.n; i++) { - const struct dst *dst = &set.dsts[i]; + + /* Then output the rest. */ + cur_vlan = initial_vlan; + for (dst = set.dsts; dst < &set.dsts[set.n]; dst++) { + if (dst->vlan == initial_vlan) { + continue; + } if (dst->vlan != cur_vlan) { if (dst->vlan == OFP_VLAN_NONE) { nl_msg_put_flag(actions, ODP_ACTION_ATTR_STRIP_VLAN); @@ -2342,6 +2325,7 @@ compose_actions(struct bridge *br, const struct flow *flow, uint16_t vlan, } nl_msg_put_u32(actions, ODP_ACTION_ATTR_OUTPUT, dst->iface->dp_ifidx); } + dst_set_free(&set); }