From: Giuseppe Lettieri Date: Fri, 5 Jul 2013 17:55:33 +0000 (+0200) Subject: Merge commit '796223f5bc3a4896e6398733c798390158479400' X-Git-Tag: sliver-openvswitch-1.10.90-3~13 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=060ea9d5152b5c8cc6646ead1175484e07c583fe;hp=-c;p=sliver-openvswitch.git Merge commit '796223f5bc3a4896e6398733c798390158479400' --- 060ea9d5152b5c8cc6646ead1175484e07c583fe diff --combined lib/dpif-netdev.c index a37933d5a,78bdedb0f..d5060f1f5 --- a/lib/dpif-netdev.c +++ b/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; @@@ -401,7 -395,7 +403,7 @@@ /* 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)", @@@ -412,6 -406,7 +414,7 @@@ error = netdev_turn_flags_on(netdev, NETDEV_PROMISC, &sf); if (error) { + netdev_rx_close(rx); netdev_close(netdev); return error; } @@@ -420,6 -415,7 +423,7 @@@ 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 index c19816ed5,bfdcd30b3..38edbd6e9 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@@ -148,58 -148,19 +148,19 @@@ struct netdev_class /* Closes 'netdev'. */ void (*close)(struct netdev *netdev); - - /* ## ----------------- ## */ - /* ## 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); - /* 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 @@@ -591,6 -552,48 +552,48 @@@ * change, although implementations should try to avoid this. */ unsigned int (*change_seq)(const struct netdev *netdev); }; + + /* 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 index 3f8732946,aa0e0127a..44675185e --- a/lib/netdev.c +++ b/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; @@@ -405,27 -398,16 +400,16 @@@ } } - /* 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; } - /* 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) {