]> git.proxmox.com Git - mirror_ovs.git/blobdiff - lib/netdev-dummy.c
netdev: Remove useless cutlen.
[mirror_ovs.git] / lib / netdev-dummy.c
index 2e7b7e9df36e4bb04904e550f8a9de67a559c454..40086a377495e860b26c3a8025e5732700a621a3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2011, 2012, 2013, 2015, 2016 Nicira, Inc.
+ * Copyright (c) 2010, 2011, 2012, 2013, 2015, 2016, 2017 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,8 +35,8 @@
 #include "ovs-atomic.h"
 #include "packets.h"
 #include "pcap-file.h"
-#include "poll-loop.h"
-#include "shash.h"
+#include "openvswitch/poll-loop.h"
+#include "openvswitch/shash.h"
 #include "sset.h"
 #include "stream.h"
 #include "unaligned.h"
@@ -50,8 +50,8 @@ struct reconnect;
 
 struct dummy_packet_stream {
     struct stream *stream;
-    struct dp_packet rxbuf;
     struct ovs_list txq;
+    struct dp_packet rxbuf;
 };
 
 enum dummy_packet_conn_type {
@@ -622,12 +622,15 @@ dummy_netdev_get_conn_state(struct dummy_packet_conn *conn)
 }
 
 static void
-netdev_dummy_run(void)
+netdev_dummy_run(const struct netdev_class *netdev_class)
 {
     struct netdev_dummy *dev;
 
     ovs_mutex_lock(&dummy_list_mutex);
     LIST_FOR_EACH (dev, list_node, &dummy_list) {
+        if (netdev_get_class(&dev->up) != netdev_class) {
+            continue;
+        }
         ovs_mutex_lock(&dev->mutex);
         dummy_packet_conn_run(dev);
         ovs_mutex_unlock(&dev->mutex);
@@ -636,12 +639,15 @@ netdev_dummy_run(void)
 }
 
 static void
-netdev_dummy_wait(void)
+netdev_dummy_wait(const struct netdev_class *netdev_class)
 {
     struct netdev_dummy *dev;
 
     ovs_mutex_lock(&dummy_list_mutex);
     LIST_FOR_EACH (dev, list_node, &dummy_list) {
+        if (netdev_get_class(&dev->up) != netdev_class) {
+            continue;
+        }
         ovs_mutex_lock(&dev->mutex);
         dummy_packet_conn_wait(&dev->conn);
         ovs_mutex_unlock(&dev->mutex);
@@ -702,6 +708,12 @@ netdev_dummy_destruct(struct netdev *netdev_)
     ovs_mutex_unlock(&dummy_list_mutex);
 
     ovs_mutex_lock(&netdev->mutex);
+    if (netdev->rxq_pcap) {
+        fclose(netdev->rxq_pcap);
+    }
+    if (netdev->tx_pcap && netdev->tx_pcap != netdev->rxq_pcap) {
+        fclose(netdev->tx_pcap);
+    }
     dummy_packet_conn_close(&netdev->conn);
     netdev->conn.type = NONE;
 
@@ -821,8 +833,11 @@ netdev_dummy_set_in6(struct netdev *netdev_, struct in6_addr *in6,
     return 0;
 }
 
+#define DUMMY_MAX_QUEUES_PER_PORT 1024
+
 static int
-netdev_dummy_set_config(struct netdev *netdev_, const struct smap *args)
+netdev_dummy_set_config(struct netdev *netdev_, const struct smap *args,
+                        char **errp OVS_UNUSED)
 {
     struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
     const char *pcap;
@@ -862,8 +877,23 @@ netdev_dummy_set_config(struct netdev *netdev_, const struct smap *args)
         goto exit;
     }
 
-    new_n_rxq = MAX(smap_get_int(args, "n_rxq", netdev->requested_n_rxq), 1);
-    new_n_txq = MAX(smap_get_int(args, "n_txq", netdev->requested_n_txq), 1);
+    new_n_rxq = MAX(smap_get_int(args, "n_rxq", NR_QUEUE), 1);
+    new_n_txq = MAX(smap_get_int(args, "n_txq", NR_QUEUE), 1);
+
+    if (new_n_rxq > DUMMY_MAX_QUEUES_PER_PORT ||
+        new_n_txq > DUMMY_MAX_QUEUES_PER_PORT) {
+        VLOG_WARN("The one or both of interface %s queues"
+                  "(rxq: %d, txq: %d) exceed %d. Sets it %d.\n",
+                  netdev_get_name(netdev_),
+                  new_n_rxq,
+                  new_n_txq,
+                  DUMMY_MAX_QUEUES_PER_PORT,
+                  DUMMY_MAX_QUEUES_PER_PORT);
+
+        new_n_rxq = MIN(DUMMY_MAX_QUEUES_PER_PORT, new_n_rxq);
+        new_n_txq = MIN(DUMMY_MAX_QUEUES_PER_PORT, new_n_txq);
+    }
+
     new_numa_id = smap_get_int(args, "numa_id", 0);
     if (new_n_rxq != netdev->requested_n_rxq
         || new_n_txq != netdev->requested_n_txq
@@ -993,8 +1023,6 @@ netdev_dummy_rxq_recv(struct netdev_rxq *rxq_, struct dp_packet_batch *batch)
     netdev->stats.rx_bytes += dp_packet_size(packet);
     ovs_mutex_unlock(&netdev->mutex);
 
-    dp_packet_pad(packet);
-
     batch->packets[0] = packet;
     batch->count = 1;
     return 0;
@@ -1034,17 +1062,21 @@ netdev_dummy_rxq_drain(struct netdev_rxq *rxq_)
 
 static int
 netdev_dummy_send(struct netdev *netdev, int qid OVS_UNUSED,
-                  struct dp_packet_batch *batch, bool may_steal)
+                  struct dp_packet_batch *batch,
+                  bool concurrent_txq OVS_UNUSED)
 {
     struct netdev_dummy *dev = netdev_dummy_cast(netdev);
     int error = 0;
-    int i;
 
-    for (i = 0; i < batch->count; i++) {
-        const void *buffer = dp_packet_data(batch->packets[i]);
-        size_t size = dp_packet_size(batch->packets[i]);
+    struct dp_packet *packet;
+    DP_PACKET_BATCH_FOR_EACH(packet, batch) {
+        const void *buffer = dp_packet_data(packet);
+        size_t size = dp_packet_size(packet);
 
-        size -= dp_packet_get_cutlen(batch->packets[i]);
+        if (batch->packets[i]->packet_type != htonl(PT_ETH)) {
+            error = EPFNOSUPPORT;
+            break;
+        }
 
         if (size < ETH_HEADER_LEN) {
             error = EMSGSIZE;
@@ -1074,11 +1106,11 @@ netdev_dummy_send(struct netdev *netdev, int qid OVS_UNUSED,
 
         /* Reply to ARP requests for 'dev''s assigned IP address. */
         if (dev->address.s_addr) {
-            struct dp_packet packet;
+            struct dp_packet dp;
             struct flow flow;
 
-            dp_packet_use_const(&packet, buffer, size);
-            flow_extract(&packet, &flow);
+            dp_packet_use_const(&dp, buffer, size);
+            flow_extract(&dp, &flow);
             if (flow.dl_type == htons(ETH_TYPE_ARP)
                 && flow.nw_proto == ARP_OP_REQUEST
                 && flow.nw_dst == dev->address.s_addr) {
@@ -1090,17 +1122,17 @@ netdev_dummy_send(struct netdev *netdev, int qid OVS_UNUSED,
         }
 
         if (dev->tx_pcap) {
-            struct dp_packet packet;
+            struct dp_packet dp;
 
-            dp_packet_use_const(&packet, buffer, size);
-            ovs_pcap_write(dev->tx_pcap, &packet);
+            dp_packet_use_const(&dp, buffer, size);
+            ovs_pcap_write(dev->tx_pcap, &dp);
             fflush(dev->tx_pcap);
         }
 
         ovs_mutex_unlock(&dev->mutex);
     }
 
-    dp_packet_delete_batch(batch, may_steal);
+    dp_packet_delete_batch(batch, true);
 
     return error;
 }
@@ -1144,13 +1176,23 @@ netdev_dummy_get_mtu(const struct netdev *netdev, int *mtup)
     return 0;
 }
 
+#define DUMMY_MIN_MTU 68
+#define DUMMY_MAX_MTU 65535
+
 static int
-netdev_dummy_set_mtu(const struct netdev *netdev, int mtu)
+netdev_dummy_set_mtu(struct netdev *netdev, int mtu)
 {
+    if (mtu < DUMMY_MIN_MTU || mtu > DUMMY_MAX_MTU) {
+        return EINVAL;
+    }
+
     struct netdev_dummy *dev = netdev_dummy_cast(netdev);
 
     ovs_mutex_lock(&dev->mutex);
-    dev->mtu = mtu;
+    if (dev->mtu != mtu) {
+        dev->mtu = mtu;
+        netdev_change_seq_changed(netdev);
+    }
     ovs_mutex_unlock(&dev->mutex);
 
     return 0;
@@ -1344,6 +1386,7 @@ netdev_dummy_update_flags(struct netdev *netdev_,
                                                                 \
     NULL,                       /* get_features */              \
     NULL,                       /* set_advertisements */        \
+    NULL,                       /* get_pt_mode */               \
                                                                 \
     NULL,                       /* set_policing */              \
     NULL,                       /* get_qos_types */             \
@@ -1376,11 +1419,16 @@ netdev_dummy_update_flags(struct netdev *netdev_,
     netdev_dummy_rxq_recv,                                      \
     netdev_dummy_rxq_wait,                                      \
     netdev_dummy_rxq_drain,                                     \
+                                                                \
+    NO_OFFLOAD_API                                              \
 }
 
 static const struct netdev_class dummy_class =
     NETDEV_DUMMY_CLASS("dummy", false, NULL);
 
+static const struct netdev_class dummy_internal_class =
+    NETDEV_DUMMY_CLASS("dummy-internal", false, NULL);
+
 static const struct netdev_class dummy_pmd_class =
     NETDEV_DUMMY_CLASS("dummy-pmd", true,
                        netdev_dummy_reconfigure);
@@ -1397,7 +1445,15 @@ pkt_list_delete(struct ovs_list *l)
 }
 
 static struct dp_packet *
-eth_from_packet_or_flow(const char *s)
+eth_from_packet(const char *s)
+{
+    struct dp_packet *packet;
+    eth_from_hex(s, &packet);
+    return packet;
+}
+
+static struct dp_packet *
+eth_from_flow(const char *s, size_t packet_size)
 {
     enum odp_key_fitness fitness;
     struct dp_packet *packet;
@@ -1405,10 +1461,6 @@ eth_from_packet_or_flow(const char *s)
     struct flow flow;
     int error;
 
-    if (!eth_from_hex(s, &packet)) {
-        return packet;
-    }
-
     /* Convert string to datapath key.
      *
      * It would actually be nicer to parse an OpenFlow-like flow key here, but
@@ -1430,7 +1482,10 @@ eth_from_packet_or_flow(const char *s)
     }
 
     packet = dp_packet_new(0);
-    flow_compose(packet, &flow);
+    if (!flow_compose(packet, &flow, packet_size)) {
+        dp_packet_delete(packet);
+        packet = NULL;
+    };
 
     ofpbuf_uninit(&odp_key);
     return packet;
@@ -1504,10 +1559,30 @@ netdev_dummy_receive(struct unixctl_conn *conn,
     for (i = k; i < argc; i++) {
         struct dp_packet *packet;
 
-        packet = eth_from_packet_or_flow(argv[i]);
+        /* Try to parse 'argv[i]' as packet in hex. */
+        packet = eth_from_packet(argv[i]);
+
         if (!packet) {
-            unixctl_command_reply_error(conn, "bad packet syntax");
-            goto exit;
+            int packet_size = 0;
+            const char *flow_str = argv[i];
+
+            /* Parse optional --len argument immediately follows a 'flow'.  */
+            if (argc >= i + 2 && !strcmp(argv[i + 1], "--len")) {
+                packet_size = strtol(argv[i + 2], NULL, 10);
+
+                if (packet_size < ETH_TOTAL_MIN) {
+                    unixctl_command_reply_error(conn, "too small packet len");
+                    goto exit;
+                }
+                i += 2;
+            }
+            /* Try parse 'argv[i]' as odp flow. */
+            packet = eth_from_flow(flow_str, packet_size);
+
+            if (!packet) {
+                unixctl_command_reply_error(conn, "bad packet or flow syntax");
+                goto exit;
+            }
         }
 
         netdev_dummy_queue_packet(dummy_dev, packet, rx_qid);
@@ -1689,7 +1764,6 @@ netdev_dummy_ip6addr(struct unixctl_conn *conn, int argc OVS_UNUSED,
             unixctl_command_reply_error(conn, error);
             free(error);
         }
-        netdev_close(netdev);
     } else {
         unixctl_command_reply_error(conn, "Unknown Dummy Interface");
     }
@@ -1721,7 +1795,7 @@ void
 netdev_dummy_register(enum dummy_level level)
 {
     unixctl_command_register("netdev-dummy/receive",
-                             "name [--qid queue_id] packet|flow...",
+                             "name [--qid queue_id] packet|flow [--len packet_len]",
                              2, INT_MAX, netdev_dummy_receive, NULL);
     unixctl_command_register("netdev-dummy/set-admin-state",
                              "[netdev] up|down", 1, 2,
@@ -1752,6 +1826,7 @@ netdev_dummy_register(enum dummy_level level)
         netdev_dummy_override("system");
     }
     netdev_register_provider(&dummy_class);
+    netdev_register_provider(&dummy_internal_class);
     netdev_register_provider(&dummy_pmd_class);
 
     netdev_vport_tunnel_register();