netdev: Improve comments on netdev_rxq_recv().
[cascardo/ovs.git] / lib / netdev.c
index 149b39a..150f8d8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
 #include "netdev-dpdk.h"
 #include "netdev-provider.h"
 #include "netdev-vport.h"
+#include "odp-netlink.h"
 #include "openflow/openflow.h"
 #include "packets.h"
 #include "poll-loop.h"
@@ -43,6 +44,7 @@
 #include "sset.h"
 #include "svec.h"
 #include "openvswitch/vlog.h"
+#include "flow.h"
 
 VLOG_DEFINE_THIS_MODULE(netdev);
 
@@ -104,12 +106,19 @@ netdev_n_rxq(const struct netdev *netdev)
     return netdev->n_rxq;
 }
 
+int
+netdev_requested_n_rxq(const struct netdev *netdev)
+{
+    return netdev->requested_n_rxq;
+}
+
 bool
 netdev_is_pmd(const struct netdev *netdev)
 {
     return (!strcmp(netdev->netdev_class->type, "dpdk") ||
             !strcmp(netdev->netdev_class->type, "dpdkr") ||
-            !strcmp(netdev->netdev_class->type, "dpdkvhost"));
+            !strcmp(netdev->netdev_class->type, "dpdkvhostcuse") ||
+            !strcmp(netdev->netdev_class->type, "dpdkvhostuser"));
 }
 
 static void
@@ -255,6 +264,8 @@ netdev_unregister_provider(const char *type)
     struct netdev_registered_class *rc;
     int error;
 
+    netdev_initialize();
+
     ovs_mutex_lock(&netdev_class_mutex);
     rc = netdev_lookup_class(type);
     if (!rc) {
@@ -371,6 +382,7 @@ netdev_open(const char *name, const char *type, struct netdev **netdevp)
                 /* By default enable one tx and rx queue per netdev. */
                 netdev->n_txq = netdev->netdev_class->send ? 1 : 0;
                 netdev->n_rxq = netdev->netdev_class->rxq_alloc ? 1 : 0;
+                netdev->requested_n_rxq = netdev->n_rxq;
 
                 list_init(&netdev->saved_flags_list);
 
@@ -627,28 +639,28 @@ netdev_rxq_close(struct netdev_rxq *rx)
     }
 }
 
-/* Attempts to receive batch of packets from 'rx'.
- *
- * Returns EAGAIN immediately if no packet is ready to be received.
+/* Attempts to receive a batch of packets from 'rx'.  'pkts' should point to
+ * the beginning of an array of MAX_RX_BATCH pointers to dp_packet.  If
+ * successful, this function stores pointers to up to MAX_RX_BATCH dp_packets
+ * into the array, transferring ownership of the packets to the caller, stores
+ * the number of received packets into '*cnt', and returns 0.
  *
- * Returns EMSGSIZE, and discards the packet, if the received packet is longer
- * than 'dp_packet_tailroom(buffer)'.
+ * The implementation does not necessarily initialize any non-data members of
+ * 'pkts'.  That is, the caller must initialize layer pointers and metadata
+ * itself, if desired, e.g. with pkt_metadata_init() and miniflow_extract().
  *
- * It is advised that the tailroom of 'buffer' should be
- * VLAN_HEADER_LEN bytes longer than the MTU to allow space for an
- * out-of-band VLAN header to be added to the packet.  At the very least,
- * 'buffer' must have at least ETH_TOTAL_MIN bytes of tailroom.
- *
- * This function may be set to null if it would always return EOPNOTSUPP
- * anyhow. */
+ * Returns EAGAIN immediately if no packet is ready to be received or another
+ * positive errno value if an error was encountered. */
 int
-netdev_rxq_recv(struct netdev_rxq *rx, struct dp_packet **buffers, int *cnt)
+netdev_rxq_recv(struct netdev_rxq *rx, struct dp_packet **pkts, int *cnt)
 {
     int retval;
 
-    retval = rx->netdev->netdev_class->rxq_recv(rx, buffers, cnt);
+    retval = rx->netdev->netdev_class->rxq_recv(rx, pkts, cnt);
     if (!retval) {
         COVERAGE_INC(netdev_received);
+    } else {
+        *cnt = 0;
     }
     return retval;
 }
@@ -673,6 +685,16 @@ netdev_rxq_drain(struct netdev_rxq *rx)
 /* Configures the number of tx queues and rx queues of 'netdev'.
  * Return 0 if successful, otherwise a positive errno value.
  *
+ * 'n_rxq' specifies the maximum number of receive queues to create.
+ * The netdev provider might choose to create less (e.g. if the hardware
+ * supports only a smaller number).  The caller can check how many have been
+ * actually created by calling 'netdev_n_rxq()'
+ *
+ * 'n_txq' specifies the exact number of transmission queues to create.
+ * If this function returns successfully, the caller can make 'n_txq'
+ * concurrent calls to netdev_send() (each one with a different 'qid' in the
+ * range [0..'n_txq'-1]).
+ *
  * On error, the tx queue and rx queue configuration is indeterminant.
  * Caller should make decision on whether to restore the previous or
  * the default configuration.  Also, caller must make sure there is no
@@ -706,7 +728,9 @@ netdev_set_multiq(struct netdev *netdev, unsigned int n_txq,
  * If the function returns a non-zero value, some of the packets might have
  * been sent anyway.
  *
- * To retain ownership of 'buffer' caller can set may_steal to false.
+ * If 'may_steal' is false, the caller retains ownership of all the packets.
+ * If 'may_steal' is true, the caller transfers ownership of all the packets
+ * to the network device, regardless of success.
  *
  * The network device is expected to maintain one or more packet
  * transmission queues, so that the caller does not ordinarily have to
@@ -720,11 +744,17 @@ int
 netdev_send(struct netdev *netdev, int qid, struct dp_packet **buffers,
             int cnt, bool may_steal)
 {
-    int error;
+    if (!netdev->netdev_class->send) {
+        if (may_steal) {
+            for (int i = 0; i < cnt; i++) {
+                dp_packet_delete(buffers[i]);
+            }
+        }
+        return EOPNOTSUPP;
+    }
 
-    error = (netdev->netdev_class->send
-             ? netdev->netdev_class->send(netdev, qid, buffers, cnt, may_steal)
-             : EOPNOTSUPP);
+    int error = netdev->netdev_class->send(netdev, qid, buffers, cnt,
+                                           may_steal);
     if (!error) {
         COVERAGE_INC(netdev_sent);
     }
@@ -734,16 +764,30 @@ netdev_send(struct netdev *netdev, int qid, struct dp_packet **buffers,
 int
 netdev_pop_header(struct netdev *netdev, struct dp_packet **buffers, int cnt)
 {
-    return (netdev->netdev_class->pop_header
-             ? netdev->netdev_class->pop_header(netdev, buffers, cnt)
-             : EOPNOTSUPP);
+    int i;
+
+    if (!netdev->netdev_class->pop_header) {
+        return EOPNOTSUPP;
+    }
+
+    for (i = 0; i < cnt; i++) {
+        int err;
+
+        err = netdev->netdev_class->pop_header(buffers[i]);
+        if (err) {
+            dp_packet_clear(buffers[i]);
+        }
+    }
+
+    return 0;
 }
 
 int
-netdev_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data)
+netdev_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data,
+                    const struct flow *tnl_flow)
 {
     if (netdev->netdev_class->build_header) {
-        return netdev->netdev_class->build_header(netdev, data);
+        return netdev->netdev_class->build_header(netdev, data, tnl_flow);
     }
     return EOPNOTSUPP;
 }
@@ -753,11 +797,18 @@ netdev_push_header(const struct netdev *netdev,
                    struct dp_packet **buffers, int cnt,
                    const struct ovs_action_push_tnl *data)
 {
-    if (netdev->netdev_class->push_header) {
-        return netdev->netdev_class->push_header(netdev, buffers, cnt, data);
-    } else {
+    int i;
+
+    if (!netdev->netdev_class->push_header) {
         return -EINVAL;
     }
+
+    for (i = 0; i < cnt; i++) {
+        netdev->netdev_class->push_header(buffers[i], data);
+        pkt_metadata_init(&buffers[i]->md, u32_to_odp(data->out_port));
+    }
+
+    return 0;
 }
 
 /* Registers with the poll loop to wake up from the next call to poll_block()
@@ -780,7 +831,7 @@ netdev_send_wait(struct netdev *netdev, int qid)
 /* Attempts to set 'netdev''s MAC address to 'mac'.  Returns 0 if successful,
  * otherwise a positive errno value. */
 int
-netdev_set_etheraddr(struct netdev *netdev, const uint8_t mac[ETH_ADDR_LEN])
+netdev_set_etheraddr(struct netdev *netdev, const struct eth_addr mac)
 {
     return netdev->netdev_class->set_etheraddr(netdev, mac);
 }
@@ -789,7 +840,7 @@ netdev_set_etheraddr(struct netdev *netdev, const uint8_t mac[ETH_ADDR_LEN])
  * the MAC address into 'mac'.  On failure, returns a positive errno value and
  * clears 'mac' to all-zeros. */
 int
-netdev_get_etheraddr(const struct netdev *netdev, uint8_t mac[ETH_ADDR_LEN])
+netdev_get_etheraddr(const struct netdev *netdev, struct eth_addr *mac)
 {
     return netdev->netdev_class->get_etheraddr(netdev, mac);
 }
@@ -1223,13 +1274,13 @@ netdev_restore_flags(struct netdev_saved_flags *sf)
  * ENXIO indicates that there is no ARP table entry for 'ip' on 'netdev'. */
 int
 netdev_arp_lookup(const struct netdev *netdev,
-                  ovs_be32 ip, uint8_t mac[ETH_ADDR_LEN])
+                  ovs_be32 ip, struct eth_addr *mac)
 {
     int error = (netdev->netdev_class->arp_lookup
                  ? netdev->netdev_class->arp_lookup(netdev, ip, mac)
                  : EOPNOTSUPP);
     if (error) {
-        memset(mac, 0, ETH_ADDR_LEN);
+        *mac = eth_addr_zero;
     }
     return error;
 }
@@ -1764,6 +1815,12 @@ netdev_rxq_get_name(const struct netdev_rxq *rx)
     return netdev_get_name(netdev_rxq_get_netdev(rx));
 }
 
+int
+netdev_rxq_get_queue_id(const struct netdev_rxq *rx)
+{
+    return rx->queue_id;
+}
+
 static void
 restore_all_flags(void *aux OVS_UNUSED)
 {