netdev: Extend rx_recv to pass multiple packets.
[sliver-openvswitch.git] / lib / netdev-bsd.c
index 689014b..cb99619 100644 (file)
@@ -49,6 +49,7 @@
 #include "rtbsd.h"
 #include "connectivity.h"
 #include "coverage.h"
+#include "dpif-netdev.h"
 #include "dynamic-string.h"
 #include "fatal-signal.h"
 #include "ofpbuf.h"
@@ -151,6 +152,7 @@ static int af_link_ioctl(unsigned long command, const void *arg);
 #endif
 
 static void netdev_bsd_run(void);
+static int netdev_bsd_get_mtu(const struct netdev *netdev_, int *mtup);
 
 static bool
 is_netdev_bsd_class(const struct netdev_class *netdev_class)
@@ -620,13 +622,32 @@ netdev_rx_bsd_recv_tap(struct netdev_rx_bsd *rx, struct ofpbuf *buffer)
 }
 
 static int
-netdev_bsd_rx_recv(struct netdev_rx *rx_, struct ofpbuf *buffer)
+netdev_bsd_rx_recv(struct netdev_rx *rx_, struct ofpbuf **packet, int *c)
 {
     struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_);
+    struct netdev *netdev = rx->up.netdev;
+    struct ofpbuf *buffer;
+    ssize_t retval;
+    int mtu;
+
+    if (netdev_bsd_get_mtu(netdev_bsd_cast(netdev), &mtu)) {
+        mtu = ETH_PAYLOAD_MAX;
+    }
 
-    return (rx->pcap_handle
+    buffer = ofpbuf_new_with_headroom(VLAN_ETH_HEADER_LEN + mtu, DP_NETDEV_HEADROOM);
+
+    retval = (rx->pcap_handle
             ? netdev_rx_bsd_recv_pcap(rx, buffer)
             : netdev_rx_bsd_recv_tap(rx, buffer));
+
+    if (retval) {
+        ofpbuf_delete(buffer);
+    } else {
+        dp_packet_pad(buffer);
+        packet[0] = buffer;
+        *c = 1;
+    }
+    return retval;
 }
 
 /*
@@ -863,7 +884,7 @@ netdev_bsd_get_carrier(const struct netdev *netdev_, bool *carrier)
 }
 
 static void
-convert_stats(struct netdev_stats *stats, const struct if_data *ifd)
+convert_stats_system(struct netdev_stats *stats, const struct if_data *ifd)
 {
     /*
      * note: UINT64_MAX means unsupported
@@ -891,6 +912,51 @@ convert_stats(struct netdev_stats *stats, const struct if_data *ifd)
     stats->tx_window_errors = UINT64_MAX;
 }
 
+static void
+convert_stats_tap(struct netdev_stats *stats, const struct if_data *ifd)
+{
+    /*
+     * Similar to convert_stats_system but swapping rx and tx
+     * because 'ifd' is stats for the network interface side of the
+     * tap device and what the caller wants is one for the character
+     * device side.
+     *
+     * note: UINT64_MAX means unsupported
+     */
+    stats->rx_packets = ifd->ifi_opackets;
+    stats->tx_packets = ifd->ifi_ipackets;
+    stats->rx_bytes = ifd->ifi_ibytes;
+    stats->tx_bytes = ifd->ifi_obytes;
+    stats->rx_errors = ifd->ifi_oerrors;
+    stats->tx_errors = ifd->ifi_ierrors;
+    stats->rx_dropped = UINT64_MAX;
+    stats->tx_dropped = ifd->ifi_iqdrops;
+    stats->multicast = ifd->ifi_omcasts;
+    stats->collisions = UINT64_MAX;
+    stats->rx_length_errors = UINT64_MAX;
+    stats->rx_over_errors = UINT64_MAX;
+    stats->rx_crc_errors = UINT64_MAX;
+    stats->rx_frame_errors = UINT64_MAX;
+    stats->rx_fifo_errors = UINT64_MAX;
+    stats->rx_missed_errors = UINT64_MAX;
+    stats->tx_aborted_errors = UINT64_MAX;
+    stats->tx_carrier_errors = UINT64_MAX;
+    stats->tx_fifo_errors = UINT64_MAX;
+    stats->tx_heartbeat_errors = UINT64_MAX;
+    stats->tx_window_errors = UINT64_MAX;
+}
+
+static void
+convert_stats(const struct netdev *netdev, struct netdev_stats *stats,
+              const struct if_data *ifd)
+{
+    if (netdev_bsd_cast(netdev)->tap_fd == -1) {
+        convert_stats_system(stats, ifd);
+    } else {
+        convert_stats_tap(stats, ifd);
+    }
+}
+
 /* Retrieves current device stats for 'netdev'. */
 static int
 netdev_bsd_get_stats(const struct netdev *netdev_, struct netdev_stats *stats)
@@ -926,7 +992,7 @@ netdev_bsd_get_stats(const struct netdev *netdev_, struct netdev_stats *stats)
                         netdev_get_name(netdev_), ovs_strerror(errno));
             return errno;
         } else if (!strcmp(ifmd.ifmd_name, netdev_get_name(netdev_))) {
-            convert_stats(stats, &ifmd.ifmd_data);
+            convert_stats(netdev, stats, &ifdr.ifdr_data);
             break;
         }
     }
@@ -941,7 +1007,7 @@ netdev_bsd_get_stats(const struct netdev *netdev_, struct netdev_stats *stats)
             sizeof(ifdr.ifdr_name));
     error = af_link_ioctl(SIOCGIFDATA, &ifdr);
     if (!error) {
-        convert_stats(stats, &ifdr.ifdr_data);
+        convert_stats(netdev_, stats, &ifdr.ifdr_data);
     }
     return error;
 #else
@@ -1460,132 +1526,85 @@ netdev_bsd_update_flags(struct netdev *netdev_, enum netdev_flags off,
     return error;
 }
 
+/* Linux has also different GET_STATS, SET_STATS,
+ * GET_STATUS)
+ */
+#define NETDEV_BSD_CLASS(NAME, CONSTRUCT,            \
+                         GET_FEATURES)               \
+{                                                    \
+    NAME,                                            \
+                                                     \
+    NULL, /* init */                                 \
+    netdev_bsd_run,                                  \
+    netdev_bsd_wait,                                 \
+    netdev_bsd_alloc,                                \
+    CONSTRUCT,                                       \
+    netdev_bsd_destruct,                             \
+    netdev_bsd_dealloc,                              \
+    NULL, /* get_config */                           \
+    NULL, /* set_config */                           \
+    NULL, /* get_tunnel_config */                    \
+                                                     \
+    netdev_bsd_send,                                 \
+    netdev_bsd_send_wait,                            \
+                                                     \
+    netdev_bsd_set_etheraddr,                        \
+    netdev_bsd_get_etheraddr,                        \
+    netdev_bsd_get_mtu,                              \
+    NULL, /* set_mtu */                              \
+    netdev_bsd_get_ifindex,                          \
+    netdev_bsd_get_carrier,                          \
+    NULL, /* get_carrier_resets */                   \
+    NULL, /* set_miimon_interval */                  \
+    netdev_bsd_get_stats,                            \
+    NULL, /* set_stats */                            \
+                                                     \
+    GET_FEATURES,                                    \
+    NULL, /* set_advertisement */                    \
+    NULL, /* set_policing */                         \
+    NULL, /* get_qos_type */                         \
+    NULL, /* get_qos_capabilities */                 \
+    NULL, /* get_qos */                              \
+    NULL, /* set_qos */                              \
+    NULL, /* get_queue */                            \
+    NULL, /* set_queue */                            \
+    NULL, /* delete_queue */                         \
+    NULL, /* get_queue_stats */                      \
+    NULL, /* queue_dump_start */                     \
+    NULL, /* queue_dump_next */                      \
+    NULL, /* queue_dump_done */                      \
+    NULL, /* dump_queue_stats */                     \
+                                                     \
+    netdev_bsd_get_in4,                              \
+    netdev_bsd_set_in4,                              \
+    netdev_bsd_get_in6,                              \
+    NULL, /* add_router */                           \
+    netdev_bsd_get_next_hop,                         \
+    NULL, /* get_status */                           \
+    netdev_bsd_arp_lookup, /* arp_lookup */          \
+                                                     \
+    netdev_bsd_update_flags,                         \
+                                                     \
+    netdev_bsd_rx_alloc,                             \
+    netdev_bsd_rx_construct,                         \
+    netdev_bsd_rx_destruct,                          \
+    netdev_bsd_rx_dealloc,                           \
+    netdev_bsd_rx_recv,                              \
+    netdev_bsd_rx_wait,                              \
+    netdev_bsd_rx_drain,                             \
+}
 
-const struct netdev_class netdev_bsd_class = {
-    "system",
-
-    NULL, /* init */
-    netdev_bsd_run,
-    netdev_bsd_wait,
-    netdev_bsd_alloc,
-    netdev_bsd_construct_system,
-    netdev_bsd_destruct,
-    netdev_bsd_dealloc,
-    NULL, /* get_config */
-    NULL, /* set_config */
-    NULL, /* get_tunnel_config */
-
-    netdev_bsd_send,
-    netdev_bsd_send_wait,
-
-    netdev_bsd_set_etheraddr,
-    netdev_bsd_get_etheraddr,
-    netdev_bsd_get_mtu,
-    NULL, /* set_mtu */
-    netdev_bsd_get_ifindex,
-    netdev_bsd_get_carrier,
-    NULL, /* get_carrier_resets */
-    NULL, /* set_miimon_interval */
-    netdev_bsd_get_stats,
-    NULL, /* set_stats */
-
-    netdev_bsd_get_features,
-    NULL, /* set_advertisement */
-    NULL, /* set_policing */
-    NULL, /* get_qos_type */
-    NULL, /* get_qos_capabilities */
-    NULL, /* get_qos */
-    NULL, /* set_qos */
-    NULL, /* get_queue */
-    NULL, /* set_queue */
-    NULL, /* delete_queue */
-    NULL, /* get_queue_stats */
-    NULL, /* queue_dump_start */
-    NULL, /* queue_dump_next */
-    NULL, /* queue_dump_done */
-    NULL, /* dump_queue_stats */
-
-    netdev_bsd_get_in4,
-    netdev_bsd_set_in4,
-    netdev_bsd_get_in6,
-    NULL, /* add_router */
-    netdev_bsd_get_next_hop,
-    NULL, /* get_status */
-    netdev_bsd_arp_lookup, /* arp_lookup */
-
-    netdev_bsd_update_flags,
-
-    netdev_bsd_rx_alloc,
-    netdev_bsd_rx_construct,
-    netdev_bsd_rx_destruct,
-    netdev_bsd_rx_dealloc,
-    netdev_bsd_rx_recv,
-    netdev_bsd_rx_wait,
-    netdev_bsd_rx_drain,
-};
-
-const struct netdev_class netdev_tap_class = {
-    "tap",
-
-    NULL, /* init */
-    netdev_bsd_run,
-    netdev_bsd_wait,
-    netdev_bsd_alloc,
-    netdev_bsd_construct_tap,
-    netdev_bsd_destruct,
-    netdev_bsd_dealloc,
-    NULL, /* get_config */
-    NULL, /* set_config */
-    NULL, /* get_tunnel_config */
-
-    netdev_bsd_send,
-    netdev_bsd_send_wait,
-
-    netdev_bsd_set_etheraddr,
-    netdev_bsd_get_etheraddr,
-    netdev_bsd_get_mtu,
-    NULL, /* set_mtu */
-    netdev_bsd_get_ifindex,
-    netdev_bsd_get_carrier,
-    NULL, /* get_carrier_resets */
-    NULL, /* set_miimon_interval */
-    netdev_bsd_get_stats,
-    NULL, /* set_stats */
-
-    netdev_bsd_get_features,
-    NULL, /* set_advertisement */
-    NULL, /* set_policing */
-    NULL, /* get_qos_type */
-    NULL, /* get_qos_capabilities */
-    NULL, /* get_qos */
-    NULL, /* set_qos */
-    NULL, /* get_queue */
-    NULL, /* set_queue */
-    NULL, /* delete_queue */
-    NULL, /* get_queue_stats */
-    NULL, /* queue_dump_start */
-    NULL, /* queue_dump_next */
-    NULL, /* queue_dump_done */
-    NULL, /* dump_queue_stats */
-
-    netdev_bsd_get_in4,
-    netdev_bsd_set_in4,
-    netdev_bsd_get_in6,
-    NULL, /* add_router */
-    netdev_bsd_get_next_hop,
-    NULL, /* get_status */
-    netdev_bsd_arp_lookup, /* arp_lookup */
-
-    netdev_bsd_update_flags,
-
-    netdev_bsd_rx_alloc,
-    netdev_bsd_rx_construct,
-    netdev_bsd_rx_destruct,
-    netdev_bsd_rx_dealloc,
-    netdev_bsd_rx_recv,
-    netdev_bsd_rx_wait,
-    netdev_bsd_rx_drain,
-};
+const struct netdev_class netdev_bsd_class =
+    NETDEV_BSD_CLASS(
+        "system",
+        netdev_bsd_construct_system,
+        netdev_bsd_get_features);
+
+const struct netdev_class netdev_tap_class =
+    NETDEV_BSD_CLASS(
+        "tap",
+        netdev_bsd_construct_tap,
+        netdev_bsd_get_features);
 \f
 
 static void