2010-11-29 12:21:08 -08:00
|
|
|
|
/*
|
2015-03-29 15:49:29 -07:00
|
|
|
|
* Copyright (c) 2010, 2011, 2012, 2013, 2015 Nicira, Inc.
|
2010-11-29 12:21:08 -08:00
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at:
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
|
|
#include "dummy.h"
|
|
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
2015-02-25 12:01:53 -08:00
|
|
|
|
#include "dp-packet.h"
|
2014-03-20 10:54:37 -07:00
|
|
|
|
#include "dpif-netdev.h"
|
2014-06-05 16:01:17 -07:00
|
|
|
|
#include "dynamic-string.h"
|
2011-12-06 14:22:27 -08:00
|
|
|
|
#include "flow.h"
|
2010-11-29 12:21:08 -08:00
|
|
|
|
#include "list.h"
|
|
|
|
|
#include "netdev-provider.h"
|
2013-01-25 13:30:40 -08:00
|
|
|
|
#include "netdev-vport.h"
|
2011-12-06 14:22:27 -08:00
|
|
|
|
#include "odp-util.h"
|
|
|
|
|
#include "ofp-print.h"
|
|
|
|
|
#include "ofpbuf.h"
|
2015-03-29 15:49:29 -07:00
|
|
|
|
#include "ovs-atomic.h"
|
2010-11-29 12:21:08 -08:00
|
|
|
|
#include "packets.h"
|
2013-09-23 10:26:51 -07:00
|
|
|
|
#include "pcap-file.h"
|
2011-12-06 14:22:27 -08:00
|
|
|
|
#include "poll-loop.h"
|
2010-11-29 12:21:08 -08:00
|
|
|
|
#include "shash.h"
|
2012-01-19 10:24:46 -08:00
|
|
|
|
#include "sset.h"
|
2012-10-25 16:54:23 -07:00
|
|
|
|
#include "stream.h"
|
|
|
|
|
#include "unaligned.h"
|
2013-09-23 10:26:51 -07:00
|
|
|
|
#include "timeval.h"
|
2011-12-06 14:22:27 -08:00
|
|
|
|
#include "unixctl.h"
|
2013-12-18 13:55:25 -08:00
|
|
|
|
#include "reconnect.h"
|
2014-12-15 14:10:38 +01:00
|
|
|
|
#include "openvswitch/vlog.h"
|
2010-11-29 12:21:08 -08:00
|
|
|
|
|
|
|
|
|
VLOG_DEFINE_THIS_MODULE(netdev_dummy);
|
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
struct reconnect;
|
|
|
|
|
|
|
|
|
|
struct dummy_packet_stream {
|
2012-10-25 16:54:23 -07:00
|
|
|
|
struct stream *stream;
|
2015-02-22 03:21:09 -08:00
|
|
|
|
struct dp_packet rxbuf;
|
2014-12-15 14:10:38 +01:00
|
|
|
|
struct ovs_list txq;
|
2012-10-25 16:54:23 -07:00
|
|
|
|
};
|
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
enum dummy_packet_conn_type {
|
|
|
|
|
NONE, /* No connection is configured. */
|
|
|
|
|
PASSIVE, /* Listener. */
|
|
|
|
|
ACTIVE /* Connect to listener. */
|
|
|
|
|
};
|
|
|
|
|
|
2014-06-05 16:01:17 -07:00
|
|
|
|
enum dummy_netdev_conn_state {
|
|
|
|
|
CONN_STATE_CONNECTED, /* Listener connected. */
|
|
|
|
|
CONN_STATE_NOT_CONNECTED, /* Listener not connected. */
|
|
|
|
|
CONN_STATE_UNKNOWN, /* No relavent information. */
|
|
|
|
|
};
|
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
struct dummy_packet_pconn {
|
|
|
|
|
struct pstream *pstream;
|
|
|
|
|
struct dummy_packet_stream *streams;
|
|
|
|
|
size_t n_streams;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct dummy_packet_rconn {
|
|
|
|
|
struct dummy_packet_stream *rstream;
|
|
|
|
|
struct reconnect *reconnect;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct dummy_packet_conn {
|
|
|
|
|
enum dummy_packet_conn_type type;
|
|
|
|
|
union {
|
|
|
|
|
struct dummy_packet_pconn pconn;
|
|
|
|
|
struct dummy_packet_rconn rconn;
|
|
|
|
|
} u;
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-18 10:47:45 -07:00
|
|
|
|
struct pkt_list_node {
|
|
|
|
|
struct dp_packet *pkt;
|
|
|
|
|
struct ovs_list list_node;
|
|
|
|
|
};
|
|
|
|
|
|
2013-08-12 12:49:23 -07:00
|
|
|
|
/* Protects 'dummy_list'. */
|
|
|
|
|
static struct ovs_mutex dummy_list_mutex = OVS_MUTEX_INITIALIZER;
|
|
|
|
|
|
|
|
|
|
/* Contains all 'struct dummy_dev's. */
|
2014-12-15 14:10:38 +01:00
|
|
|
|
static struct ovs_list dummy_list OVS_GUARDED_BY(dummy_list_mutex)
|
2014-12-15 14:10:38 +01:00
|
|
|
|
= OVS_LIST_INITIALIZER(&dummy_list);
|
2013-08-12 12:49:23 -07:00
|
|
|
|
|
2013-03-15 15:54:36 -07:00
|
|
|
|
struct netdev_dummy {
|
|
|
|
|
struct netdev up;
|
2013-08-09 21:34:02 -07:00
|
|
|
|
|
2013-08-12 12:49:23 -07:00
|
|
|
|
/* In dummy_list. */
|
2014-12-15 14:10:38 +01:00
|
|
|
|
struct ovs_list list_node OVS_GUARDED_BY(dummy_list_mutex);
|
2013-08-12 12:49:23 -07:00
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
/* Protects all members below. */
|
2013-08-12 12:49:23 -07:00
|
|
|
|
struct ovs_mutex mutex OVS_ACQ_AFTER(dummy_list_mutex);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
|
2015-08-28 14:55:11 -07:00
|
|
|
|
struct eth_addr hwaddr OVS_GUARDED;
|
2013-08-16 14:04:08 -07:00
|
|
|
|
int mtu OVS_GUARDED;
|
|
|
|
|
struct netdev_stats stats OVS_GUARDED;
|
|
|
|
|
enum netdev_flags flags OVS_GUARDED;
|
|
|
|
|
int ifindex OVS_GUARDED;
|
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
struct dummy_packet_conn conn OVS_GUARDED;
|
2013-08-16 14:04:08 -07:00
|
|
|
|
|
2014-03-20 19:38:14 -07:00
|
|
|
|
FILE *tx_pcap, *rxq_pcap OVS_GUARDED;
|
2013-09-23 10:26:51 -07:00
|
|
|
|
|
2014-11-11 11:53:47 -08:00
|
|
|
|
struct in_addr address, netmask;
|
2014-12-15 14:10:38 +01:00
|
|
|
|
struct ovs_list rxes OVS_GUARDED; /* List of child "netdev_rxq_dummy"s. */
|
2010-11-29 12:21:08 -08:00
|
|
|
|
};
|
|
|
|
|
|
2012-08-16 16:37:32 -07:00
|
|
|
|
/* Max 'recv_queue_len' in struct netdev_dummy. */
|
|
|
|
|
#define NETDEV_DUMMY_MAX_QUEUE 100
|
|
|
|
|
|
2014-03-20 19:38:14 -07:00
|
|
|
|
struct netdev_rxq_dummy {
|
|
|
|
|
struct netdev_rxq up;
|
2014-12-15 14:10:38 +01:00
|
|
|
|
struct ovs_list node; /* In netdev_dummy's "rxes" list. */
|
|
|
|
|
struct ovs_list recv_queue;
|
2012-08-16 16:37:32 -07:00
|
|
|
|
int recv_queue_len; /* list_size(&recv_queue). */
|
2013-12-25 22:27:25 -08:00
|
|
|
|
struct seq *seq; /* Reports newly queued packets. */
|
2010-11-29 12:21:08 -08:00
|
|
|
|
};
|
|
|
|
|
|
2012-08-09 18:08:40 -07:00
|
|
|
|
static unixctl_cb_func netdev_dummy_set_admin_state;
|
2013-08-09 21:21:38 -07:00
|
|
|
|
static int netdev_dummy_construct(struct netdev *);
|
2015-02-22 03:21:09 -08:00
|
|
|
|
static void netdev_dummy_queue_packet(struct netdev_dummy *, struct dp_packet *);
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
static void dummy_packet_stream_close(struct dummy_packet_stream *);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
|
2015-05-18 10:47:45 -07:00
|
|
|
|
static void pkt_list_delete(struct ovs_list *);
|
|
|
|
|
|
2010-11-29 12:21:08 -08:00
|
|
|
|
static bool
|
|
|
|
|
is_dummy_class(const struct netdev_class *class)
|
|
|
|
|
{
|
2013-08-09 21:21:38 -07:00
|
|
|
|
return class->construct == netdev_dummy_construct;
|
2010-11-29 12:21:08 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct netdev_dummy *
|
|
|
|
|
netdev_dummy_cast(const struct netdev *netdev)
|
|
|
|
|
{
|
2013-03-15 15:54:36 -07:00
|
|
|
|
ovs_assert(is_dummy_class(netdev_get_class(netdev)));
|
2013-03-08 15:09:42 -08:00
|
|
|
|
return CONTAINER_OF(netdev, struct netdev_dummy, up);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-20 19:38:14 -07:00
|
|
|
|
static struct netdev_rxq_dummy *
|
|
|
|
|
netdev_rxq_dummy_cast(const struct netdev_rxq *rx)
|
2013-05-10 14:39:19 -07:00
|
|
|
|
{
|
2013-08-09 21:21:38 -07:00
|
|
|
|
ovs_assert(is_dummy_class(netdev_get_class(rx->netdev)));
|
2014-03-20 19:38:14 -07:00
|
|
|
|
return CONTAINER_OF(rx, struct netdev_rxq_dummy, up);
|
2013-05-10 14:39:19 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-10-25 16:54:23 -07:00
|
|
|
|
static void
|
2013-12-18 13:55:25 -08:00
|
|
|
|
dummy_packet_stream_init(struct dummy_packet_stream *s, struct stream *stream)
|
2012-10-25 16:54:23 -07:00
|
|
|
|
{
|
2013-12-18 13:55:25 -08:00
|
|
|
|
int rxbuf_size = stream ? 2048 : 0;
|
|
|
|
|
s->stream = stream;
|
2015-02-22 03:21:09 -08:00
|
|
|
|
dp_packet_init(&s->rxbuf, rxbuf_size);
|
2013-12-18 13:55:25 -08:00
|
|
|
|
list_init(&s->txq);
|
|
|
|
|
}
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
static struct dummy_packet_stream *
|
|
|
|
|
dummy_packet_stream_create(struct stream *stream)
|
|
|
|
|
{
|
|
|
|
|
struct dummy_packet_stream *s;
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
s = xzalloc(sizeof *s);
|
|
|
|
|
dummy_packet_stream_init(s, stream);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
return s;
|
|
|
|
|
}
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
static void
|
|
|
|
|
dummy_packet_stream_wait(struct dummy_packet_stream *s)
|
|
|
|
|
{
|
|
|
|
|
stream_run_wait(s->stream);
|
|
|
|
|
if (!list_is_empty(&s->txq)) {
|
|
|
|
|
stream_send_wait(s->stream);
|
|
|
|
|
}
|
|
|
|
|
stream_recv_wait(s->stream);
|
|
|
|
|
}
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
static void
|
|
|
|
|
dummy_packet_stream_send(struct dummy_packet_stream *s, const void *buffer, size_t size)
|
|
|
|
|
{
|
|
|
|
|
if (list_size(&s->txq) < NETDEV_DUMMY_MAX_QUEUE) {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
struct dp_packet *b;
|
2015-05-18 10:47:45 -07:00
|
|
|
|
struct pkt_list_node *node;
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2015-02-22 03:21:09 -08:00
|
|
|
|
b = dp_packet_clone_data_with_headroom(buffer, size, 2);
|
|
|
|
|
put_unaligned_be16(dp_packet_push_uninit(b, 2), htons(size));
|
2015-05-18 10:47:45 -07:00
|
|
|
|
|
|
|
|
|
node = xmalloc(sizeof *node);
|
|
|
|
|
node->pkt = b;
|
|
|
|
|
list_push_back(&s->txq, &node->list_node);
|
2013-12-18 13:55:25 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
dummy_packet_stream_run(struct netdev_dummy *dev, struct dummy_packet_stream *s)
|
|
|
|
|
{
|
|
|
|
|
int error = 0;
|
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
|
|
stream_run(s->stream);
|
|
|
|
|
|
|
|
|
|
if (!list_is_empty(&s->txq)) {
|
2015-05-18 10:47:45 -07:00
|
|
|
|
struct pkt_list_node *txbuf_node;
|
2015-02-22 03:21:09 -08:00
|
|
|
|
struct dp_packet *txbuf;
|
2013-12-18 13:55:25 -08:00
|
|
|
|
int retval;
|
|
|
|
|
|
2015-05-18 10:47:45 -07:00
|
|
|
|
ASSIGN_CONTAINER(txbuf_node, list_front(&s->txq), list_node);
|
|
|
|
|
txbuf = txbuf_node->pkt;
|
2015-02-22 03:21:09 -08:00
|
|
|
|
retval = stream_send(s->stream, dp_packet_data(txbuf), dp_packet_size(txbuf));
|
2014-02-07 14:45:14 -08:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
if (retval > 0) {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
dp_packet_pull(txbuf, retval);
|
|
|
|
|
if (!dp_packet_size(txbuf)) {
|
2015-05-18 10:47:45 -07:00
|
|
|
|
list_remove(&txbuf_node->list_node);
|
|
|
|
|
free(txbuf_node);
|
2015-02-22 03:21:09 -08:00
|
|
|
|
dp_packet_delete(txbuf);
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
2013-12-18 13:55:25 -08:00
|
|
|
|
} else if (retval != -EAGAIN) {
|
|
|
|
|
error = -retval;
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
2013-12-18 13:55:25 -08:00
|
|
|
|
}
|
2013-07-25 16:11:52 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
if (!error) {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
if (dp_packet_size(&s->rxbuf) < 2) {
|
|
|
|
|
n = 2 - dp_packet_size(&s->rxbuf);
|
2013-12-18 13:55:25 -08:00
|
|
|
|
} else {
|
|
|
|
|
uint16_t frame_len;
|
|
|
|
|
|
2015-02-22 03:21:09 -08:00
|
|
|
|
frame_len = ntohs(get_unaligned_be16(dp_packet_data(&s->rxbuf)));
|
2013-12-18 13:55:25 -08:00
|
|
|
|
if (frame_len < ETH_HEADER_LEN) {
|
|
|
|
|
error = EPROTO;
|
|
|
|
|
n = 0;
|
|
|
|
|
} else {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
n = (2 + frame_len) - dp_packet_size(&s->rxbuf);
|
2013-12-18 13:55:25 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
2013-12-18 13:55:25 -08:00
|
|
|
|
if (!error) {
|
|
|
|
|
int retval;
|
|
|
|
|
|
2015-02-22 03:21:09 -08:00
|
|
|
|
dp_packet_prealloc_tailroom(&s->rxbuf, n);
|
|
|
|
|
retval = stream_recv(s->stream, dp_packet_tail(&s->rxbuf), n);
|
2014-02-07 14:45:14 -08:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
if (retval > 0) {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
dp_packet_set_size(&s->rxbuf, dp_packet_size(&s->rxbuf) + retval);
|
|
|
|
|
if (retval == n && dp_packet_size(&s->rxbuf) > 2) {
|
|
|
|
|
dp_packet_pull(&s->rxbuf, 2);
|
2013-12-18 13:55:25 -08:00
|
|
|
|
netdev_dummy_queue_packet(dev,
|
2015-02-22 03:21:09 -08:00
|
|
|
|
dp_packet_clone(&s->rxbuf));
|
|
|
|
|
dp_packet_clear(&s->rxbuf);
|
2013-12-18 13:55:25 -08:00
|
|
|
|
}
|
|
|
|
|
} else if (retval != -EAGAIN) {
|
|
|
|
|
error = (retval < 0 ? -retval
|
2015-02-22 03:21:09 -08:00
|
|
|
|
: dp_packet_size(&s->rxbuf) ? EPROTO
|
2013-12-18 13:55:25 -08:00
|
|
|
|
: EOF);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return error;
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2013-12-18 13:55:25 -08:00
|
|
|
|
dummy_packet_stream_close(struct dummy_packet_stream *s)
|
2012-10-25 16:54:23 -07:00
|
|
|
|
{
|
|
|
|
|
stream_close(s->stream);
|
2015-02-22 03:21:09 -08:00
|
|
|
|
dp_packet_uninit(&s->rxbuf);
|
2015-05-18 10:47:45 -07:00
|
|
|
|
pkt_list_delete(&s->txq);
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2013-12-18 13:55:25 -08:00
|
|
|
|
dummy_packet_conn_init(struct dummy_packet_conn *conn)
|
2012-10-25 16:54:23 -07:00
|
|
|
|
{
|
2013-12-18 13:55:25 -08:00
|
|
|
|
memset(conn, 0, sizeof *conn);
|
|
|
|
|
conn->type = NONE;
|
|
|
|
|
}
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
static void
|
|
|
|
|
dummy_packet_conn_get_config(struct dummy_packet_conn *conn, struct smap *args)
|
|
|
|
|
{
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
switch (conn->type) {
|
|
|
|
|
case PASSIVE:
|
|
|
|
|
smap_add(args, "pstream", pstream_get_name(conn->u.pconn.pstream));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ACTIVE:
|
|
|
|
|
smap_add(args, "stream", stream_get_name(conn->u.rconn.rstream->stream));
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NONE:
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dummy_packet_conn_close(struct dummy_packet_conn *conn)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
struct dummy_packet_pconn *pconn = &conn->u.pconn;
|
|
|
|
|
struct dummy_packet_rconn *rconn = &conn->u.rconn;
|
|
|
|
|
|
|
|
|
|
switch (conn->type) {
|
|
|
|
|
case PASSIVE:
|
|
|
|
|
pstream_close(pconn->pstream);
|
|
|
|
|
for (i = 0; i < pconn->n_streams; i++) {
|
|
|
|
|
dummy_packet_stream_close(&pconn->streams[i]);
|
|
|
|
|
}
|
|
|
|
|
free(pconn->streams);
|
|
|
|
|
pconn->pstream = NULL;
|
|
|
|
|
pconn->streams = NULL;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ACTIVE:
|
|
|
|
|
dummy_packet_stream_close(rconn->rstream);
|
|
|
|
|
free(rconn->rstream);
|
|
|
|
|
rconn->rstream = NULL;
|
|
|
|
|
reconnect_destroy(rconn->reconnect);
|
|
|
|
|
rconn->reconnect = NULL;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NONE:
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conn->type = NONE;
|
|
|
|
|
memset(conn, 0, sizeof *conn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dummy_packet_conn_set_config(struct dummy_packet_conn *conn,
|
|
|
|
|
const struct smap *args)
|
|
|
|
|
{
|
|
|
|
|
const char *pstream = smap_get(args, "pstream");
|
|
|
|
|
const char *stream = smap_get(args, "stream");
|
|
|
|
|
|
|
|
|
|
if (pstream && stream) {
|
|
|
|
|
VLOG_WARN("Open failed: both %s and %s are configured",
|
|
|
|
|
pstream, stream);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (conn->type) {
|
|
|
|
|
case PASSIVE:
|
2015-04-16 14:38:36 -07:00
|
|
|
|
if (pstream &&
|
|
|
|
|
!strcmp(pstream_get_name(conn->u.pconn.pstream), pstream)) {
|
2013-12-18 13:55:25 -08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
dummy_packet_conn_close(conn);
|
|
|
|
|
break;
|
|
|
|
|
case ACTIVE:
|
2015-04-16 14:38:36 -07:00
|
|
|
|
if (stream &&
|
|
|
|
|
!strcmp(stream_get_name(conn->u.rconn.rstream->stream), stream)) {
|
2013-12-18 13:55:25 -08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
dummy_packet_conn_close(conn);
|
|
|
|
|
break;
|
|
|
|
|
case NONE:
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pstream) {
|
|
|
|
|
int error;
|
|
|
|
|
|
|
|
|
|
error = pstream_open(pstream, &conn->u.pconn.pstream, DSCP_DEFAULT);
|
|
|
|
|
if (error) {
|
|
|
|
|
VLOG_WARN("%s: open failed (%s)", pstream, ovs_strerror(error));
|
|
|
|
|
} else {
|
|
|
|
|
conn->type = PASSIVE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stream) {
|
|
|
|
|
int error;
|
|
|
|
|
struct stream *active_stream;
|
2015-07-22 08:30:15 -07:00
|
|
|
|
struct reconnect *reconnect;
|
2013-12-18 13:55:25 -08:00
|
|
|
|
|
|
|
|
|
reconnect = reconnect_create(time_msec());
|
|
|
|
|
reconnect_set_name(reconnect, stream);
|
|
|
|
|
reconnect_set_passive(reconnect, false, time_msec());
|
|
|
|
|
reconnect_enable(reconnect, time_msec());
|
2014-02-07 17:25:42 -08:00
|
|
|
|
reconnect_set_backoff(reconnect, 100, INT_MAX);
|
2014-02-07 12:50:17 -08:00
|
|
|
|
reconnect_set_probe_interval(reconnect, 0);
|
2013-12-18 13:55:25 -08:00
|
|
|
|
conn->u.rconn.reconnect = reconnect;
|
2014-02-07 14:45:14 -08:00
|
|
|
|
conn->type = ACTIVE;
|
2013-12-18 13:55:25 -08:00
|
|
|
|
|
|
|
|
|
error = stream_open(stream, &active_stream, DSCP_DEFAULT);
|
|
|
|
|
conn->u.rconn.rstream = dummy_packet_stream_create(active_stream);
|
|
|
|
|
|
|
|
|
|
switch (error) {
|
|
|
|
|
case 0:
|
2014-02-07 14:45:14 -08:00
|
|
|
|
reconnect_connected(reconnect, time_msec());
|
2013-12-18 13:55:25 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EAGAIN:
|
2014-02-07 14:45:14 -08:00
|
|
|
|
reconnect_connecting(reconnect, time_msec());
|
2013-12-18 13:55:25 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2014-02-07 14:45:14 -08:00
|
|
|
|
reconnect_connect_failed(reconnect, time_msec(), error);
|
2013-12-18 13:55:25 -08:00
|
|
|
|
stream_close(active_stream);
|
2014-02-07 14:45:14 -08:00
|
|
|
|
conn->u.rconn.rstream->stream = NULL;
|
2013-12-18 13:55:25 -08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dummy_pconn_run(struct netdev_dummy *dev)
|
|
|
|
|
OVS_REQUIRES(dev->mutex)
|
|
|
|
|
{
|
|
|
|
|
struct stream *new_stream;
|
|
|
|
|
struct dummy_packet_pconn *pconn = &dev->conn.u.pconn;
|
|
|
|
|
int error;
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
error = pstream_accept(pconn->pstream, &new_stream);
|
|
|
|
|
if (!error) {
|
|
|
|
|
struct dummy_packet_stream *s;
|
|
|
|
|
|
|
|
|
|
pconn->streams = xrealloc(pconn->streams,
|
|
|
|
|
((pconn->n_streams + 1)
|
|
|
|
|
* sizeof *s));
|
|
|
|
|
s = &pconn->streams[pconn->n_streams++];
|
|
|
|
|
dummy_packet_stream_init(s, new_stream);
|
|
|
|
|
} else if (error != EAGAIN) {
|
|
|
|
|
VLOG_WARN("%s: accept failed (%s)",
|
|
|
|
|
pstream_get_name(pconn->pstream), ovs_strerror(error));
|
|
|
|
|
pstream_close(pconn->pstream);
|
|
|
|
|
pconn->pstream = NULL;
|
|
|
|
|
dev->conn.type = NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < pconn->n_streams; i++) {
|
|
|
|
|
struct dummy_packet_stream *s = &pconn->streams[i];
|
|
|
|
|
|
|
|
|
|
error = dummy_packet_stream_run(dev, s);
|
|
|
|
|
if (error) {
|
|
|
|
|
VLOG_DBG("%s: closing connection (%s)",
|
|
|
|
|
stream_get_name(s->stream),
|
|
|
|
|
ovs_retval_to_string(error));
|
|
|
|
|
dummy_packet_stream_close(s);
|
|
|
|
|
pconn->streams[i] = pconn->streams[--pconn->n_streams];
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
2013-12-18 13:55:25 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
static void
|
|
|
|
|
dummy_rconn_run(struct netdev_dummy *dev)
|
|
|
|
|
OVS_REQUIRES(dev->mutex)
|
|
|
|
|
{
|
|
|
|
|
struct dummy_packet_rconn *rconn = &dev->conn.u.rconn;
|
|
|
|
|
|
|
|
|
|
switch (reconnect_run(rconn->reconnect, time_msec())) {
|
|
|
|
|
case RECONNECT_CONNECT:
|
|
|
|
|
{
|
2014-02-07 14:45:14 -08:00
|
|
|
|
int error;
|
|
|
|
|
|
|
|
|
|
if (rconn->rstream->stream) {
|
|
|
|
|
error = stream_connect(rconn->rstream->stream);
|
|
|
|
|
} else {
|
|
|
|
|
error = stream_open(reconnect_get_name(rconn->reconnect),
|
|
|
|
|
&rconn->rstream->stream, DSCP_DEFAULT);
|
|
|
|
|
}
|
2013-12-18 13:55:25 -08:00
|
|
|
|
|
2014-02-07 14:45:14 -08:00
|
|
|
|
switch (error) {
|
|
|
|
|
case 0:
|
2013-12-18 13:55:25 -08:00
|
|
|
|
reconnect_connected(rconn->reconnect, time_msec());
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EAGAIN:
|
|
|
|
|
reconnect_connecting(rconn->reconnect, time_msec());
|
2014-02-07 14:45:14 -08:00
|
|
|
|
break;
|
2013-12-18 13:55:25 -08:00
|
|
|
|
|
|
|
|
|
default:
|
2014-02-07 14:45:14 -08:00
|
|
|
|
reconnect_connect_failed(rconn->reconnect, time_msec(), error);
|
2013-12-18 13:55:25 -08:00
|
|
|
|
stream_close(rconn->rstream->stream);
|
2014-02-07 14:45:14 -08:00
|
|
|
|
rconn->rstream->stream = NULL;
|
|
|
|
|
break;
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-12-18 13:55:25 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RECONNECT_DISCONNECT:
|
|
|
|
|
case RECONNECT_PROBE:
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (reconnect_is_connected(rconn->reconnect)) {
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
err = dummy_packet_stream_run(dev, rconn->rstream);
|
|
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
|
reconnect_disconnected(rconn->reconnect, time_msec(), err);
|
|
|
|
|
stream_close(rconn->rstream->stream);
|
2014-02-07 14:45:14 -08:00
|
|
|
|
rconn->rstream->stream = NULL;
|
2013-12-18 13:55:25 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dummy_packet_conn_run(struct netdev_dummy *dev)
|
|
|
|
|
OVS_REQUIRES(dev->mutex)
|
|
|
|
|
{
|
|
|
|
|
switch (dev->conn.type) {
|
|
|
|
|
case PASSIVE:
|
|
|
|
|
dummy_pconn_run(dev);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ACTIVE:
|
|
|
|
|
dummy_rconn_run(dev);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NONE:
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dummy_packet_conn_wait(struct dummy_packet_conn *conn)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
switch (conn->type) {
|
|
|
|
|
case PASSIVE:
|
|
|
|
|
pstream_wait(conn->u.pconn.pstream);
|
|
|
|
|
for (i = 0; i < conn->u.pconn.n_streams; i++) {
|
|
|
|
|
struct dummy_packet_stream *s = &conn->u.pconn.streams[i];
|
|
|
|
|
dummy_packet_stream_wait(s);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ACTIVE:
|
2014-02-07 14:45:14 -08:00
|
|
|
|
if (reconnect_is_connected(conn->u.rconn.reconnect)) {
|
|
|
|
|
dummy_packet_stream_wait(conn->u.rconn.rstream);
|
|
|
|
|
}
|
2013-12-18 13:55:25 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NONE:
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dummy_packet_conn_send(struct dummy_packet_conn *conn,
|
|
|
|
|
const void *buffer, size_t size)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
switch (conn->type) {
|
|
|
|
|
case PASSIVE:
|
|
|
|
|
for (i = 0; i < conn->u.pconn.n_streams; i++) {
|
|
|
|
|
struct dummy_packet_stream *s = &conn->u.pconn.streams[i];
|
|
|
|
|
|
|
|
|
|
dummy_packet_stream_send(s, buffer, size);
|
|
|
|
|
pstream_wait(conn->u.pconn.pstream);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ACTIVE:
|
2014-02-07 14:45:14 -08:00
|
|
|
|
if (reconnect_is_connected(conn->u.rconn.reconnect)) {
|
|
|
|
|
dummy_packet_stream_send(conn->u.rconn.rstream, buffer, size);
|
|
|
|
|
dummy_packet_stream_wait(conn->u.rconn.rstream);
|
|
|
|
|
}
|
2013-12-18 13:55:25 -08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NONE:
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-05 16:01:17 -07:00
|
|
|
|
static enum dummy_netdev_conn_state
|
|
|
|
|
dummy_netdev_get_conn_state(struct dummy_packet_conn *conn)
|
|
|
|
|
{
|
|
|
|
|
enum dummy_netdev_conn_state state;
|
|
|
|
|
|
|
|
|
|
if (conn->type == ACTIVE) {
|
|
|
|
|
if (reconnect_is_connected(conn->u.rconn.reconnect)) {
|
|
|
|
|
state = CONN_STATE_CONNECTED;
|
|
|
|
|
} else {
|
|
|
|
|
state = CONN_STATE_NOT_CONNECTED;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
state = CONN_STATE_UNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return state;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
static void
|
|
|
|
|
netdev_dummy_run(void)
|
|
|
|
|
{
|
|
|
|
|
struct netdev_dummy *dev;
|
|
|
|
|
|
|
|
|
|
ovs_mutex_lock(&dummy_list_mutex);
|
|
|
|
|
LIST_FOR_EACH (dev, list_node, &dummy_list) {
|
|
|
|
|
ovs_mutex_lock(&dev->mutex);
|
|
|
|
|
dummy_packet_conn_run(dev);
|
|
|
|
|
ovs_mutex_unlock(&dev->mutex);
|
|
|
|
|
}
|
|
|
|
|
ovs_mutex_unlock(&dummy_list_mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
netdev_dummy_wait(void)
|
|
|
|
|
{
|
|
|
|
|
struct netdev_dummy *dev;
|
|
|
|
|
|
|
|
|
|
ovs_mutex_lock(&dummy_list_mutex);
|
|
|
|
|
LIST_FOR_EACH (dev, list_node, &dummy_list) {
|
|
|
|
|
ovs_mutex_lock(&dev->mutex);
|
|
|
|
|
dummy_packet_conn_wait(&dev->conn);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&dev->mutex);
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
2013-08-12 12:49:23 -07:00
|
|
|
|
ovs_mutex_unlock(&dummy_list_mutex);
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
|
|
|
|
|
2013-08-09 21:21:38 -07:00
|
|
|
|
static struct netdev *
|
|
|
|
|
netdev_dummy_alloc(void)
|
|
|
|
|
{
|
|
|
|
|
struct netdev_dummy *netdev = xzalloc(sizeof *netdev);
|
|
|
|
|
return &netdev->up;
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-29 12:21:08 -08:00
|
|
|
|
static int
|
2013-08-09 21:21:38 -07:00
|
|
|
|
netdev_dummy_construct(struct netdev *netdev_)
|
2010-11-29 12:21:08 -08:00
|
|
|
|
{
|
2014-08-29 10:34:53 -07:00
|
|
|
|
static atomic_count next_n = ATOMIC_COUNT_INIT(0xaa550000);
|
2013-08-09 21:21:38 -07:00
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
2013-04-26 12:58:14 -07:00
|
|
|
|
unsigned int n;
|
|
|
|
|
|
2014-08-29 10:34:53 -07:00
|
|
|
|
n = atomic_count_inc(&next_n);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
|
Use "error-checking" mutexes in place of other kinds wherever possible.
We've seen a number of deadlocks in the tree since thread safety was
introduced. So far, all of these are self-deadlocks, that is, a single
thread acquiring a lock and then attempting to re-acquire the same lock
recursively. When this has happened, the process simply hung, and it was
somewhat difficult to find the cause.
POSIX "error-checking" mutexes check for this specific problem (and
others). This commit switches from other types of mutexes to
error-checking mutexes everywhere that we can, that is, everywhere that
we're not using recursive mutexes. This ought to help find problems more
quickly in the future.
There might be performance advantages to other kinds of mutexes in some
cases. However, the existing mutex type choices were just guesses, so I'd
rather go for easy detection of errors until we know that other mutex
types actually perform better in specific cases. Also, I did a quick
microbenchmark of glibc mutex types on my host and found that the
error checking mutexes weren't any slower than the other types, at least
when the mutex is uncontended.
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Ethan Jackson <ethan@nicira.com>
2013-08-20 13:40:02 -07:00
|
|
|
|
ovs_mutex_init(&netdev->mutex);
|
2013-08-16 14:04:08 -07:00
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
2015-08-28 14:55:11 -07:00
|
|
|
|
netdev->hwaddr.ea[0] = 0xaa;
|
|
|
|
|
netdev->hwaddr.ea[1] = 0x55;
|
|
|
|
|
netdev->hwaddr.ea[2] = n >> 24;
|
|
|
|
|
netdev->hwaddr.ea[3] = n >> 16;
|
|
|
|
|
netdev->hwaddr.ea[4] = n >> 8;
|
|
|
|
|
netdev->hwaddr.ea[5] = n;
|
2013-03-15 15:54:36 -07:00
|
|
|
|
netdev->mtu = 1500;
|
|
|
|
|
netdev->flags = 0;
|
|
|
|
|
netdev->ifindex = -EOPNOTSUPP;
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
dummy_packet_conn_init(&netdev->conn);
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2013-03-15 15:54:36 -07:00
|
|
|
|
list_init(&netdev->rxes);
|
2013-08-16 14:04:08 -07:00
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
2013-03-15 15:54:36 -07:00
|
|
|
|
|
2013-08-12 12:49:23 -07:00
|
|
|
|
ovs_mutex_lock(&dummy_list_mutex);
|
|
|
|
|
list_push_back(&dummy_list, &netdev->list_node);
|
|
|
|
|
ovs_mutex_unlock(&dummy_list_mutex);
|
|
|
|
|
|
2010-11-29 12:21:08 -08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2013-08-09 21:21:38 -07:00
|
|
|
|
netdev_dummy_destruct(struct netdev *netdev_)
|
2010-11-29 12:21:08 -08:00
|
|
|
|
{
|
2013-03-15 15:54:36 -07:00
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
|
2013-08-12 12:49:23 -07:00
|
|
|
|
ovs_mutex_lock(&dummy_list_mutex);
|
|
|
|
|
list_remove(&netdev->list_node);
|
|
|
|
|
ovs_mutex_unlock(&dummy_list_mutex);
|
|
|
|
|
|
2013-08-16 14:04:08 -07:00
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
2013-12-18 13:55:25 -08:00
|
|
|
|
dummy_packet_conn_close(&netdev->conn);
|
|
|
|
|
netdev->conn.type = NONE;
|
|
|
|
|
|
2013-08-16 14:04:08 -07:00
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_destroy(&netdev->mutex);
|
2013-08-09 21:21:38 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
netdev_dummy_dealloc(struct netdev *netdev_)
|
|
|
|
|
{
|
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
|
|
|
|
|
2013-03-15 15:54:36 -07:00
|
|
|
|
free(netdev);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
}
|
|
|
|
|
|
2013-03-27 23:02:21 -07:00
|
|
|
|
static int
|
2013-03-15 15:54:36 -07:00
|
|
|
|
netdev_dummy_get_config(const struct netdev *netdev_, struct smap *args)
|
2013-03-27 23:02:21 -07:00
|
|
|
|
{
|
2013-03-15 15:54:36 -07:00
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
2013-03-27 23:02:21 -07:00
|
|
|
|
|
2013-08-12 12:51:47 -07:00
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
2013-09-23 10:26:51 -07:00
|
|
|
|
|
2013-03-15 15:54:36 -07:00
|
|
|
|
if (netdev->ifindex >= 0) {
|
|
|
|
|
smap_add_format(args, "ifindex", "%d", netdev->ifindex);
|
2013-03-27 23:02:21 -07:00
|
|
|
|
}
|
2013-09-23 10:26:51 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
dummy_packet_conn_get_config(&netdev->conn, args);
|
2013-08-12 12:51:47 -07:00
|
|
|
|
|
2013-09-23 10:26:51 -07:00
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
2013-03-27 23:02:21 -07:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-11 11:53:47 -08:00
|
|
|
|
static int
|
|
|
|
|
netdev_dummy_get_in4(const struct netdev *netdev_,
|
|
|
|
|
struct in_addr *address, struct in_addr *netmask)
|
|
|
|
|
{
|
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
|
|
|
|
|
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
|
|
|
|
*address = netdev->address;
|
|
|
|
|
*netmask = netdev->netmask;
|
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
2015-05-09 23:58:41 -07:00
|
|
|
|
|
|
|
|
|
return address->s_addr ? 0 : EADDRNOTAVAIL;
|
2014-11-11 11:53:47 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
netdev_dummy_set_in4(struct netdev *netdev_, struct in_addr address,
|
|
|
|
|
struct in_addr netmask)
|
|
|
|
|
{
|
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
|
|
|
|
|
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
|
|
|
|
netdev->address = address;
|
|
|
|
|
netdev->netmask = netmask;
|
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-27 23:02:21 -07:00
|
|
|
|
static int
|
2013-03-15 15:54:36 -07:00
|
|
|
|
netdev_dummy_set_config(struct netdev *netdev_, const struct smap *args)
|
2010-11-29 12:21:08 -08:00
|
|
|
|
{
|
2013-03-15 15:54:36 -07:00
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
2013-09-23 10:26:51 -07:00
|
|
|
|
const char *pcap;
|
2010-11-29 12:21:08 -08:00
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
2013-03-15 15:54:36 -07:00
|
|
|
|
netdev->ifindex = smap_get_int(args, "ifindex", -EOPNOTSUPP);
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2013-12-18 13:55:25 -08:00
|
|
|
|
dummy_packet_conn_set_config(&netdev->conn, args);
|
2013-09-23 10:26:51 -07:00
|
|
|
|
|
2014-03-20 19:38:14 -07:00
|
|
|
|
if (netdev->rxq_pcap) {
|
|
|
|
|
fclose(netdev->rxq_pcap);
|
2013-09-23 10:26:51 -07:00
|
|
|
|
}
|
2014-03-20 19:38:14 -07:00
|
|
|
|
if (netdev->tx_pcap && netdev->tx_pcap != netdev->rxq_pcap) {
|
2013-09-23 10:26:51 -07:00
|
|
|
|
fclose(netdev->tx_pcap);
|
|
|
|
|
}
|
2014-03-20 19:38:14 -07:00
|
|
|
|
netdev->rxq_pcap = netdev->tx_pcap = NULL;
|
2013-09-23 10:26:51 -07:00
|
|
|
|
pcap = smap_get(args, "pcap");
|
|
|
|
|
if (pcap) {
|
2014-03-20 19:38:14 -07:00
|
|
|
|
netdev->rxq_pcap = netdev->tx_pcap = ovs_pcap_open(pcap, "ab");
|
2013-09-23 10:26:51 -07:00
|
|
|
|
} else {
|
2014-03-20 19:38:14 -07:00
|
|
|
|
const char *rxq_pcap = smap_get(args, "rxq_pcap");
|
2013-09-23 10:26:51 -07:00
|
|
|
|
const char *tx_pcap = smap_get(args, "tx_pcap");
|
|
|
|
|
|
2014-03-20 19:38:14 -07:00
|
|
|
|
if (rxq_pcap) {
|
|
|
|
|
netdev->rxq_pcap = ovs_pcap_open(rxq_pcap, "ab");
|
2013-09-23 10:26:51 -07:00
|
|
|
|
}
|
|
|
|
|
if (tx_pcap) {
|
2014-01-23 17:24:03 +01:00
|
|
|
|
netdev->tx_pcap = ovs_pcap_open(tx_pcap, "ab");
|
2013-09-23 10:26:51 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
|
|
|
|
|
2010-11-29 12:21:08 -08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-20 19:38:14 -07:00
|
|
|
|
static struct netdev_rxq *
|
|
|
|
|
netdev_dummy_rxq_alloc(void)
|
2013-08-09 21:21:38 -07:00
|
|
|
|
{
|
2014-03-20 19:38:14 -07:00
|
|
|
|
struct netdev_rxq_dummy *rx = xzalloc(sizeof *rx);
|
2013-08-09 21:21:38 -07:00
|
|
|
|
return &rx->up;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-05 14:15:32 -07:00
|
|
|
|
static int
|
2014-03-20 19:38:14 -07:00
|
|
|
|
netdev_dummy_rxq_construct(struct netdev_rxq *rxq_)
|
2011-08-05 14:15:32 -07:00
|
|
|
|
{
|
2014-03-20 19:38:14 -07:00
|
|
|
|
struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_);
|
2013-08-09 21:21:38 -07:00
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
|
2013-05-10 14:39:19 -07:00
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
2013-03-15 15:54:36 -07:00
|
|
|
|
list_push_back(&netdev->rxes, &rx->node);
|
2013-05-10 14:39:19 -07:00
|
|
|
|
list_init(&rx->recv_queue);
|
2012-08-16 16:37:32 -07:00
|
|
|
|
rx->recv_queue_len = 0;
|
2013-12-25 22:27:25 -08:00
|
|
|
|
rx->seq = seq_create();
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
2013-05-10 14:39:19 -07:00
|
|
|
|
|
2011-08-05 14:15:32 -07:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-09 21:21:38 -07:00
|
|
|
|
static void
|
2014-03-20 19:38:14 -07:00
|
|
|
|
netdev_dummy_rxq_destruct(struct netdev_rxq *rxq_)
|
2013-08-09 21:21:38 -07:00
|
|
|
|
{
|
2014-03-20 19:38:14 -07:00
|
|
|
|
struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
|
2013-08-09 21:21:38 -07:00
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
2013-08-09 21:21:38 -07:00
|
|
|
|
list_remove(&rx->node);
|
2015-05-18 10:47:45 -07:00
|
|
|
|
pkt_list_delete(&rx->recv_queue);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
2013-12-25 22:27:25 -08:00
|
|
|
|
seq_destroy(rx->seq);
|
2013-08-09 21:21:38 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-03-20 19:38:14 -07:00
|
|
|
|
netdev_dummy_rxq_dealloc(struct netdev_rxq *rxq_)
|
2013-08-09 21:21:38 -07:00
|
|
|
|
{
|
2014-03-20 19:38:14 -07:00
|
|
|
|
struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_);
|
2013-08-09 21:21:38 -07:00
|
|
|
|
|
|
|
|
|
free(rx);
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-05 14:15:32 -07:00
|
|
|
|
static int
|
2015-02-25 12:01:53 -08:00
|
|
|
|
netdev_dummy_rxq_recv(struct netdev_rxq *rxq_, struct dp_packet **arr,
|
2014-06-23 11:43:57 -07:00
|
|
|
|
int *c)
|
2011-12-06 14:22:27 -08:00
|
|
|
|
{
|
2014-03-20 19:38:14 -07:00
|
|
|
|
struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
|
2015-02-22 03:21:09 -08:00
|
|
|
|
struct dp_packet *packet;
|
2011-12-06 14:22:27 -08:00
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
|
|
|
|
if (!list_is_empty(&rx->recv_queue)) {
|
2015-05-18 10:47:45 -07:00
|
|
|
|
struct pkt_list_node *pkt_node;
|
|
|
|
|
|
|
|
|
|
ASSIGN_CONTAINER(pkt_node, list_pop_front(&rx->recv_queue), list_node);
|
|
|
|
|
packet = pkt_node->pkt;
|
|
|
|
|
free(pkt_node);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
rx->recv_queue_len--;
|
|
|
|
|
} else {
|
|
|
|
|
packet = NULL;
|
|
|
|
|
}
|
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
|
|
|
|
|
|
|
|
|
if (!packet) {
|
2014-01-15 17:17:00 +09:00
|
|
|
|
return EAGAIN;
|
2011-12-06 14:22:27 -08:00
|
|
|
|
}
|
2014-03-20 10:54:37 -07:00
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
|
|
|
|
netdev->stats.rx_packets++;
|
2015-02-22 03:21:09 -08:00
|
|
|
|
netdev->stats.rx_bytes += dp_packet_size(packet);
|
2014-03-20 10:54:37 -07:00
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
2011-12-06 14:22:27 -08:00
|
|
|
|
|
2014-03-20 10:54:37 -07:00
|
|
|
|
dp_packet_pad(packet);
|
2015-06-16 19:16:24 +01:00
|
|
|
|
dp_packet_rss_invalidate(packet);
|
2014-06-23 11:43:57 -07:00
|
|
|
|
|
2015-02-22 03:21:09 -08:00
|
|
|
|
arr[0] = packet;
|
2014-03-20 10:54:37 -07:00
|
|
|
|
*c = 1;
|
|
|
|
|
return 0;
|
2011-12-06 14:22:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-03-20 19:38:14 -07:00
|
|
|
|
netdev_dummy_rxq_wait(struct netdev_rxq *rxq_)
|
2013-05-10 14:39:19 -07:00
|
|
|
|
{
|
2014-03-20 19:38:14 -07:00
|
|
|
|
struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
|
2013-12-25 22:27:25 -08:00
|
|
|
|
uint64_t seq = seq_read(rx->seq);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
|
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
2013-05-10 14:39:19 -07:00
|
|
|
|
if (!list_is_empty(&rx->recv_queue)) {
|
2011-12-06 14:22:27 -08:00
|
|
|
|
poll_immediate_wake();
|
2013-12-25 22:27:25 -08:00
|
|
|
|
} else {
|
|
|
|
|
seq_wait(rx->seq, seq);
|
2011-12-06 14:22:27 -08:00
|
|
|
|
}
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
2011-12-06 14:22:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2014-03-20 19:38:14 -07:00
|
|
|
|
netdev_dummy_rxq_drain(struct netdev_rxq *rxq_)
|
2011-12-06 14:22:27 -08:00
|
|
|
|
{
|
2014-03-20 19:38:14 -07:00
|
|
|
|
struct netdev_rxq_dummy *rx = netdev_rxq_dummy_cast(rxq_);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
|
|
|
|
|
|
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
2015-05-18 10:47:45 -07:00
|
|
|
|
pkt_list_delete(&rx->recv_queue);
|
2012-08-16 16:37:32 -07:00
|
|
|
|
rx->recv_queue_len = 0;
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
|
|
|
|
|
2013-12-25 22:27:25 -08:00
|
|
|
|
seq_change(rx->seq);
|
|
|
|
|
|
2011-12-06 14:22:27 -08:00
|
|
|
|
return 0;
|
2011-08-05 14:15:32 -07:00
|
|
|
|
}
|
|
|
|
|
|
2012-09-18 11:06:08 -07:00
|
|
|
|
static int
|
2014-09-03 14:37:35 -07:00
|
|
|
|
netdev_dummy_send(struct netdev *netdev, int qid OVS_UNUSED,
|
2015-02-25 12:01:53 -08:00
|
|
|
|
struct dp_packet **pkts, int cnt, bool may_steal)
|
2012-09-18 11:06:08 -07:00
|
|
|
|
{
|
2013-03-15 15:54:36 -07:00
|
|
|
|
struct netdev_dummy *dev = netdev_dummy_cast(netdev);
|
2014-06-23 11:43:58 -07:00
|
|
|
|
int error = 0;
|
|
|
|
|
int i;
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2014-06-23 11:43:58 -07:00
|
|
|
|
for (i = 0; i < cnt; i++) {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
const void *buffer = dp_packet_data(pkts[i]);
|
|
|
|
|
size_t size = dp_packet_size(pkts[i]);
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2014-06-23 11:43:58 -07:00
|
|
|
|
if (size < ETH_HEADER_LEN) {
|
|
|
|
|
error = EMSGSIZE;
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
const struct eth_header *eth = buffer;
|
|
|
|
|
int max_size;
|
2013-08-16 14:04:08 -07:00
|
|
|
|
|
2014-06-23 11:43:58 -07:00
|
|
|
|
ovs_mutex_lock(&dev->mutex);
|
|
|
|
|
max_size = dev->mtu + ETH_HEADER_LEN;
|
|
|
|
|
ovs_mutex_unlock(&dev->mutex);
|
|
|
|
|
|
|
|
|
|
if (eth->eth_type == htons(ETH_TYPE_VLAN)) {
|
|
|
|
|
max_size += VLAN_HEADER_LEN;
|
|
|
|
|
}
|
|
|
|
|
if (size > max_size) {
|
|
|
|
|
error = EMSGSIZE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
2012-09-18 11:06:08 -07:00
|
|
|
|
|
2014-06-23 11:43:58 -07:00
|
|
|
|
ovs_mutex_lock(&dev->mutex);
|
|
|
|
|
dev->stats.tx_packets++;
|
|
|
|
|
dev->stats.tx_bytes += size;
|
|
|
|
|
|
|
|
|
|
dummy_packet_conn_send(&dev->conn, buffer, size);
|
2012-09-18 11:06:08 -07:00
|
|
|
|
|
2015-05-10 00:01:59 -07:00
|
|
|
|
/* Reply to ARP requests for 'dev''s assigned IP address. */
|
|
|
|
|
if (dev->address.s_addr) {
|
|
|
|
|
struct dp_packet packet;
|
|
|
|
|
struct flow flow;
|
|
|
|
|
|
|
|
|
|
dp_packet_use_const(&packet, buffer, size);
|
|
|
|
|
flow_extract(&packet, &flow);
|
|
|
|
|
if (flow.dl_type == htons(ETH_TYPE_ARP)
|
|
|
|
|
&& flow.nw_proto == ARP_OP_REQUEST
|
|
|
|
|
&& flow.nw_dst == dev->address.s_addr) {
|
|
|
|
|
struct dp_packet *reply = dp_packet_new(0);
|
|
|
|
|
compose_arp(reply, ARP_OP_REPLY, dev->hwaddr, flow.dl_src,
|
|
|
|
|
false, flow.nw_dst, flow.nw_src);
|
|
|
|
|
netdev_dummy_queue_packet(dev, reply);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-23 11:43:58 -07:00
|
|
|
|
if (dev->tx_pcap) {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
struct dp_packet packet;
|
2013-12-18 13:55:25 -08:00
|
|
|
|
|
2015-02-22 03:21:09 -08:00
|
|
|
|
dp_packet_use_const(&packet, buffer, size);
|
2014-06-23 11:43:58 -07:00
|
|
|
|
ovs_pcap_write(dev->tx_pcap, &packet);
|
|
|
|
|
fflush(dev->tx_pcap);
|
|
|
|
|
}
|
2013-09-23 10:26:51 -07:00
|
|
|
|
|
2014-06-23 11:43:58 -07:00
|
|
|
|
ovs_mutex_unlock(&dev->mutex);
|
2013-09-23 10:26:51 -07:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-20 10:56:51 -07:00
|
|
|
|
if (may_steal) {
|
2014-06-23 11:43:58 -07:00
|
|
|
|
for (i = 0; i < cnt; i++) {
|
2015-02-25 12:01:53 -08:00
|
|
|
|
dp_packet_delete(pkts[i]);
|
2014-06-23 11:43:58 -07:00
|
|
|
|
}
|
2014-03-20 10:56:51 -07:00
|
|
|
|
}
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2014-06-23 11:43:58 -07:00
|
|
|
|
return error;
|
2012-09-18 11:06:08 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-29 12:21:08 -08:00
|
|
|
|
static int
|
2015-08-28 14:55:11 -07:00
|
|
|
|
netdev_dummy_set_etheraddr(struct netdev *netdev, const struct eth_addr mac)
|
2010-11-29 12:21:08 -08:00
|
|
|
|
{
|
2013-03-15 15:54:36 -07:00
|
|
|
|
struct netdev_dummy *dev = netdev_dummy_cast(netdev);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_lock(&dev->mutex);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
if (!eth_addr_equals(dev->hwaddr, mac)) {
|
2015-08-28 14:55:11 -07:00
|
|
|
|
dev->hwaddr = mac;
|
2014-04-03 00:17:34 -07:00
|
|
|
|
netdev_change_seq_changed(netdev);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
}
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&dev->mutex);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2015-08-28 14:55:11 -07:00
|
|
|
|
netdev_dummy_get_etheraddr(const struct netdev *netdev, struct eth_addr *mac)
|
2010-11-29 12:21:08 -08:00
|
|
|
|
{
|
2013-08-09 21:34:02 -07:00
|
|
|
|
struct netdev_dummy *dev = netdev_dummy_cast(netdev);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_lock(&dev->mutex);
|
2015-08-28 14:55:11 -07:00
|
|
|
|
*mac = dev->hwaddr;
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&dev->mutex);
|
|
|
|
|
|
2010-11-29 12:21:08 -08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
netdev_dummy_get_mtu(const struct netdev *netdev, int *mtup)
|
|
|
|
|
{
|
2013-08-09 21:34:02 -07:00
|
|
|
|
struct netdev_dummy *dev = netdev_dummy_cast(netdev);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_lock(&dev->mutex);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
*mtup = dev->mtu;
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&dev->mutex);
|
|
|
|
|
|
2010-11-29 12:21:08 -08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-12 17:12:52 -07:00
|
|
|
|
static int
|
|
|
|
|
netdev_dummy_set_mtu(const struct netdev *netdev, int mtu)
|
|
|
|
|
{
|
2013-03-15 15:54:36 -07:00
|
|
|
|
struct netdev_dummy *dev = netdev_dummy_cast(netdev);
|
2011-09-12 17:12:52 -07:00
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_lock(&dev->mutex);
|
2011-09-12 17:12:52 -07:00
|
|
|
|
dev->mtu = mtu;
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&dev->mutex);
|
|
|
|
|
|
2011-09-12 17:12:52 -07:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-29 12:21:08 -08:00
|
|
|
|
static int
|
|
|
|
|
netdev_dummy_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
|
|
|
|
|
{
|
2013-08-09 21:34:02 -07:00
|
|
|
|
struct netdev_dummy *dev = netdev_dummy_cast(netdev);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_lock(&dev->mutex);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
*stats = dev->stats;
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&dev->mutex);
|
|
|
|
|
|
2010-11-29 12:21:08 -08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-27 23:02:21 -07:00
|
|
|
|
static int
|
|
|
|
|
netdev_dummy_get_ifindex(const struct netdev *netdev)
|
|
|
|
|
{
|
2013-03-15 15:54:36 -07:00
|
|
|
|
struct netdev_dummy *dev = netdev_dummy_cast(netdev);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
int ifindex;
|
|
|
|
|
|
|
|
|
|
ovs_mutex_lock(&dev->mutex);
|
|
|
|
|
ifindex = dev->ifindex;
|
|
|
|
|
ovs_mutex_unlock(&dev->mutex);
|
2013-03-27 23:02:21 -07:00
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
return ifindex;
|
2013-03-27 23:02:21 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-11-29 12:21:08 -08:00
|
|
|
|
static int
|
2013-08-09 21:34:02 -07:00
|
|
|
|
netdev_dummy_update_flags__(struct netdev_dummy *netdev,
|
|
|
|
|
enum netdev_flags off, enum netdev_flags on,
|
|
|
|
|
enum netdev_flags *old_flagsp)
|
|
|
|
|
OVS_REQUIRES(netdev->mutex)
|
2010-11-29 12:21:08 -08:00
|
|
|
|
{
|
|
|
|
|
if ((off | on) & ~(NETDEV_UP | NETDEV_PROMISC)) {
|
|
|
|
|
return EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-15 15:54:36 -07:00
|
|
|
|
*old_flagsp = netdev->flags;
|
|
|
|
|
netdev->flags |= on;
|
|
|
|
|
netdev->flags &= ~off;
|
|
|
|
|
if (*old_flagsp != netdev->flags) {
|
2014-04-03 00:17:34 -07:00
|
|
|
|
netdev_change_seq_changed(&netdev->up);
|
2010-11-29 12:21:08 -08:00
|
|
|
|
}
|
2013-08-09 21:34:02 -07:00
|
|
|
|
|
2010-11-29 12:21:08 -08:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
static int
|
|
|
|
|
netdev_dummy_update_flags(struct netdev *netdev_,
|
|
|
|
|
enum netdev_flags off, enum netdev_flags on,
|
|
|
|
|
enum netdev_flags *old_flagsp)
|
|
|
|
|
{
|
|
|
|
|
struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
|
|
|
|
|
int error;
|
|
|
|
|
|
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
|
|
|
|
error = netdev_dummy_update_flags__(netdev, off, on, old_flagsp);
|
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
|
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
2010-11-29 12:21:08 -08:00
|
|
|
|
|
|
|
|
|
/* Helper functions. */
|
|
|
|
|
|
|
|
|
|
static const struct netdev_class dummy_class = {
|
|
|
|
|
"dummy",
|
|
|
|
|
NULL, /* init */
|
2012-10-25 16:54:23 -07:00
|
|
|
|
netdev_dummy_run,
|
|
|
|
|
netdev_dummy_wait,
|
2010-11-29 12:21:08 -08:00
|
|
|
|
|
2013-08-09 21:21:38 -07:00
|
|
|
|
netdev_dummy_alloc,
|
|
|
|
|
netdev_dummy_construct,
|
|
|
|
|
netdev_dummy_destruct,
|
|
|
|
|
netdev_dummy_dealloc,
|
2013-03-27 23:02:21 -07:00
|
|
|
|
netdev_dummy_get_config,
|
|
|
|
|
netdev_dummy_set_config,
|
2013-01-07 16:56:04 -08:00
|
|
|
|
NULL, /* get_tunnel_config */
|
2014-11-11 11:53:47 -08:00
|
|
|
|
NULL, /* build header */
|
|
|
|
|
NULL, /* push header */
|
|
|
|
|
NULL, /* pop header */
|
2014-06-11 16:33:08 -07:00
|
|
|
|
NULL, /* get_numa_id */
|
2014-09-08 14:52:54 -07:00
|
|
|
|
NULL, /* set_multiq */
|
2010-11-29 12:21:08 -08:00
|
|
|
|
|
2012-09-18 11:06:08 -07:00
|
|
|
|
netdev_dummy_send, /* send */
|
2010-11-29 12:21:08 -08:00
|
|
|
|
NULL, /* send_wait */
|
|
|
|
|
|
|
|
|
|
netdev_dummy_set_etheraddr,
|
|
|
|
|
netdev_dummy_get_etheraddr,
|
|
|
|
|
netdev_dummy_get_mtu,
|
2011-09-12 17:12:52 -07:00
|
|
|
|
netdev_dummy_set_mtu,
|
2013-03-27 23:02:21 -07:00
|
|
|
|
netdev_dummy_get_ifindex,
|
2010-11-29 12:21:08 -08:00
|
|
|
|
NULL, /* get_carrier */
|
2011-10-14 12:49:57 -07:00
|
|
|
|
NULL, /* get_carrier_resets */
|
2011-01-07 16:22:34 -08:00
|
|
|
|
NULL, /* get_miimon */
|
2010-11-29 12:21:08 -08:00
|
|
|
|
netdev_dummy_get_stats,
|
|
|
|
|
|
|
|
|
|
NULL, /* get_features */
|
|
|
|
|
NULL, /* set_advertisements */
|
|
|
|
|
|
|
|
|
|
NULL, /* set_policing */
|
|
|
|
|
NULL, /* get_qos_types */
|
|
|
|
|
NULL, /* get_qos_capabilities */
|
|
|
|
|
NULL, /* get_qos */
|
|
|
|
|
NULL, /* set_qos */
|
|
|
|
|
NULL, /* get_queue */
|
|
|
|
|
NULL, /* set_queue */
|
|
|
|
|
NULL, /* delete_queue */
|
|
|
|
|
NULL, /* get_queue_stats */
|
2013-08-27 17:15:53 -07:00
|
|
|
|
NULL, /* queue_dump_start */
|
|
|
|
|
NULL, /* queue_dump_next */
|
|
|
|
|
NULL, /* queue_dump_done */
|
2010-11-29 12:21:08 -08:00
|
|
|
|
NULL, /* dump_queue_stats */
|
|
|
|
|
|
2014-11-11 11:53:47 -08:00
|
|
|
|
netdev_dummy_get_in4, /* get_in4 */
|
2010-11-29 12:21:08 -08:00
|
|
|
|
NULL, /* set_in4 */
|
|
|
|
|
NULL, /* get_in6 */
|
|
|
|
|
NULL, /* add_router */
|
|
|
|
|
NULL, /* get_next_hop */
|
2012-12-16 16:42:17 -08:00
|
|
|
|
NULL, /* get_status */
|
2010-11-29 12:21:08 -08:00
|
|
|
|
NULL, /* arp_lookup */
|
|
|
|
|
|
|
|
|
|
netdev_dummy_update_flags,
|
|
|
|
|
|
2014-03-20 19:38:14 -07:00
|
|
|
|
netdev_dummy_rxq_alloc,
|
|
|
|
|
netdev_dummy_rxq_construct,
|
|
|
|
|
netdev_dummy_rxq_destruct,
|
|
|
|
|
netdev_dummy_rxq_dealloc,
|
|
|
|
|
netdev_dummy_rxq_recv,
|
|
|
|
|
netdev_dummy_rxq_wait,
|
|
|
|
|
netdev_dummy_rxq_drain,
|
2013-05-10 14:39:19 -07:00
|
|
|
|
};
|
|
|
|
|
|
2015-05-18 10:47:45 -07:00
|
|
|
|
static void
|
|
|
|
|
pkt_list_delete(struct ovs_list *l)
|
|
|
|
|
{
|
|
|
|
|
struct pkt_list_node *pkt;
|
|
|
|
|
|
|
|
|
|
LIST_FOR_EACH_POP(pkt, list_node, l) {
|
|
|
|
|
dp_packet_delete(pkt->pkt);
|
|
|
|
|
free(pkt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-22 03:21:09 -08:00
|
|
|
|
static struct dp_packet *
|
2011-12-06 14:22:27 -08:00
|
|
|
|
eth_from_packet_or_flow(const char *s)
|
|
|
|
|
{
|
|
|
|
|
enum odp_key_fitness fitness;
|
2015-02-22 03:21:09 -08:00
|
|
|
|
struct dp_packet *packet;
|
2011-12-06 14:22:27 -08:00
|
|
|
|
struct ofpbuf odp_key;
|
|
|
|
|
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
|
|
|
|
|
* the code for that currently calls exit() on parse error. We have to
|
|
|
|
|
* settle for parsing a datapath key for now.
|
|
|
|
|
*/
|
|
|
|
|
ofpbuf_init(&odp_key, 0);
|
2013-06-19 07:15:10 +00:00
|
|
|
|
error = odp_flow_from_string(s, NULL, &odp_key, NULL);
|
2011-12-06 14:22:27 -08:00
|
|
|
|
if (error) {
|
|
|
|
|
ofpbuf_uninit(&odp_key);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert odp_key to flow. */
|
2015-03-02 17:29:44 -08:00
|
|
|
|
fitness = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
|
2011-12-06 14:22:27 -08:00
|
|
|
|
if (fitness == ODP_FIT_ERROR) {
|
|
|
|
|
ofpbuf_uninit(&odp_key);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-22 03:21:09 -08:00
|
|
|
|
packet = dp_packet_new(0);
|
2011-12-06 14:22:27 -08:00
|
|
|
|
flow_compose(packet, &flow);
|
|
|
|
|
|
|
|
|
|
ofpbuf_uninit(&odp_key);
|
|
|
|
|
return packet;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-28 11:23:29 -07:00
|
|
|
|
static void
|
2015-02-22 03:21:09 -08:00
|
|
|
|
netdev_dummy_queue_packet__(struct netdev_rxq_dummy *rx, struct dp_packet *packet)
|
2012-08-10 15:21:58 -07:00
|
|
|
|
{
|
2015-05-18 10:47:45 -07:00
|
|
|
|
struct pkt_list_node *pkt_node = xmalloc(sizeof *pkt_node);
|
|
|
|
|
|
|
|
|
|
pkt_node->pkt = packet;
|
|
|
|
|
list_push_back(&rx->recv_queue, &pkt_node->list_node);
|
2012-10-25 16:54:23 -07:00
|
|
|
|
rx->recv_queue_len++;
|
2013-12-25 22:27:25 -08:00
|
|
|
|
seq_change(rx->seq);
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
2012-08-10 15:21:58 -07:00
|
|
|
|
|
2012-10-25 16:54:23 -07:00
|
|
|
|
static void
|
2015-02-22 03:21:09 -08:00
|
|
|
|
netdev_dummy_queue_packet(struct netdev_dummy *dummy, struct dp_packet *packet)
|
2013-09-23 10:26:51 -07:00
|
|
|
|
OVS_REQUIRES(dummy->mutex)
|
2012-10-25 16:54:23 -07:00
|
|
|
|
{
|
2014-03-20 19:38:14 -07:00
|
|
|
|
struct netdev_rxq_dummy *rx, *prev;
|
2012-10-25 16:54:23 -07:00
|
|
|
|
|
2014-03-20 19:38:14 -07:00
|
|
|
|
if (dummy->rxq_pcap) {
|
|
|
|
|
ovs_pcap_write(dummy->rxq_pcap, packet);
|
|
|
|
|
fflush(dummy->rxq_pcap);
|
2013-09-23 10:26:51 -07:00
|
|
|
|
}
|
2012-10-25 16:54:23 -07:00
|
|
|
|
prev = NULL;
|
2012-08-10 15:21:58 -07:00
|
|
|
|
LIST_FOR_EACH (rx, node, &dummy->rxes) {
|
|
|
|
|
if (rx->recv_queue_len < NETDEV_DUMMY_MAX_QUEUE) {
|
2012-10-25 16:54:23 -07:00
|
|
|
|
if (prev) {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
netdev_dummy_queue_packet__(prev, dp_packet_clone(packet));
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
|
|
|
|
prev = rx;
|
2012-08-10 15:21:58 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-10-25 16:54:23 -07:00
|
|
|
|
if (prev) {
|
|
|
|
|
netdev_dummy_queue_packet__(prev, packet);
|
|
|
|
|
} else {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
dp_packet_delete(packet);
|
2012-10-25 16:54:23 -07:00
|
|
|
|
}
|
2012-08-10 15:21:58 -07:00
|
|
|
|
}
|
|
|
|
|
|
2011-12-06 14:22:27 -08:00
|
|
|
|
static void
|
|
|
|
|
netdev_dummy_receive(struct unixctl_conn *conn,
|
|
|
|
|
int argc, const char *argv[], void *aux OVS_UNUSED)
|
|
|
|
|
{
|
2013-03-15 15:54:36 -07:00
|
|
|
|
struct netdev_dummy *dummy_dev;
|
2013-07-25 16:11:52 -07:00
|
|
|
|
struct netdev *netdev;
|
2011-12-06 14:22:27 -08:00
|
|
|
|
int i;
|
|
|
|
|
|
2013-07-25 16:11:52 -07:00
|
|
|
|
netdev = netdev_from_name(argv[1]);
|
|
|
|
|
if (!netdev || !is_dummy_class(netdev->netdev_class)) {
|
2012-02-14 20:53:59 -08:00
|
|
|
|
unixctl_command_reply_error(conn, "no such dummy netdev");
|
2013-07-25 16:11:52 -07:00
|
|
|
|
goto exit;
|
2011-12-06 14:22:27 -08:00
|
|
|
|
}
|
2013-07-25 16:11:52 -07:00
|
|
|
|
dummy_dev = netdev_dummy_cast(netdev);
|
2011-12-06 14:22:27 -08:00
|
|
|
|
|
|
|
|
|
for (i = 2; i < argc; i++) {
|
2015-02-22 03:21:09 -08:00
|
|
|
|
struct dp_packet *packet;
|
2011-12-06 14:22:27 -08:00
|
|
|
|
|
|
|
|
|
packet = eth_from_packet_or_flow(argv[i]);
|
|
|
|
|
if (!packet) {
|
2012-02-14 20:53:59 -08:00
|
|
|
|
unixctl_command_reply_error(conn, "bad packet syntax");
|
2013-07-25 16:11:52 -07:00
|
|
|
|
goto exit;
|
2011-12-06 14:22:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_lock(&dummy_dev->mutex);
|
2012-10-25 16:54:23 -07:00
|
|
|
|
netdev_dummy_queue_packet(dummy_dev, packet);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&dummy_dev->mutex);
|
2011-12-06 14:22:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
2013-05-28 11:23:29 -07:00
|
|
|
|
unixctl_command_reply(conn, NULL);
|
2013-07-25 16:11:52 -07:00
|
|
|
|
|
|
|
|
|
exit:
|
|
|
|
|
netdev_close(netdev);
|
2011-12-06 14:22:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
2012-08-09 18:08:40 -07:00
|
|
|
|
static void
|
2013-03-15 15:54:36 -07:00
|
|
|
|
netdev_dummy_set_admin_state__(struct netdev_dummy *dev, bool admin_state)
|
2013-08-09 21:34:02 -07:00
|
|
|
|
OVS_REQUIRES(dev->mutex)
|
2012-08-09 18:08:40 -07:00
|
|
|
|
{
|
|
|
|
|
enum netdev_flags old_flags;
|
|
|
|
|
|
|
|
|
|
if (admin_state) {
|
2013-08-09 21:34:02 -07:00
|
|
|
|
netdev_dummy_update_flags__(dev, 0, NETDEV_UP, &old_flags);
|
2012-08-09 18:08:40 -07:00
|
|
|
|
} else {
|
2013-08-09 21:34:02 -07:00
|
|
|
|
netdev_dummy_update_flags__(dev, NETDEV_UP, 0, &old_flags);
|
2012-08-09 18:08:40 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
netdev_dummy_set_admin_state(struct unixctl_conn *conn, int argc,
|
|
|
|
|
const char *argv[], void *aux OVS_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
bool up;
|
|
|
|
|
|
|
|
|
|
if (!strcasecmp(argv[argc - 1], "up")) {
|
|
|
|
|
up = true;
|
|
|
|
|
} else if ( !strcasecmp(argv[argc - 1], "down")) {
|
|
|
|
|
up = false;
|
|
|
|
|
} else {
|
|
|
|
|
unixctl_command_reply_error(conn, "Invalid Admin State");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (argc > 2) {
|
2013-07-25 16:11:52 -07:00
|
|
|
|
struct netdev *netdev = netdev_from_name(argv[1]);
|
|
|
|
|
if (netdev && is_dummy_class(netdev->netdev_class)) {
|
|
|
|
|
struct netdev_dummy *dummy_dev = netdev_dummy_cast(netdev);
|
2012-08-09 18:08:40 -07:00
|
|
|
|
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_lock(&dummy_dev->mutex);
|
2013-03-15 15:54:36 -07:00
|
|
|
|
netdev_dummy_set_admin_state__(dummy_dev, up);
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_unlock(&dummy_dev->mutex);
|
|
|
|
|
|
2013-07-25 16:11:52 -07:00
|
|
|
|
netdev_close(netdev);
|
2012-08-09 18:08:40 -07:00
|
|
|
|
} else {
|
|
|
|
|
unixctl_command_reply_error(conn, "Unknown Dummy Interface");
|
2013-07-25 16:11:52 -07:00
|
|
|
|
netdev_close(netdev);
|
2012-08-09 18:08:40 -07:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2013-08-12 12:49:23 -07:00
|
|
|
|
struct netdev_dummy *netdev;
|
2013-08-09 21:34:02 -07:00
|
|
|
|
|
2013-08-12 12:49:23 -07:00
|
|
|
|
ovs_mutex_lock(&dummy_list_mutex);
|
|
|
|
|
LIST_FOR_EACH (netdev, list_node, &dummy_list) {
|
2013-08-09 21:34:02 -07:00
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
|
|
|
|
netdev_dummy_set_admin_state__(netdev, up);
|
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
2012-08-09 18:08:40 -07:00
|
|
|
|
}
|
2013-08-12 12:49:23 -07:00
|
|
|
|
ovs_mutex_unlock(&dummy_list_mutex);
|
2012-08-09 18:08:40 -07:00
|
|
|
|
}
|
|
|
|
|
unixctl_command_reply(conn, "OK");
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-05 16:01:17 -07:00
|
|
|
|
static void
|
|
|
|
|
display_conn_state__(struct ds *s, const char *name,
|
|
|
|
|
enum dummy_netdev_conn_state state)
|
|
|
|
|
{
|
|
|
|
|
ds_put_format(s, "%s: ", name);
|
|
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
|
case CONN_STATE_CONNECTED:
|
|
|
|
|
ds_put_cstr(s, "connected\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CONN_STATE_NOT_CONNECTED:
|
|
|
|
|
ds_put_cstr(s, "disconnected\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CONN_STATE_UNKNOWN:
|
|
|
|
|
default:
|
|
|
|
|
ds_put_cstr(s, "unknown\n");
|
|
|
|
|
break;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
netdev_dummy_conn_state(struct unixctl_conn *conn, int argc,
|
|
|
|
|
const char *argv[], void *aux OVS_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
enum dummy_netdev_conn_state state = CONN_STATE_UNKNOWN;
|
|
|
|
|
struct ds s;
|
|
|
|
|
|
|
|
|
|
ds_init(&s);
|
|
|
|
|
|
|
|
|
|
if (argc > 1) {
|
|
|
|
|
const char *dev_name = argv[1];
|
|
|
|
|
struct netdev *netdev = netdev_from_name(dev_name);
|
|
|
|
|
|
|
|
|
|
if (netdev && is_dummy_class(netdev->netdev_class)) {
|
|
|
|
|
struct netdev_dummy *dummy_dev = netdev_dummy_cast(netdev);
|
|
|
|
|
|
|
|
|
|
ovs_mutex_lock(&dummy_dev->mutex);
|
|
|
|
|
state = dummy_netdev_get_conn_state(&dummy_dev->conn);
|
|
|
|
|
ovs_mutex_unlock(&dummy_dev->mutex);
|
|
|
|
|
|
|
|
|
|
netdev_close(netdev);
|
|
|
|
|
}
|
|
|
|
|
display_conn_state__(&s, dev_name, state);
|
|
|
|
|
} else {
|
|
|
|
|
struct netdev_dummy *netdev;
|
|
|
|
|
|
|
|
|
|
ovs_mutex_lock(&dummy_list_mutex);
|
|
|
|
|
LIST_FOR_EACH (netdev, list_node, &dummy_list) {
|
|
|
|
|
ovs_mutex_lock(&netdev->mutex);
|
|
|
|
|
state = dummy_netdev_get_conn_state(&netdev->conn);
|
|
|
|
|
ovs_mutex_unlock(&netdev->mutex);
|
|
|
|
|
if (state != CONN_STATE_UNKNOWN) {
|
|
|
|
|
display_conn_state__(&s, netdev->up.name, state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ovs_mutex_unlock(&dummy_list_mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unixctl_command_reply(conn, ds_cstr(&s));
|
|
|
|
|
ds_destroy(&s);
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-11 11:53:47 -08:00
|
|
|
|
static void
|
|
|
|
|
netdev_dummy_ip4addr(struct unixctl_conn *conn, int argc OVS_UNUSED,
|
|
|
|
|
const char *argv[], void *aux OVS_UNUSED)
|
|
|
|
|
{
|
|
|
|
|
struct netdev *netdev = netdev_from_name(argv[1]);
|
|
|
|
|
|
|
|
|
|
if (netdev && is_dummy_class(netdev->netdev_class)) {
|
|
|
|
|
struct in_addr ip;
|
|
|
|
|
uint16_t plen;
|
|
|
|
|
|
|
|
|
|
if (ovs_scan(argv[2], IP_SCAN_FMT"/%"SCNi16,
|
|
|
|
|
IP_SCAN_ARGS(&ip.s_addr), &plen)) {
|
|
|
|
|
struct in_addr mask;
|
|
|
|
|
|
|
|
|
|
mask.s_addr = be32_prefix_mask(plen);
|
|
|
|
|
netdev_dummy_set_in4(netdev, ip, mask);
|
|
|
|
|
unixctl_command_reply(conn, "OK");
|
|
|
|
|
} else {
|
|
|
|
|
unixctl_command_reply(conn, "Invalid parameters");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
netdev_close(netdev);
|
|
|
|
|
} else {
|
|
|
|
|
unixctl_command_reply_error(conn, "Unknown Dummy Interface");
|
|
|
|
|
netdev_close(netdev);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-13 16:58:49 -07:00
|
|
|
|
static void
|
|
|
|
|
netdev_dummy_override(const char *type)
|
|
|
|
|
{
|
|
|
|
|
if (!netdev_unregister_provider(type)) {
|
|
|
|
|
struct netdev_class *class;
|
|
|
|
|
int error;
|
|
|
|
|
|
|
|
|
|
class = xmemdup(&dummy_class, sizeof dummy_class);
|
|
|
|
|
class->type = xstrdup(type);
|
|
|
|
|
error = netdev_register_provider(class);
|
|
|
|
|
if (error) {
|
|
|
|
|
VLOG_ERR("%s: failed to register netdev provider (%s)",
|
|
|
|
|
type, ovs_strerror(error));
|
|
|
|
|
free(CONST_CAST(char *, class->type));
|
|
|
|
|
free(class);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-29 12:21:08 -08:00
|
|
|
|
void
|
2015-06-13 16:58:49 -07:00
|
|
|
|
netdev_dummy_register(enum dummy_level level)
|
2010-11-29 12:21:08 -08:00
|
|
|
|
{
|
2014-08-22 16:27:22 -07:00
|
|
|
|
unixctl_command_register("netdev-dummy/receive", "name packet|flow...",
|
2011-12-06 14:22:27 -08:00
|
|
|
|
2, INT_MAX, netdev_dummy_receive, NULL);
|
2012-08-09 18:08:40 -07:00
|
|
|
|
unixctl_command_register("netdev-dummy/set-admin-state",
|
|
|
|
|
"[netdev] up|down", 1, 2,
|
|
|
|
|
netdev_dummy_set_admin_state, NULL);
|
2014-06-05 16:01:17 -07:00
|
|
|
|
unixctl_command_register("netdev-dummy/conn-state",
|
|
|
|
|
"[netdev]", 0, 1,
|
|
|
|
|
netdev_dummy_conn_state, NULL);
|
2014-11-11 11:53:47 -08:00
|
|
|
|
unixctl_command_register("netdev-dummy/ip4addr",
|
|
|
|
|
"[netdev] ipaddr/mask-prefix-len", 2, 2,
|
|
|
|
|
netdev_dummy_ip4addr, NULL);
|
|
|
|
|
|
2015-06-13 16:58:49 -07:00
|
|
|
|
if (level == DUMMY_OVERRIDE_ALL) {
|
2012-01-19 10:24:46 -08:00
|
|
|
|
struct sset types;
|
|
|
|
|
const char *type;
|
|
|
|
|
|
|
|
|
|
sset_init(&types);
|
|
|
|
|
netdev_enumerate_types(&types);
|
|
|
|
|
SSET_FOR_EACH (type, &types) {
|
2015-06-13 16:58:49 -07:00
|
|
|
|
if (strcmp(type, "patch")) {
|
|
|
|
|
netdev_dummy_override(type);
|
2012-01-19 10:24:46 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sset_destroy(&types);
|
2015-06-13 16:58:49 -07:00
|
|
|
|
} else if (level == DUMMY_OVERRIDE_SYSTEM) {
|
|
|
|
|
netdev_dummy_override("system");
|
2012-01-19 10:24:46 -08:00
|
|
|
|
}
|
|
|
|
|
netdev_register_provider(&dummy_class);
|
2013-01-25 13:30:40 -08:00
|
|
|
|
|
2013-05-18 08:27:20 -07:00
|
|
|
|
netdev_vport_tunnel_register();
|
2010-11-29 12:21:08 -08:00
|
|
|
|
}
|