Merge commit '796223f5bc3a4896e6398733c798390158479400'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Fri, 5 Jul 2013 17:55:33 +0000 (19:55 +0200)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Fri, 5 Jul 2013 17:55:33 +0000 (19:55 +0200)
1  2 
lib/dpif-netdev.c
lib/netdev-provider.h
lib/netdev.c

diff --combined lib/dpif-netdev.c
@@@ -107,6 -107,7 +107,7 @@@ struct dp_netdev_port 
      struct list node;           /* Element in dp_netdev's 'port_list'. */
      struct netdev *netdev;
      struct netdev_saved_flags *sf;
+     struct netdev_rx *rx;
      char *type;                 /* Port type as requested by user. */
  };
  
@@@ -188,17 -189,10 +189,17 @@@ dpif_netdev_class_is_dummy(const struc
      return class != &dpif_netdev_class;
  }
  
 +static bool
 +dpif_netdev_class_is_planetlab(const struct dpif_class *class)
 +{
 +    return class == &dpif_planetlab_class;
 +}
 +
  static const char *
  dpif_netdev_port_open_type(const struct dpif_class *class, const char *type)
  {
      return strcmp(type, "internal") ? type
 +                  : dpif_netdev_class_is_planetlab(class) ? "pltap"
                    : dpif_netdev_class_is_dummy(class) ? "dummy"
                    : "tap";
  }
@@@ -224,8 -218,7 +225,8 @@@ choose_port(struct dp_netdev *dp, cons
  {
      int port_no;
  
 -    if (dp->class != &dpif_netdev_class) {
 +    if (dp->class != &dpif_netdev_class && 
 +        dp->class != &dpif_planetlab_class) {
          const char *p;
          int start_no = 0;
  
@@@ -386,6 -379,7 +387,7 @@@ do_add_port(struct dp_netdev *dp, cons
      struct netdev_saved_flags *sf;
      struct dp_netdev_port *port;
      struct netdev *netdev;
+     struct netdev_rx *rx;
      const char *open_type;
      int mtu;
      int error;
      /* XXX reject loopback devices */
      /* XXX reject non-Ethernet devices */
  
-     error = netdev_listen(netdev);
+     error = netdev_rx_open(netdev, &rx);
      if (error
          && !(error == EOPNOTSUPP && dpif_netdev_class_is_dummy(dp->class))) {
          VLOG_ERR("%s: cannot receive packets on this network device (%s)",
  
      error = netdev_turn_flags_on(netdev, NETDEV_PROMISC, &sf);
      if (error) {
+         netdev_rx_close(rx);
          netdev_close(netdev);
          return error;
      }
      port->port_no = port_no;
      port->netdev = netdev;
      port->sf = sf;
+     port->rx = rx;
      port->type = xstrdup(type);
  
      error = netdev_get_mtu(netdev, &mtu);
@@@ -517,6 -513,7 +521,7 @@@ do_del_port(struct dp_netdev *dp, uint3
  
      netdev_close(port->netdev);
      netdev_restore_flags(port->sf);
+     netdev_rx_close(port->rx);
      free(port->type);
      free(port);
  
@@@ -1071,7 -1068,7 +1076,7 @@@ dpif_netdev_run(struct dpif *dpif
          ofpbuf_clear(&packet);
          ofpbuf_reserve(&packet, DP_NETDEV_HEADROOM);
  
-         error = netdev_recv(port->netdev, &packet);
+         error = port->rx ? netdev_rx_recv(port->rx, &packet) : EOPNOTSUPP;
          if (!error) {
              dp_netdev_port_input(dp, port, &packet);
          } else if (error != EAGAIN && error != EOPNOTSUPP) {
@@@ -1091,7 -1088,9 +1096,9 @@@ dpif_netdev_wait(struct dpif *dpif
      struct dp_netdev_port *port;
  
      LIST_FOR_EACH (port, node, &dp->port_list) {
-         netdev_recv_wait(port->netdev);
+         if (port->rx) {
+             netdev_rx_wait(port->rx);
+         }
      }
  }
  
@@@ -1327,49 -1326,41 +1334,49 @@@ dp_netdev_execute_actions(struct dp_net
      }
  }
  
 +#define DPIF_NETDEV_CLASS_FUNCTIONS                   \
 +    dpif_netdev_enumerate,                            \
 +    dpif_netdev_port_open_type,                               \
 +    dpif_netdev_open,                                 \
 +    dpif_netdev_close,                                        \
 +    dpif_netdev_destroy,                              \
 +    dpif_netdev_run,                                  \
 +    dpif_netdev_wait,                                 \
 +    dpif_netdev_get_stats,                            \
 +    dpif_netdev_port_add,                             \
 +    dpif_netdev_port_del,                             \
 +    dpif_netdev_port_query_by_number,                 \
 +    dpif_netdev_port_query_by_name,                   \
 +    dpif_netdev_get_max_ports,                                \
 +    NULL,                       /* port_get_pid */    \
 +    dpif_netdev_port_dump_start,                      \
 +    dpif_netdev_port_dump_next,                               \
 +    dpif_netdev_port_dump_done,                               \
 +    dpif_netdev_port_poll,                            \
 +    dpif_netdev_port_poll_wait,                               \
 +    dpif_netdev_flow_get,                             \
 +    dpif_netdev_flow_put,                             \
 +    dpif_netdev_flow_del,                             \
 +    dpif_netdev_flow_flush,                           \
 +    dpif_netdev_flow_dump_start,                      \
 +    dpif_netdev_flow_dump_next,                               \
 +    dpif_netdev_flow_dump_done,                               \
 +    dpif_netdev_execute,                              \
 +    NULL,                       /* operate */         \
 +    dpif_netdev_recv_set,                             \
 +    dpif_netdev_queue_to_priority,                    \
 +    dpif_netdev_recv,                                 \
 +    dpif_netdev_recv_wait,                            \
 +    dpif_netdev_recv_purge,                           \
 +
  const struct dpif_class dpif_netdev_class = {
      "netdev",
 -    dpif_netdev_enumerate,
 -    dpif_netdev_port_open_type,
 -    dpif_netdev_open,
 -    dpif_netdev_close,
 -    dpif_netdev_destroy,
 -    dpif_netdev_run,
 -    dpif_netdev_wait,
 -    dpif_netdev_get_stats,
 -    dpif_netdev_port_add,
 -    dpif_netdev_port_del,
 -    dpif_netdev_port_query_by_number,
 -    dpif_netdev_port_query_by_name,
 -    dpif_netdev_get_max_ports,
 -    NULL,                       /* port_get_pid */
 -    dpif_netdev_port_dump_start,
 -    dpif_netdev_port_dump_next,
 -    dpif_netdev_port_dump_done,
 -    dpif_netdev_port_poll,
 -    dpif_netdev_port_poll_wait,
 -    dpif_netdev_flow_get,
 -    dpif_netdev_flow_put,
 -    dpif_netdev_flow_del,
 -    dpif_netdev_flow_flush,
 -    dpif_netdev_flow_dump_start,
 -    dpif_netdev_flow_dump_next,
 -    dpif_netdev_flow_dump_done,
 -    dpif_netdev_execute,
 -    NULL,                       /* operate */
 -    dpif_netdev_recv_set,
 -    dpif_netdev_queue_to_priority,
 -    dpif_netdev_recv,
 -    dpif_netdev_recv_wait,
 -    dpif_netdev_recv_purge,
 +    DPIF_NETDEV_CLASS_FUNCTIONS
 +};
 +
 +const struct dpif_class dpif_planetlab_class = {
 +    "planetlab",
 +    DPIF_NETDEV_CLASS_FUNCTIONS
  };
  
  static void
@@@ -1402,4 -1393,3 +1409,4 @@@ dpif_dummy_register(bool override
  
      dpif_dummy_register__("dummy");
  }
 +
diff --combined lib/netdev-provider.h
@@@ -148,58 -148,19 +148,19 @@@ struct netdev_class 
  
      /* Closes 'netdev'. */
      void (*close)(struct netdev *netdev);
\f
- /* ## ----------------- ## */
- /* ## Receiving Packets ## */
- /* ## ----------------- ## */
- /* The network provider interface is mostly used for inspecting and configuring
-  * device "metadata", not for sending and receiving packets directly.  It may
-  * be impractical to implement these functions on some operating systems and
-  * hardware.  These functions may all be NULL in such cases.
-  *
-  * (However, the "dpif-netdev" implementation, which is the easiest way to
-  * integrate Open vSwitch with a new operating system or hardware, does require
-  * the ability to receive packets.) */
  
-     /* Attempts to set up 'netdev' for receiving packets with ->recv().
-      * Returns 0 if successful, otherwise a positive errno value.  Return
+     /* Attempts to open a netdev_rx for receiving packets from 'netdev'.
+      * Returns 0 if successful, otherwise a positive errno value.  Returns
       * EOPNOTSUPP to indicate that the network device does not implement packet
       * reception through this interface.  This function may be set to null if
       * it would always return EOPNOTSUPP anyhow.  (This will prevent the
       * network device from being usefully used by the netdev-based "userspace
-      * datapath".)*/
-     int (*listen)(struct netdev *netdev);
-     /* Attempts to receive a packet from 'netdev' into the 'size' bytes in
-      * 'buffer'.  If successful, returns the number of bytes in the received
-      * packet, otherwise a negative errno value.  Returns -EAGAIN immediately
-      * if no packet is ready to be received.
-      *
-      * Returns -EMSGSIZE, and discards the packet, if the received packet is
-      * longer than 'size' bytes.
-      *
-      * This function can only be expected to return a packet if ->listen() has
-      * been called successfully.
-      *
-      * May be null if not needed, such as for a network device that does not
-      * implement packet reception through the 'recv' member function. */
-     int (*recv)(struct netdev *netdev, void *buffer, size_t size);
-     /* Registers with the poll loop to wake up from the next call to
-      * poll_block() when a packet is ready to be received with netdev_recv() on
-      * 'netdev'.
+      * datapath".)
       *
-      * May be null if not needed, such as for a network device that does not
-      * implement packet reception through the 'recv' member function. */
-     void (*recv_wait)(struct netdev *netdev);
+      * On success, the implementation must set '*rxp' to a 'netdev_rx' for
+      * 'netdev' that it has already initialized (with netdev_rx_init()). */
+     int (*rx_open)(struct netdev *netdev, struct netdev_rx **rxp);
  
-     /* Discards all packets waiting to be received from 'netdev'.
-      *
-      * May be null if not needed, such as for a network device that does not
-      * implement packet reception through the 'recv' member function. */
-     int (*drain)(struct netdev *netdev);
\f
      /* Sends the 'size'-byte packet in 'buffer' on 'netdev'.  Returns 0 if
       * successful, otherwise a positive errno value.  Returns EAGAIN without
       * blocking if the packet cannot be queued immediately.  Returns EMSGSIZE
       * change, although implementations should try to avoid this. */
      unsigned int (*change_seq)(const struct netdev *netdev);
  };
\f
+ /* A data structure for capturing packets received by a network device.
+  *
+  * This structure should be treated as opaque by network device
+  * implementations. */
+ struct netdev_rx {
+     const struct netdev_rx_class *rx_class;
+     struct netdev_dev *netdev_dev;
+ };
+ void netdev_rx_init(struct netdev_rx *, struct netdev_dev *,
+                     const struct netdev_rx_class *);
+ void netdev_rx_uninit(struct netdev_rx *);
+ struct netdev_dev *netdev_rx_get_dev(const struct netdev_rx *);
+ struct netdev_rx_class {
+     /* Destroys 'rx'. */
+     void (*destroy)(struct netdev_rx *rx);
+     /* Attempts to receive a packet from 'rx' into the 'size' bytes in
+      * 'buffer'.  If successful, returns the number of bytes in the received
+      * packet, otherwise a negative errno value.  Returns -EAGAIN immediately
+      * if no packet is ready to be received.
+      *
+      * Must return -EMSGSIZE, and discard the packet, if the received packet
+      * is longer than 'size' bytes. */
+     int (*recv)(struct netdev_rx *rx, void *buffer, size_t size);
+     /* Registers with the poll loop to wake up from the next call to
+      * poll_block() when a packet is ready to be received with netdev_rx_recv()
+      * on 'rx'. */
+     void (*wait)(struct netdev_rx *rx);
+     /* Discards all packets waiting to be received from 'rx'. */
+     int (*drain)(struct netdev_rx *rx);
+ };
+ static inline void netdev_rx_assert_class(const struct netdev_rx *rx,
+                                           const struct netdev_rx_class *class_)
+ {
+     ovs_assert(rx->rx_class == class_);
+ }
  
  int netdev_register_provider(const struct netdev_class *);
  int netdev_unregister_provider(const char *type);
@@@ -603,9 -606,6 +606,9 @@@ extern const struct netdev_class netdev
  extern const struct netdev_class netdev_bsd_class;
  #endif
  
 +extern const struct netdev_class netdev_tunnel_class;
 +extern const struct netdev_class netdev_pltap_class;
 +
  #ifdef  __cplusplus
  }
  #endif
diff --combined lib/netdev.c
@@@ -91,8 -91,6 +91,8 @@@ netdev_initialize(void
          netdev_register_provider(&netdev_tap_class);
          netdev_register_provider(&netdev_bsd_class);
  #endif
 +      netdev_register_provider(&netdev_tunnel_class);
 +      netdev_register_provider(&netdev_pltap_class);
      }
  }
  
@@@ -350,49 -348,44 +350,44 @@@ netdev_parse_name(const char *netdev_na
      }
  }
  
- /* Attempts to set up 'netdev' for receiving packets with netdev_recv().
-  * Returns 0 if successful, otherwise a positive errno value.  EOPNOTSUPP
-  * indicates that the network device does not implement packet reception
-  * through this interface. */
  int
- netdev_listen(struct netdev *netdev)
+ netdev_rx_open(struct netdev *netdev, struct netdev_rx **rxp)
  {
-     int (*listen)(struct netdev *);
+     struct netdev_dev *dev = netdev_get_dev(netdev);
+     int error;
  
-     listen = netdev_get_dev(netdev)->netdev_class->listen;
-     return listen ? (listen)(netdev) : EOPNOTSUPP;
+     error = (dev->netdev_class->rx_open
+              ? dev->netdev_class->rx_open(netdev, rxp)
+              : EOPNOTSUPP);
+     if (!error) {
+         ovs_assert((*rxp)->netdev_dev == dev);
+         dev->ref_cnt++;
+     } else {
+         *rxp = NULL;
+     }
+     return error;
+ }
+ void
+ netdev_rx_close(struct netdev_rx *rx)
+ {
+     if (rx) {
+         struct netdev_dev *dev = rx->netdev_dev;
+         rx->rx_class->destroy(rx);
+         netdev_dev_unref(dev);
+     }
  }
  
- /* Attempts to receive a packet from 'netdev' into 'buffer', which the caller
-  * must have initialized with sufficient room for the packet.  The space
-  * required to receive any packet is ETH_HEADER_LEN bytes, plus VLAN_HEADER_LEN
-  * bytes, plus the device's MTU (which may be retrieved via netdev_get_mtu()).
-  * (Some devices do not allow for a VLAN header, in which case VLAN_HEADER_LEN
-  * need not be included.)
-  *
-  * This function can only be expected to return a packet if ->listen() has
-  * been called successfully.
-  *
-  * If a packet is successfully retrieved, returns 0.  In this case 'buffer' is
-  * guaranteed to contain at least ETH_TOTAL_MIN bytes.  Otherwise, returns a
-  * positive errno value.  Returns EAGAIN immediately if no packet is ready to
-  * be returned.
-  *
-  * Some network devices may not implement support for this function.  In such
-  * cases this function will always return EOPNOTSUPP. */
  int
- netdev_recv(struct netdev *netdev, struct ofpbuf *buffer)
+ netdev_rx_recv(struct netdev_rx *rx, struct ofpbuf *buffer)
  {
-     int (*recv)(struct netdev *, void *, size_t);
      int retval;
  
      ovs_assert(buffer->size == 0);
      ovs_assert(ofpbuf_tailroom(buffer) >= ETH_TOTAL_MIN);
  
-     recv = netdev_get_dev(netdev)->netdev_class->recv;
-     retval = (recv
-               ? (recv)(netdev, buffer->data, ofpbuf_tailroom(buffer))
-               : -EOPNOTSUPP);
+     retval = rx->rx_class->recv(rx, buffer->data, ofpbuf_tailroom(buffer));
      if (retval >= 0) {
          COVERAGE_INC(netdev_received);
          buffer->size += retval;
      }
  }
  
- /* Registers with the poll loop to wake up from the next call to poll_block()
-  * when a packet is ready to be received with netdev_recv() on 'netdev'. */
  void
- netdev_recv_wait(struct netdev *netdev)
+ netdev_rx_wait(struct netdev_rx *rx)
  {
-     void (*recv_wait)(struct netdev *);
-     recv_wait = netdev_get_dev(netdev)->netdev_class->recv_wait;
-     if (recv_wait) {
-         recv_wait(netdev);
-     }
+     rx->rx_class->wait(rx);
  }
  
- /* Discards all packets waiting to be received from 'netdev'. */
  int
- netdev_drain(struct netdev *netdev)
+ netdev_rx_drain(struct netdev_rx *rx)
  {
-     int (*drain)(struct netdev *);
-     drain = netdev_get_dev(netdev)->netdev_class->drain;
-     return drain ? drain(netdev) : 0;
+     return rx->rx_class->drain ? rx->rx_class->drain(rx) : 0;
  }
  
  /* Sends 'buffer' on 'netdev'.  Returns 0 if successful, otherwise a positive
@@@ -1461,8 -1443,34 +1445,34 @@@ netdev_get_dev(const struct netdev *net
      return netdev->netdev_dev;
  }
  \f
- /* Restores all flags that have been saved with netdev_save_flags() and not yet
-  * restored with netdev_restore_flags(). */
+ void
+ netdev_rx_init(struct netdev_rx *rx, struct netdev_dev *dev,
+                const struct netdev_rx_class *class)
+ {
+     ovs_assert(dev->ref_cnt > 0);
+     rx->rx_class = class;
+     rx->netdev_dev = dev;
+ }
+ void
+ netdev_rx_uninit(struct netdev_rx *rx OVS_UNUSED)
+ {
+     /* Nothing to do. */
+ }
+ struct netdev_dev *
+ netdev_rx_get_dev(const struct netdev_rx *rx)
+ {
+     ovs_assert(rx->netdev_dev->ref_cnt > 0);
+     return rx->netdev_dev;
+ }
+ const char *
+ netdev_rx_get_name(const struct netdev_rx *rx)
+ {
+     return netdev_dev_get_name(netdev_rx_get_dev(rx));
+ }
  static void
  restore_all_flags(void *aux OVS_UNUSED)
  {