static int expire(struct ofproto_dpif *);
/* Utilities. */
-static int send_packet(struct ofproto_dpif *,
- uint32_t odp_port, uint16_t vlan_tci,
+static int send_packet(struct ofproto_dpif *, uint32_t odp_port,
const struct ofpbuf *packet);
/* Global variables. */
{
struct ofbundle *bundle = port->bundle;
+ bundle->ofproto->need_revalidate = true;
+
list_remove(&port->bundle_node);
port->bundle = NULL;
}
if (port->bundle != bundle) {
+ bundle->ofproto->need_revalidate = true;
if (port->bundle) {
bundle_del_port(port);
}
LIST_FOR_EACH_SAFE (port, next_port, bundle_node, &bundle->ports) {
for (i = 0; i < s->n_slaves; i++) {
- if (s->slaves[i] == odp_port_to_ofp_port(port->odp_port)) {
+ if (s->slaves[i] == port->up.ofp_port) {
goto found;
}
}
}
} else {
bundle->bond = bond_create(s->bond);
+ ofproto->need_revalidate = true;
}
LIST_FOR_EACH (port, bundle_node, &bundle->ports) {
ETH_TYPE_CFM, sizeof *ccm);
cfm_compose_ccm(ofport->cfm, ccm);
send_packet(ofproto_dpif_cast(ofport->up.ofproto),
- ofport->odp_port, 0, &packet);
+ ofport->odp_port, &packet);
ofpbuf_uninit(&packet);
}
}
/* Check with in-band control to see if this packet should be sent
* to the local port regardless of the flow table. */
if (connmgr_msg_in_hook(ofproto->up.connmgr, &flow, upcall->packet)) {
- send_packet(ofproto, OFPP_LOCAL, 0, upcall->packet);
+ send_packet(ofproto, ODPP_LOCAL, upcall->packet);
}
facet = facet_lookup_valid(ofproto, &flow);
}
}
+static int
+vlan_tci_to_openflow_vlan(ovs_be16 vlan_tci)
+{
+ return vlan_tci != htons(0) ? vlan_tci_to_vid(vlan_tci) : OFP_VLAN_NONE;
+}
+
static void
facet_account(struct ofproto_dpif *ofproto,
struct facet *facet, uint64_t extra_bytes)
const struct nlattr *a;
tag_type dummy = 0;
unsigned int left;
+ ovs_be16 vlan_tci;
int vlan;
total_bytes = facet->byte_count + extra_bytes;
if (!ofproto->has_bonded_bundles) {
return;
}
+
+ /* This loop feeds byte counters to bond_account() for rebalancing to use
+ * as a basis. We also need to track the actual VLAN on which the packet
+ * is going to be sent to ensure that it matches the one passed to
+ * bond_choose_output_slave(). (Otherwise, we will account to the wrong
+ * hash bucket.) */
+ vlan_tci = facet->flow.vlan_tci;
NL_ATTR_FOR_EACH_UNSAFE (a, left, facet->actions, facet->actions_len) {
- if (nl_attr_type(a) == ODP_ACTION_ATTR_OUTPUT) {
- struct ofport_dpif *port;
+ struct ofport_dpif *port;
+ switch (nl_attr_type(a)) {
+ case ODP_ACTION_ATTR_OUTPUT:
port = get_odp_port(ofproto, nl_attr_get_u32(a));
if (port && port->bundle && port->bundle->bond) {
- bond_account(port->bundle->bond, &facet->flow, vlan, n_bytes);
+ bond_account(port->bundle->bond, &facet->flow,
+ vlan_tci_to_openflow_vlan(vlan_tci), n_bytes);
}
+ break;
+
+ case ODP_ACTION_ATTR_STRIP_VLAN:
+ vlan_tci = htons(0);
+ break;
+
+ case ODP_ACTION_ATTR_SET_DL_TCI:
+ vlan_tci = nl_attr_get_be16(a);
+ break;
}
}
}
return error;
}
\f
-/* Sends 'packet' out of port 'odp_port' within 'ofproto'. If 'vlan_tci' is
- * zero the packet will not have any 802.1Q hader; if it is nonzero, then the
- * packet will be sent with the VLAN TCI specified by 'vlan_tci & ~VLAN_CFI'.
- *
+/* Sends 'packet' out of port 'odp_port' within 'p'.
* Returns 0 if successful, otherwise a positive errno value. */
static int
-send_packet(struct ofproto_dpif *ofproto, uint32_t odp_port, uint16_t vlan_tci,
+send_packet(struct ofproto_dpif *ofproto, uint32_t odp_port,
const struct ofpbuf *packet)
{
struct ofpbuf odp_actions;
int error;
ofpbuf_init(&odp_actions, 32);
- if (vlan_tci != 0) {
- nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_SET_DL_TCI,
- ntohs(vlan_tci & ~VLAN_CFI));
- }
nl_msg_put_u32(&odp_actions, ODP_ACTION_ATTR_OUTPUT, odp_port);
error = dpif_execute(ofproto->dpif, odp_actions.data, odp_actions.size,
packet);