ofproto-dpif: Use send_packet() instead of netdev_send().
authorJesse Gross <jesse@nicira.com>
Sun, 23 Oct 2011 00:22:11 +0000 (17:22 -0700)
committerJesse Gross <jesse@nicira.com>
Wed, 2 Nov 2011 23:36:49 +0000 (16:36 -0700)
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
lib/bond.h
ofproto/ofproto-dpif.c

index 73ee814..2b99b9a 100644 (file)
@@ -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;
 }
 \f
 /* Checks whether a packet that arrived on 'slave_' within 'bond', with an
index f955432..1958029 100644 (file)
@@ -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 {
index 93e79a9..9fdc489 100644 (file)
@@ -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++;