} u;
};
+struct pkt_list_node {
+ struct dp_packet *pkt;
+ struct ovs_list list_node;
+};
+
/* Protects 'dummy_list'. */
static struct ovs_mutex dummy_list_mutex = OVS_MUTEX_INITIALIZER;
/* Protects all members below. */
struct ovs_mutex mutex OVS_ACQ_AFTER(dummy_list_mutex);
- uint8_t hwaddr[ETH_ADDR_LEN] OVS_GUARDED;
+ struct eth_addr hwaddr OVS_GUARDED;
int mtu OVS_GUARDED;
struct netdev_stats stats OVS_GUARDED;
enum netdev_flags flags OVS_GUARDED;
static void dummy_packet_stream_close(struct dummy_packet_stream *);
+static void pkt_list_delete(struct ovs_list *);
+
static bool
is_dummy_class(const struct netdev_class *class)
{
{
if (list_size(&s->txq) < NETDEV_DUMMY_MAX_QUEUE) {
struct dp_packet *b;
+ struct pkt_list_node *node;
b = dp_packet_clone_data_with_headroom(buffer, size, 2);
put_unaligned_be16(dp_packet_push_uninit(b, 2), htons(size));
- list_push_back(&s->txq, &b->list_node);
+
+ node = xmalloc(sizeof *node);
+ node->pkt = b;
+ list_push_back(&s->txq, &node->list_node);
}
}
stream_run(s->stream);
if (!list_is_empty(&s->txq)) {
+ struct pkt_list_node *txbuf_node;
struct dp_packet *txbuf;
int retval;
- txbuf = dp_packet_from_list(list_front(&s->txq));
+ ASSIGN_CONTAINER(txbuf_node, list_front(&s->txq), list_node);
+ txbuf = txbuf_node->pkt;
retval = stream_send(s->stream, dp_packet_data(txbuf), dp_packet_size(txbuf));
if (retval > 0) {
dp_packet_pull(txbuf, retval);
if (!dp_packet_size(txbuf)) {
- list_remove(&txbuf->list_node);
+ list_remove(&txbuf_node->list_node);
+ free(txbuf_node);
dp_packet_delete(txbuf);
}
} else if (retval != -EAGAIN) {
{
stream_close(s->stream);
dp_packet_uninit(&s->rxbuf);
- dp_packet_list_delete(&s->txq);
+ pkt_list_delete(&s->txq);
}
static void
if (stream) {
int error;
struct stream *active_stream;
- struct reconnect *reconnect;;
+ struct reconnect *reconnect;
reconnect = reconnect_create(time_msec());
reconnect_set_name(reconnect, stream);
ovs_mutex_init(&netdev->mutex);
ovs_mutex_lock(&netdev->mutex);
- netdev->hwaddr[0] = 0xaa;
- netdev->hwaddr[1] = 0x55;
- netdev->hwaddr[2] = n >> 24;
- netdev->hwaddr[3] = n >> 16;
- netdev->hwaddr[4] = n >> 8;
- netdev->hwaddr[5] = n;
+ 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;
netdev->mtu = 1500;
netdev->flags = 0;
netdev->ifindex = -EOPNOTSUPP;
*address = netdev->address;
*netmask = netdev->netmask;
ovs_mutex_unlock(&netdev->mutex);
- return 0;
+
+ return address->s_addr ? 0 : EADDRNOTAVAIL;
}
static int
ovs_mutex_lock(&netdev->mutex);
list_remove(&rx->node);
- dp_packet_list_delete(&rx->recv_queue);
+ pkt_list_delete(&rx->recv_queue);
ovs_mutex_unlock(&netdev->mutex);
seq_destroy(rx->seq);
}
ovs_mutex_lock(&netdev->mutex);
if (!list_is_empty(&rx->recv_queue)) {
- packet = dp_packet_from_list(list_pop_front(&rx->recv_queue));
+ 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);
rx->recv_queue_len--;
} else {
packet = NULL;
ovs_mutex_unlock(&netdev->mutex);
dp_packet_pad(packet);
- dp_packet_set_rss_hash(packet, 0);
+ dp_packet_rss_invalidate(packet);
arr[0] = packet;
*c = 1;
struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev);
ovs_mutex_lock(&netdev->mutex);
- dp_packet_list_delete(&rx->recv_queue);
+ pkt_list_delete(&rx->recv_queue);
rx->recv_queue_len = 0;
ovs_mutex_unlock(&netdev->mutex);
dummy_packet_conn_send(&dev->conn, buffer, size);
+ /* 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);
+ }
+ }
+
if (dev->tx_pcap) {
struct dp_packet packet;
}
static int
-netdev_dummy_set_etheraddr(struct netdev *netdev,
- const uint8_t mac[ETH_ADDR_LEN])
+netdev_dummy_set_etheraddr(struct netdev *netdev, const struct eth_addr mac)
{
struct netdev_dummy *dev = netdev_dummy_cast(netdev);
ovs_mutex_lock(&dev->mutex);
if (!eth_addr_equals(dev->hwaddr, mac)) {
- memcpy(dev->hwaddr, mac, ETH_ADDR_LEN);
+ dev->hwaddr = mac;
netdev_change_seq_changed(netdev);
}
ovs_mutex_unlock(&dev->mutex);
}
static int
-netdev_dummy_get_etheraddr(const struct netdev *netdev,
- uint8_t mac[ETH_ADDR_LEN])
+netdev_dummy_get_etheraddr(const struct netdev *netdev, struct eth_addr *mac)
{
struct netdev_dummy *dev = netdev_dummy_cast(netdev);
ovs_mutex_lock(&dev->mutex);
- memcpy(mac, dev->hwaddr, ETH_ADDR_LEN);
+ *mac = dev->hwaddr;
ovs_mutex_unlock(&dev->mutex);
return 0;
netdev_dummy_rxq_drain,
};
+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);
+ }
+}
+
static struct dp_packet *
eth_from_packet_or_flow(const char *s)
{
static void
netdev_dummy_queue_packet__(struct netdev_rxq_dummy *rx, struct dp_packet *packet)
{
- list_push_back(&rx->recv_queue, &packet->list_node);
+ struct pkt_list_node *pkt_node = xmalloc(sizeof *pkt_node);
+
+ pkt_node->pkt = packet;
+ list_push_back(&rx->recv_queue, &pkt_node->list_node);
rx->recv_queue_len++;
seq_change(rx->seq);
}
}
+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);
+ }
+ }
+}
+
void
-netdev_dummy_register(bool override)
+netdev_dummy_register(enum dummy_level level)
{
unixctl_command_register("netdev-dummy/receive", "name packet|flow...",
2, INT_MAX, netdev_dummy_receive, NULL);
"[netdev] ipaddr/mask-prefix-len", 2, 2,
netdev_dummy_ip4addr, NULL);
-
- if (override) {
+ if (level == DUMMY_OVERRIDE_ALL) {
struct sset types;
const char *type;
sset_init(&types);
netdev_enumerate_types(&types);
SSET_FOR_EACH (type, &types) {
- if (!strcmp(type, "patch")) {
- continue;
- }
- 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);
- }
+ if (strcmp(type, "patch")) {
+ netdev_dummy_override(type);
}
}
sset_destroy(&types);
+ } else if (level == DUMMY_OVERRIDE_SYSTEM) {
+ netdev_dummy_override("system");
}
netdev_register_provider(&dummy_class);