From ea131871e4c8793ff90f60cfb5f45947d6a2c10b Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Sat, 22 Oct 2011 17:22:11 -0700 Subject: [PATCH] ofproto-dpif: Use send_packet() instead of netdev_send(). netdev_send() directly sends a packet using Linux mechanisms, skipping our kernel module. Several upper layer abstractions are built on top of the kernel module, so this means that we loose stats, sFlow, etc. on these packets. This changes bonding, LACP, and STP to use send_packet() as CFM does, which uses the standard kernel mechanisms and provides a single place that needs to be updated. --- lib/bond.c | 35 ++++++++++++++++------------------- lib/bond.h | 6 +++--- ofproto/ofproto-dpif.c | 28 ++++++++++++++-------------- 3 files changed, 33 insertions(+), 36 deletions(-) diff --git a/lib/bond.c b/lib/bond.c index 73ee814c..2b99b9ac 100644 --- a/lib/bond.c +++ b/lib/bond.c @@ -484,14 +484,15 @@ bond_wait(struct bond *bond) 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. @@ -507,37 +508,33 @@ bond_should_send_learning_packets(struct bond *bond) /* 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; } /* Checks whether a packet that arrived on 'slave_' within 'bond', with an diff --git a/lib/bond.h b/lib/bond.h index f9554326..19580298 100644 --- a/lib/bond.h +++ b/lib/bond.h @@ -75,9 +75,9 @@ void bond_slave_set_may_enable(struct bond *, void *slave_, bool may_enable); /* 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 { diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 93e79a97..9fdc489d 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -949,13 +949,8 @@ send_bpdu_cb(struct ofpbuf *pkt, int port_num, void *ofproto_) 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); @@ -1549,12 +1544,8 @@ send_pdu_cb(void *port_, const void *pdu, size_t pdu_size) 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 " @@ -1573,7 +1564,16 @@ bundle_send_learning_packets(struct ofbundle *bundle) 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++; -- 2.30.2