ofp-actions: Fix use-after-free in bundle action.
[cascardo/ovs.git] / lib / netdev-dummy.c
index 76815c2..ccd4a0a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2011, 2012, 2013, 2015 Nicira, Inc.
+ * Copyright (c) 2010, 2011, 2012, 2013, 2015, 2016 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -116,6 +116,7 @@ struct netdev_dummy {
     FILE *tx_pcap, *rxq_pcap OVS_GUARDED;
 
     struct in_addr address, netmask;
+    struct in6_addr ipv6;
     struct ovs_list rxes OVS_GUARDED; /* List of child "netdev_rxq_dummy"s. */
 };
 
@@ -729,6 +730,18 @@ netdev_dummy_get_in4(const struct netdev *netdev_,
     return address->s_addr ? 0 : EADDRNOTAVAIL;
 }
 
+static int
+netdev_dummy_get_in6(const struct netdev *netdev_, struct in6_addr *in6)
+{
+    struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
+
+    ovs_mutex_lock(&netdev->mutex);
+    *in6 = netdev->ipv6;
+    ovs_mutex_unlock(&netdev->mutex);
+
+    return ipv6_addr_is_set(in6) ? 0 : EADDRNOTAVAIL;
+}
+
 static int
 netdev_dummy_set_in4(struct netdev *netdev_, struct in_addr address,
                      struct in_addr netmask)
@@ -743,6 +756,18 @@ netdev_dummy_set_in4(struct netdev *netdev_, struct in_addr address,
     return 0;
 }
 
+static int
+netdev_dummy_set_in6(struct netdev *netdev_, struct in6_addr *in6)
+{
+    struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
+
+    ovs_mutex_lock(&netdev->mutex);
+    netdev->ipv6 = *in6;
+    ovs_mutex_unlock(&netdev->mutex);
+
+    return 0;
+}
+
 static int
 netdev_dummy_set_config(struct netdev *netdev_, const struct smap *args)
 {
@@ -1032,6 +1057,92 @@ netdev_dummy_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
     return 0;
 }
 
+static int
+netdev_dummy_get_queue(const struct netdev *netdev OVS_UNUSED,
+                       unsigned int queue_id, struct smap *details OVS_UNUSED)
+{
+    if (queue_id == 0) {
+        return 0;
+    } else {
+        return EINVAL;
+    }
+}
+
+static void
+netdev_dummy_init_queue_stats(struct netdev_queue_stats *stats)
+{
+    *stats = (struct netdev_queue_stats) {
+        .tx_bytes = UINT64_MAX,
+        .tx_packets = UINT64_MAX,
+        .tx_errors = UINT64_MAX,
+        .created = LLONG_MIN,
+    };
+}
+
+static int
+netdev_dummy_get_queue_stats(const struct netdev *netdev OVS_UNUSED,
+                             unsigned int queue_id,
+                             struct netdev_queue_stats *stats)
+{
+    if (queue_id == 0) {
+        netdev_dummy_init_queue_stats(stats);
+        return 0;
+    } else {
+        return EINVAL;
+    }
+}
+
+struct netdev_dummy_queue_state {
+    unsigned int next_queue;
+};
+
+static int
+netdev_dummy_queue_dump_start(const struct netdev *netdev OVS_UNUSED,
+                              void **statep)
+{
+    struct netdev_dummy_queue_state *state = xmalloc(sizeof *state);
+    state->next_queue = 0;
+    *statep = state;
+    return 0;
+}
+
+static int
+netdev_dummy_queue_dump_next(const struct netdev *netdev OVS_UNUSED,
+                             void *state_,
+                             unsigned int *queue_id,
+                             struct smap *details OVS_UNUSED)
+{
+    struct netdev_dummy_queue_state *state = state_;
+    if (state->next_queue == 0) {
+        *queue_id = 0;
+        state->next_queue++;
+        return 0;
+    } else {
+        return EOF;
+    }
+}
+
+static int
+netdev_dummy_queue_dump_done(const struct netdev *netdev OVS_UNUSED,
+                             void *state)
+{
+    free(state);
+    return 0;
+}
+
+static int
+netdev_dummy_dump_queue_stats(const struct netdev *netdev OVS_UNUSED,
+                              void (*cb)(unsigned int queue_id,
+                                         struct netdev_queue_stats *,
+                                         void *aux),
+                              void *aux)
+{
+    struct netdev_queue_stats stats;
+    netdev_dummy_init_queue_stats(&stats);
+    cb(0, &stats, aux);
+    return 0;
+}
+
 static int
 netdev_dummy_get_ifindex(const struct netdev *netdev)
 {
@@ -1122,18 +1233,18 @@ static const struct netdev_class dummy_class = {
     NULL,                       /* get_qos_capabilities */
     NULL,                       /* get_qos */
     NULL,                       /* set_qos */
-    NULL,                       /* get_queue */
+    netdev_dummy_get_queue,
     NULL,                       /* set_queue */
     NULL,                       /* delete_queue */
-    NULL,                       /* get_queue_stats */
-    NULL,                       /* queue_dump_start */
-    NULL,                       /* queue_dump_next */
-    NULL,                       /* queue_dump_done */
-    NULL,                       /* dump_queue_stats */
+    netdev_dummy_get_queue_stats,
+    netdev_dummy_queue_dump_start,
+    netdev_dummy_queue_dump_next,
+    netdev_dummy_queue_dump_done,
+    netdev_dummy_dump_queue_stats,
 
     netdev_dummy_get_in4,       /* get_in4 */
     NULL,                       /* set_in4 */
-    NULL,                       /* get_in6 */
+    netdev_dummy_get_in6,       /* get_in6 */
     NULL,                       /* add_router */
     NULL,                       /* get_next_hop */
     NULL,                       /* get_status */
@@ -1401,29 +1512,50 @@ netdev_dummy_ip4addr(struct unixctl_conn *conn, int argc 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;
+        struct in_addr ip, mask;
+        char *error;
 
-            mask.s_addr = be32_prefix_mask(plen);
+        error = ip_parse_masked(argv[2], &ip.s_addr, &mask.s_addr);
+        if (!error) {
             netdev_dummy_set_in4(netdev, ip, mask);
             unixctl_command_reply(conn, "OK");
         } else {
-            unixctl_command_reply(conn, "Invalid parameters");
+            unixctl_command_reply_error(conn, error);
+            free(error);
         }
+    } else {
+        unixctl_command_reply_error(conn, "Unknown Dummy Interface");
+    }
+
+    netdev_close(netdev);
+}
+
+static void
+netdev_dummy_ip6addr(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)) {
+        char ip6_s[IPV6_SCAN_LEN + 1];
+        struct in6_addr ip6;
 
+        if (ovs_scan(argv[2], IPV6_SCAN_FMT, ip6_s) &&
+            inet_pton(AF_INET6, ip6_s, &ip6) == 1) {
+            netdev_dummy_set_in6(netdev, &ip6);
+            unixctl_command_reply(conn, "OK");
+        } else {
+            unixctl_command_reply_error(conn, "Invalid parameters");
+        }
         netdev_close(netdev);
     } else {
         unixctl_command_reply_error(conn, "Unknown Dummy Interface");
-        netdev_close(netdev);
-        return;
     }
 
+    netdev_close(netdev);
 }
 
+
 static void
 netdev_dummy_override(const char *type)
 {
@@ -1457,6 +1589,9 @@ netdev_dummy_register(enum dummy_level level)
     unixctl_command_register("netdev-dummy/ip4addr",
                              "[netdev] ipaddr/mask-prefix-len", 2, 2,
                              netdev_dummy_ip4addr, NULL);
+    unixctl_command_register("netdev-dummy/ip6addr",
+                             "[netdev] ip6addr", 2, 2,
+                             netdev_dummy_ip6addr, NULL);
 
     if (level == DUMMY_OVERRIDE_ALL) {
         struct sset types;