static bool
may_send_learning_packets(const struct bond *bond)
{
- return !bond->lacp_negotiated && bond->balance != BM_AB;
+ return !bond->lacp_negotiated && bond->balance != BM_AB &&
+ bond->active_slave;
}
/* Returns true if 'bond' needs the client to send out packets to assist with
* MAC learning on 'bond'. If this function returns true, then the client
* should iterate through its MAC learning table for the bridge on which 'bond'
* is located. For each MAC that has been learned on a port other than 'bond',
- * it should call bond_send_learning_packet().
+ * it should call bond_compose_learning_packet().
*
* This function will only return true if 'bond' is in SLB mode and LACP is not
* negotiated. Otherwise sending learning packets isn't necessary.
/* Sends a gratuitous learning packet on 'bond' from 'eth_src' on 'vlan'.
*
- * See bond_should_send_learning_packets() for description of usage. */
-int
-bond_send_learning_packet(struct bond *bond,
- const uint8_t eth_src[ETH_ADDR_LEN],
- uint16_t vlan)
+ * See bond_should_send_learning_packets() for description of usage. The
+ * caller should send the composed packet on the port associated with
+ * port_aux and takes ownership of the returned ofpbuf. */
+struct ofpbuf *
+bond_compose_learning_packet(struct bond *bond,
+ const uint8_t eth_src[ETH_ADDR_LEN],
+ uint16_t vlan, void **port_aux)
{
struct bond_slave *slave;
- struct ofpbuf packet;
+ struct ofpbuf *packet;
struct flow flow;
- int error;
assert(may_send_learning_packets(bond));
- if (!bond->active_slave) {
- /* Nowhere to send the learning packet. */
- return 0;
- }
memset(&flow, 0, sizeof flow);
memcpy(flow.dl_src, eth_src, ETH_ADDR_LEN);
slave = choose_output_slave(bond, &flow, vlan);
- ofpbuf_init(&packet, 0);
- compose_benign_packet(&packet, "Open vSwitch Bond Failover", 0xf177,
+ packet = ofpbuf_new(0);
+ compose_benign_packet(packet, "Open vSwitch Bond Failover", 0xf177,
eth_src);
if (vlan) {
- eth_push_vlan(&packet, htons(vlan));
+ eth_push_vlan(packet, htons(vlan));
}
- error = netdev_send(slave->netdev, &packet);
- ofpbuf_uninit(&packet);
- return error;
+ *port_aux = slave->aux;
+ return packet;
}
\f
/* Checks whether a packet that arrived on 'slave_' within 'bond', with an
/* Special MAC learning support for SLB bonding. */
bool bond_should_send_learning_packets(struct bond *);
-int bond_send_learning_packet(struct bond *,
- const uint8_t eth_src[ETH_ADDR_LEN],
- uint16_t vlan);
+struct ofpbuf *bond_compose_learning_packet(struct bond *,
+ const uint8_t eth_src[ETH_ADDR_LEN],
+ uint16_t vlan, void **port_aux);
/* Packet processing. */
enum bond_verdict {
VLOG_WARN_RL(&rl, "%s: cannot send BPDU on port %d "
"with unknown MAC", ofproto->up.name, port_num);
} else {
- int error = netdev_send(ofport->up.netdev, pkt);
- if (error) {
- VLOG_WARN_RL(&rl, "%s: sending BPDU on port %s failed (%s)",
- ofproto->up.name,
- netdev_get_name(ofport->up.netdev),
- strerror(error));
- }
+ send_packet(ofproto_dpif_cast(ofport->up.ofproto),
+ ofport->odp_port, pkt);
}
}
ofpbuf_delete(pkt);
pdu_size);
memcpy(packet_pdu, pdu, pdu_size);
- error = netdev_send(port->up.netdev, &packet);
- if (error) {
- VLOG_WARN_RL(&rl, "port %s: sending LACP PDU on iface %s failed "
- "(%s)", port->bundle->name,
- netdev_get_name(port->up.netdev), strerror(error));
- }
+ send_packet(ofproto_dpif_cast(port->up.ofproto), port->odp_port,
+ &packet);
ofpbuf_uninit(&packet);
} else {
VLOG_ERR_RL(&rl, "port %s: cannot obtain Ethernet address of iface "
error = n_packets = n_errors = 0;
LIST_FOR_EACH (e, lru_node, &ofproto->ml->lrus) {
if (e->port.p != bundle) {
- int ret = bond_send_learning_packet(bundle->bond, e->mac, e->vlan);
+ struct ofpbuf *learning_packet;
+ struct ofport_dpif *port;
+ int ret;
+
+ learning_packet = bond_compose_learning_packet(bundle->bond, e->mac,
+ e->vlan,
+ (void **)&port);
+ ret = send_packet(ofproto_dpif_cast(port->up.ofproto),
+ port->odp_port, learning_packet);
+ ofpbuf_delete(learning_packet);
if (ret) {
error = ret;
n_errors++;