projects
/
openvswitch
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
ovs-vsctl: Prevent double-free when retrying a transaction
[openvswitch]
/
lib
/
netdev.c
diff --git
a/lib/netdev.c
b/lib/netdev.c
index 7d834ad0909282b76b6a21d49edb3e4c1b5f9edc..993f27a8860496bec78256d05a6f549f9057295a 100644
(file)
--- a/
lib/netdev.c
+++ b/
lib/netdev.c
@@
-31,6
+31,7
@@
#include "hash.h"
#include "list.h"
#include "netdev-provider.h"
#include "hash.h"
#include "list.h"
#include "netdev-provider.h"
+#include "netdev-vport.h"
#include "ofpbuf.h"
#include "openflow/openflow.h"
#include "packets.h"
#include "ofpbuf.h"
#include "openflow/openflow.h"
#include "packets.h"
@@
-41,15
+42,6
@@
VLOG_DEFINE_THIS_MODULE(netdev)
VLOG_DEFINE_THIS_MODULE(netdev)
-static const struct netdev_class *base_netdev_classes[] = {
-#ifdef HAVE_NETLINK
- &netdev_linux_class,
- &netdev_tap_class,
- &netdev_patch_class,
- &netdev_gre_class,
-#endif
-};
-
static struct shash netdev_classes = SHASH_INITIALIZER(&netdev_classes);
/* All created network devices. */
static struct shash netdev_classes = SHASH_INITIALIZER(&netdev_classes);
/* All created network devices. */
@@
-69,17
+61,18
@@
void update_device_args(struct netdev_dev *, const struct shash *args);
static void
netdev_initialize(void)
{
static void
netdev_initialize(void)
{
- static
int status = -1
;
+ static
bool inited
;
- if (
status < 0
) {
- in
t i
;
+ if (
!inited
) {
+ in
ited = true
;
fatal_signal_add_hook(close_all_netdevs, NULL, NULL, true);
fatal_signal_add_hook(close_all_netdevs, NULL, NULL, true);
- status = 0;
- for (i = 0; i < ARRAY_SIZE(base_netdev_classes); i++) {
- netdev_register_provider(base_netdev_classes[i]);
- }
+#ifdef HAVE_NETLINK
+ netdev_register_provider(&netdev_linux_class);
+ netdev_register_provider(&netdev_tap_class);
+ netdev_vport_register();
+#endif
}
}
}
}
@@
-120,8
+113,6
@@
netdev_wait(void)
int
netdev_register_provider(const struct netdev_class *new_class)
{
int
netdev_register_provider(const struct netdev_class *new_class)
{
- struct netdev_class *new_provider;
-
if (shash_find(&netdev_classes, new_class->type)) {
VLOG_WARN("attempted to register duplicate netdev provider: %s",
new_class->type);
if (shash_find(&netdev_classes, new_class->type)) {
VLOG_WARN("attempted to register duplicate netdev provider: %s",
new_class->type);
@@
-137,10
+128,7
@@
netdev_register_provider(const struct netdev_class *new_class)
}
}
}
}
- new_provider = xmalloc(sizeof *new_provider);
- memcpy(new_provider, new_class, sizeof *new_provider);
-
- shash_add(&netdev_classes, new_class->type, new_provider);
+ shash_add(&netdev_classes, new_class->type, new_class);
return 0;
}
return 0;
}
@@
-170,7
+158,6
@@
netdev_unregister_provider(const char *type)
}
shash_delete(&netdev_classes, del_node);
}
shash_delete(&netdev_classes, del_node);
- free(del_node->data);
return 0;
}
return 0;
}
@@
-207,7
+194,7
@@
compare_device_args(const struct netdev_dev *dev, const struct shash *args)
new_args = shash_sort(args);
for (i = 0; i < dev->n_args; i++) {
new_args = shash_sort(args);
for (i = 0; i < dev->n_args; i++) {
- if (strcmp(dev->args[i].key, new_args[i]->name) ||
+ if (strcmp(dev->args[i].key, new_args[i]->name) ||
strcmp(dev->args[i].value, new_args[i]->data)) {
result = false;
goto finish;
strcmp(dev->args[i].value, new_args[i]->data)) {
result = false;
goto finish;
@@
-272,12
+259,10
@@
create_device(struct netdev_options *options, struct netdev_dev **netdev_devp)
netdev_class = shash_find_data(&netdev_classes, options->type);
if (!netdev_class) {
netdev_class = shash_find_data(&netdev_classes, options->type);
if (!netdev_class) {
- VLOG_WARN("could not create netdev %s of unknown type %s",
- options->name, options->type);
return EAFNOSUPPORT;
}
return EAFNOSUPPORT;
}
- return netdev_class->create(
options->name, options->typ
e, options->args,
+ return netdev_class->create(
netdev_class, options->nam
e, options->args,
netdev_devp);
}
netdev_devp);
}
@@
-286,13
+271,12
@@
create_device(struct netdev_options *options, struct netdev_dev **netdev_devp)
* to the new network device, otherwise to null.
*
* If this is the first time the device has been opened, then create is called
* to the new network device, otherwise to null.
*
* If this is the first time the device has been opened, then create is called
- * before opening. The device is
created using the given type and arguments.
+ * before opening. The device is created using the given type and arguments.
*
* 'ethertype' may be a 16-bit Ethernet protocol value in host byte order to
* capture frames of that type received on the device. It may also be one of
* the 'enum netdev_pseudo_ethertype' values to receive frames in one of those
* categories. */
*
* 'ethertype' may be a 16-bit Ethernet protocol value in host byte order to
* capture frames of that type received on the device. It may also be one of
* the 'enum netdev_pseudo_ethertype' values to receive frames in one of those
* categories. */
-
int
netdev_open(struct netdev_options *options, struct netdev **netdevp)
{
int
netdev_open(struct netdev_options *options, struct netdev **netdevp)
{
@@
-312,6
+296,10
@@
netdev_open(struct netdev_options *options, struct netdev **netdevp)
if (!netdev_dev) {
error = create_device(options, &netdev_dev);
if (error) {
if (!netdev_dev) {
error = create_device(options, &netdev_dev);
if (error) {
+ if (error == EAFNOSUPPORT) {
+ VLOG_WARN("could not create netdev %s of unknown type %s",
+ options->name, options->type);
+ }
return error;
}
update_device_args(netdev_dev, options->args);
return error;
}
update_device_args(netdev_dev, options->args);
@@
-324,7
+312,7
@@
netdev_open(struct netdev_options *options, struct netdev **netdevp)
return EINVAL;
}
return EINVAL;
}
- error = netdev_dev->netdev_class->open(netdev_dev, options->ethertype,
+ error = netdev_dev->netdev_class->open(netdev_dev, options->ethertype,
netdevp);
if (!error) {
netdevp);
if (!error) {
@@
-462,8
+450,7
@@
netdev_enumerate(struct svec *svec)
* be returned.
*
* Some network devices may not implement support for this function. In such
* be returned.
*
* Some network devices may not implement support for this function. In such
- * cases this function will always return EOPNOTSUPP.
- */
+ * cases this function will always return EOPNOTSUPP. */
int
netdev_recv(struct netdev *netdev, struct ofpbuf *buffer)
{
int
netdev_recv(struct netdev *netdev, struct ofpbuf *buffer)
{
@@
-629,8
+616,7
@@
netdev_get_ifindex(const struct netdev *netdev)
* passed-in values are set to 0.
*
* Some network devices may not implement support for this function. In such
* passed-in values are set to 0.
*
* Some network devices may not implement support for this function. In such
- * cases this function will always return EOPNOTSUPP.
- */
+ * cases this function will always return EOPNOTSUPP. */
int
netdev_get_features(struct netdev *netdev,
uint32_t *current, uint32_t *advertised,
int
netdev_get_features(struct netdev *netdev,
uint32_t *current, uint32_t *advertised,
@@
-715,8
+701,8
@@
netdev_set_advertisements(struct netdev *netdev, uint32_t advertise)
*
* - EOPNOTSUPP: No IPv4 network stack attached to 'netdev'.
*
*
* - EOPNOTSUPP: No IPv4 network stack attached to 'netdev'.
*
- * 'address' or 'netmask' or both may be null, in which case the address or
netmask
- * is not reported. */
+ * 'address' or 'netmask' or both may be null, in which case the address or
+ *
netmask
is not reported. */
int
netdev_get_in4(const struct netdev *netdev,
struct in_addr *address_, struct in_addr *netmask_)
int
netdev_get_in4(const struct netdev *netdev,
struct in_addr *address_, struct in_addr *netmask_)
@@
-726,7
+712,7
@@
netdev_get_in4(const struct netdev *netdev,
int error;
error = (netdev_get_dev(netdev)->netdev_class->get_in4
int error;
error = (netdev_get_dev(netdev)->netdev_class->get_in4
- ? netdev_get_dev(netdev)->netdev_class->get_in4(netdev,
+ ? netdev_get_dev(netdev)->netdev_class->get_in4(netdev,
&address, &netmask)
: EOPNOTSUPP);
if (address_) {
&address, &netmask)
: EOPNOTSUPP);
if (address_) {
@@
-801,7
+787,7
@@
netdev_get_in6(const struct netdev *netdev, struct in6_addr *in6)
int error;
error = (netdev_get_dev(netdev)->netdev_class->get_in6
int error;
error = (netdev_get_dev(netdev)->netdev_class->get_in6
- ? netdev_get_dev(netdev)->netdev_class->get_in6(netdev,
+ ? netdev_get_dev(netdev)->netdev_class->get_in6(netdev,
in6 ? in6 : &dummy)
: EOPNOTSUPP);
if (error && in6) {
in6 ? in6 : &dummy)
: EOPNOTSUPP);
if (error && in6) {
@@
-822,7
+808,7
@@
do_update_flags(struct netdev *netdev, enum netdev_flags off,
enum netdev_flags old_flags;
int error;
enum netdev_flags old_flags;
int error;
- error = netdev_get_dev(netdev)->netdev_class->update_flags(netdev,
+ error = netdev_get_dev(netdev)->netdev_class->update_flags(netdev,
off & ~on, on, &old_flags);
if (error) {
VLOG_WARN_RL(&rl, "failed to %s flags for network device %s: %s",
off & ~on, on, &old_flags);
if (error) {
VLOG_WARN_RL(&rl, "failed to %s flags for network device %s: %s",
@@
-897,7
+883,7
@@
netdev_arp_lookup(const struct netdev *netdev,
uint32_t ip, uint8_t mac[ETH_ADDR_LEN])
{
int error = (netdev_get_dev(netdev)->netdev_class->arp_lookup
uint32_t ip, uint8_t mac[ETH_ADDR_LEN])
{
int error = (netdev_get_dev(netdev)->netdev_class->arp_lookup
- ? netdev_get_dev(netdev)->netdev_class->arp_lookup(netdev,
+ ? netdev_get_dev(netdev)->netdev_class->arp_lookup(netdev,
ip, mac)
: EOPNOTSUPP);
if (error) {
ip, mac)
: EOPNOTSUPP);
if (error) {
@@
-912,7
+898,7
@@
int
netdev_get_carrier(const struct netdev *netdev, bool *carrier)
{
int error = (netdev_get_dev(netdev)->netdev_class->get_carrier
netdev_get_carrier(const struct netdev *netdev, bool *carrier)
{
int error = (netdev_get_dev(netdev)->netdev_class->get_carrier
- ? netdev_get_dev(netdev)->netdev_class->get_carrier(netdev,
+ ? netdev_get_dev(netdev)->netdev_class->get_carrier(netdev,
carrier)
: EOPNOTSUPP);
if (error) {
carrier)
: EOPNOTSUPP);
if (error) {
@@
-958,7
+944,7
@@
netdev_set_policing(struct netdev *netdev, uint32_t kbits_rate,
uint32_t kbits_burst)
{
return (netdev_get_dev(netdev)->netdev_class->set_policing
uint32_t kbits_burst)
{
return (netdev_get_dev(netdev)->netdev_class->set_policing
- ? netdev_get_dev(netdev)->netdev_class->set_policing(netdev,
+ ? netdev_get_dev(netdev)->netdev_class->set_policing(netdev,
kbits_rate, kbits_burst)
: EOPNOTSUPP);
}
kbits_rate, kbits_burst)
: EOPNOTSUPP);
}
@@
-1147,8
+1133,7
@@
netdev_get_queue(const struct netdev *netdev,
* the current form of QoS (e.g. as returned by netdev_get_n_queues(netdev)).
*
* This function does not modify 'details', and the caller retains ownership of
* the current form of QoS (e.g. as returned by netdev_get_n_queues(netdev)).
*
* This function does not modify 'details', and the caller retains ownership of
- * it.
- */
+ * it. */
int
netdev_set_queue(struct netdev *netdev,
unsigned int queue_id, const struct shash *details)
int
netdev_set_queue(struct netdev *netdev,
unsigned int queue_id, const struct shash *details)
@@
-1251,7
+1236,7
@@
int
netdev_get_vlan_vid(const struct netdev *netdev, int *vlan_vid)
{
int error = (netdev_get_dev(netdev)->netdev_class->get_vlan_vid
netdev_get_vlan_vid(const struct netdev *netdev, int *vlan_vid)
{
int error = (netdev_get_dev(netdev)->netdev_class->get_vlan_vid
- ? netdev_get_dev(netdev)->netdev_class->get_vlan_vid(netdev,
+ ? netdev_get_dev(netdev)->netdev_class->get_vlan_vid(netdev,
vlan_vid)
: ENOENT);
if (error) {
vlan_vid)
: ENOENT);
if (error) {
@@
-1416,7
+1401,7
@@
netdev_uninit(struct netdev *netdev, bool close)
}
}
-/* Returns the class type of 'netdev'.
+/* Returns the class type of 'netdev'.
*
* The caller must not free the returned value. */
const char *
*
* The caller must not free the returned value. */
const char *
@@
-1540,8
+1525,7
@@
netdev_monitor_remove(struct netdev_monitor *monitor, struct netdev *netdev)
* sets '*devnamep' to the name of a device that has changed and returns 0.
* The caller is responsible for freeing '*devnamep' (with free()).
*
* sets '*devnamep' to the name of a device that has changed and returns 0.
* The caller is responsible for freeing '*devnamep' (with free()).
*
- * If no devices have changed, sets '*devnamep' to NULL and returns EAGAIN.
- */
+ * If no devices have changed, sets '*devnamep' to NULL and returns EAGAIN. */
int
netdev_monitor_poll(struct netdev_monitor *monitor, char **devnamep)
{
int
netdev_monitor_poll(struct netdev_monitor *monitor, char **devnamep)
{
@@
-1550,8
+1534,7
@@
netdev_monitor_poll(struct netdev_monitor *monitor, char **devnamep)
*devnamep = NULL;
return EAGAIN;
} else {
*devnamep = NULL;
return EAGAIN;
} else {
- *devnamep = xstrdup(node->name);
- shash_delete(&monitor->changed_netdevs, node);
+ *devnamep = shash_steal(&monitor->changed_netdevs, node);
return 0;
}
}
return 0;
}
}
@@
-1594,7
+1577,7
@@
static void
close_all_netdevs(void *aux OVS_UNUSED)
{
struct netdev *netdev, *next;
close_all_netdevs(void *aux OVS_UNUSED)
{
struct netdev *netdev, *next;
- LIST_FOR_EACH_SAFE(netdev, next,
struct netdev,
node, &netdev_list) {
+ LIST_FOR_EACH_SAFE(netdev, next, node, &netdev_list) {
netdev_close(netdev);
}
}
netdev_close(netdev);
}
}