[ovs-dev] [netlink 04/16] datapath: Remove implementation of port groups.

Ben Pfaff blp at nicira.com
Fri Sep 10 22:55:04 UTC 2010


The "port group" concept seems like a good one, but it has not been
used very much in userspace so far, so before we commit ourselves to
a frozen API that we must maintain forever, remove it.  We can always
add it back in later as a new kind of vport.

Signed-off-by: Ben Pfaff <blp at nicira.com>
---
 datapath/actions.c                      |   31 ------
 datapath/datapath.c                     |  153 ++++---------------------------
 datapath/datapath.h                     |   11 --
 datapath/odp-compat.h                   |    8 --
 include/openvswitch/datapath-protocol.h |   24 -----
 lib/dpif-linux.c                        |   33 +-------
 lib/dpif-netdev.c                       |  100 +--------------------
 lib/dpif-provider.h                     |   24 +-----
 lib/dpif.c                              |   72 +--------------
 lib/dpif.h                              |    8 +--
 lib/odp-util.c                          |    3 -
 ofproto/ofproto-sflow.c                 |   14 ---
 ofproto/ofproto-sflow.h                 |    4 +-
 ofproto/ofproto.c                       |   95 ++++++--------------
 ofproto/ofproto.h                       |    5 -
 utilities/ovs-dpctl.8.in                |   10 --
 utilities/ovs-dpctl.c                   |   32 +------
 17 files changed, 55 insertions(+), 572 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index 89f2d09..c0b3040 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -398,32 +398,6 @@ error:
 	kfree_skb(skb);
 }
 
-/* Never consumes 'skb'.  Returns a port that 'skb' should be sent to, -1 if
- * none.  */
-static int output_group(struct datapath *dp, __u16 group,
-			struct sk_buff *skb, gfp_t gfp)
-{
-	struct dp_port_group *g = rcu_dereference(dp->groups[group]);
-	int prev_port = -1;
-	int i;
-
-	if (!g)
-		return -1;
-	for (i = 0; i < g->n_ports; i++) {
-		struct vport *p = rcu_dereference(dp->ports[g->ports[i]]);
-		if (!p || OVS_CB(skb)->vport == p)
-			continue;
-		if (prev_port != -1) {
-			struct sk_buff *clone = skb_clone(skb, gfp);
-			if (!clone)
-				return -1;
-			do_output(dp, clone, prev_port);
-		}
-		prev_port = p->port_no;
-	}
-	return prev_port;
-}
-
 static int output_control(struct datapath *dp, struct sk_buff *skb, u32 arg,
 			  gfp_t gfp)
 {
@@ -492,11 +466,6 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
 			prev_port = a->output.port;
 			break;
 
-		case ODPAT_OUTPUT_GROUP:
-			prev_port = output_group(dp, a->output_group.group,
-						 skb, gfp);
-			break;
-
 		case ODPAT_CONTROLLER:
 			err = output_control(dp, skb, a->controller.arg, gfp);
 			if (err) {
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 30117d2..3ab302a 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -326,8 +326,6 @@ static void do_destroy_dp(struct datapath *dp)
 
 	for (i = 0; i < DP_N_QUEUES; i++)
 		skb_queue_purge(&dp->queues[i]);
-	for (i = 0; i < DP_MAX_GROUPS; i++)
-		kfree(dp->groups[i]);
 	free_percpu(dp->stats_percpu);
 	kobject_put(&dp->ifobj);
 	module_put(THIS_MODULE);
@@ -861,13 +859,23 @@ static int validate_actions(const struct sw_flow_actions *actions)
 	for (i = 0; i < actions->n_actions; i++) {
 		const union odp_action *a = &actions->actions[i];
 		switch (a->type) {
-		case ODPAT_OUTPUT:
-			if (a->output.port >= DP_MAX_PORTS)
-				return -EINVAL;
+		case ODPAT_CONTROLLER:
+		case ODPAT_STRIP_VLAN:
+		case ODPAT_SET_DL_SRC:
+		case ODPAT_SET_DL_DST:
+		case ODPAT_SET_NW_SRC:
+		case ODPAT_SET_NW_DST:
+		case ODPAT_SET_TP_SRC:
+		case ODPAT_SET_TP_DST:
+		case ODPAT_SET_TUNNEL:
+		case ODPAT_SET_PRIORITY:
+		case ODPAT_POP_PRIORITY:
+		case ODPAT_DROP_SPOOFED_ARP:
+			/* No validation needed. */
 			break;
 
-		case ODPAT_OUTPUT_GROUP:
-			if (a->output_group.group >= DP_MAX_GROUPS)
+		case ODPAT_OUTPUT:
+			if (a->output.port >= DP_MAX_PORTS)
 				return -EINVAL;
 			break;
 
@@ -888,9 +896,7 @@ static int validate_actions(const struct sw_flow_actions *actions)
 			break;
 
 		default:
-			if (a->type >= ODPAT_N_ACTIONS)
-				return -EOPNOTSUPP;
-			break;
+			return -EOPNOTSUPP;
 		}
 	}
 
@@ -1303,10 +1309,7 @@ static int do_execute(struct datapath *dp, const struct odp_execute *execute)
 	if (!skb)
 		goto error_free_actions;
 
-	if (execute->in_port < DP_MAX_PORTS)
-		OVS_CB(skb)->vport = dp->ports[execute->in_port];
-	else
-		OVS_CB(skb)->vport = NULL;
+	OVS_CB(skb)->vport = NULL;
 
 	err = -EFAULT;
 	if (copy_from_user(skb_put(skb, execute->length), execute->data,
@@ -1324,7 +1327,7 @@ static int do_execute(struct datapath *dp, const struct odp_execute *execute)
 	else
 		skb->protocol = htons(ETH_P_802_2);
 
-	err = flow_extract(skb, execute->in_port, &key);
+	err = flow_extract(skb, -1, &key);
 	if (err)
 		goto error_free_skb;
 
@@ -1365,7 +1368,6 @@ static int get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp)
 	stats.max_capacity = TBL_MAX_BUCKETS;
 	stats.n_ports = dp->n_ports;
 	stats.max_ports = DP_MAX_PORTS;
-	stats.max_groups = DP_MAX_GROUPS;
 	stats.n_frags = stats.n_hit = stats.n_missed = stats.n_lost = 0;
 	for_each_possible_cpu(i) {
 		const struct dp_stats_percpu *percpu_stats;
@@ -1522,87 +1524,6 @@ static int list_ports(struct datapath *dp, struct odp_portvec __user *upv)
 	return put_user(retval, &upv->n_ports);
 }
 
-/* RCU callback for freeing a dp_port_group */
-static void free_port_group(struct rcu_head *rcu)
-{
-	struct dp_port_group *g = container_of(rcu, struct dp_port_group, rcu);
-	kfree(g);
-}
-
-static int do_set_port_group(struct datapath *dp, u16 __user *ports,
-			     int n_ports, int group)
-{
-	struct dp_port_group *new_group, *old_group;
-	int error;
-
-	error = -EINVAL;
-	if (n_ports > DP_MAX_PORTS || group >= DP_MAX_GROUPS)
-		goto error;
-
-	error = -ENOMEM;
-	new_group = kmalloc(sizeof *new_group + sizeof(u16) * n_ports, GFP_KERNEL);
-	if (!new_group)
-		goto error;
-
-	new_group->n_ports = n_ports;
-	error = -EFAULT;
-	if (copy_from_user(new_group->ports, ports, sizeof(u16) * n_ports))
-		goto error_free;
-
-	old_group = rcu_dereference(dp->groups[group]);
-	rcu_assign_pointer(dp->groups[group], new_group);
-	if (old_group)
-		call_rcu(&old_group->rcu, free_port_group);
-	return 0;
-
-error_free:
-	kfree(new_group);
-error:
-	return error;
-}
-
-static int set_port_group(struct datapath *dp,
-			  const struct odp_port_group __user *upg)
-{
-	struct odp_port_group pg;
-
-	if (copy_from_user(&pg, upg, sizeof pg))
-		return -EFAULT;
-
-	return do_set_port_group(dp, pg.ports, pg.n_ports, pg.group);
-}
-
-static int do_get_port_group(struct datapath *dp,
-			     u16 __user *ports, int n_ports, int group,
-			     u16 __user *n_portsp)
-{
-	struct dp_port_group *g;
-	u16 n_copy;
-
-	if (group >= DP_MAX_GROUPS)
-		return -EINVAL;
-
-	g = dp->groups[group];
-	n_copy = g ? min_t(int, g->n_ports, n_ports) : 0;
-	if (n_copy && copy_to_user(ports, g->ports, n_copy * sizeof(u16)))
-		return -EFAULT;
-
-	if (put_user(g ? g->n_ports : 0, n_portsp))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int get_port_group(struct datapath *dp, struct odp_port_group __user *upg)
-{
-	struct odp_port_group pg;
-
-	if (copy_from_user(&pg, upg, sizeof pg))
-		return -EFAULT;
-
-	return do_get_port_group(dp, pg.ports, pg.n_ports, pg.group, &upg->n_ports);
-}
-
 static int get_listen_mask(const struct file *f)
 {
 	return (long)f->private_data;
@@ -1729,14 +1650,6 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
 		err = list_ports(dp, (struct odp_portvec __user *)argp);
 		break;
 
-	case ODP_PORT_GROUP_SET:
-		err = set_port_group(dp, (struct odp_port_group __user *)argp);
-		break;
-
-	case ODP_PORT_GROUP_GET:
-		err = get_port_group(dp, (struct odp_port_group __user *)argp);
-		break;
-
 	case ODP_FLOW_FLUSH:
 		err = flush_flows(dp);
 		break;
@@ -1796,27 +1709,6 @@ static int compat_list_ports(struct datapath *dp, struct compat_odp_portvec __us
 	return put_user(retval, &upv->n_ports);
 }
 
-static int compat_set_port_group(struct datapath *dp, const struct compat_odp_port_group __user *upg)
-{
-	struct compat_odp_port_group pg;
-
-	if (copy_from_user(&pg, upg, sizeof pg))
-		return -EFAULT;
-
-	return do_set_port_group(dp, compat_ptr(pg.ports), pg.n_ports, pg.group);
-}
-
-static int compat_get_port_group(struct datapath *dp, struct compat_odp_port_group __user *upg)
-{
-	struct compat_odp_port_group pg;
-
-	if (copy_from_user(&pg, upg, sizeof pg))
-		return -EFAULT;
-
-	return do_get_port_group(dp, compat_ptr(pg.ports), pg.n_ports,
-				 pg.group, &upg->n_ports);
-}
-
 static int compat_get_flow(struct odp_flow *flow, const struct compat_odp_flow __user *compat)
 {
 	compat_uptr_t actions;
@@ -1992,7 +1884,6 @@ static int compat_execute(struct datapath *dp, const struct compat_odp_execute _
 	compat_uptr_t data;
 
 	if (!access_ok(VERIFY_READ, uexecute, sizeof(struct compat_odp_execute)) ||
-	    __get_user(execute.in_port, &uexecute->in_port) ||
 	    __get_user(actions, &uexecute->actions) ||
 	    __get_user(execute.n_actions, &uexecute->n_actions) ||
 	    __get_user(data, &uexecute->data) ||
@@ -2049,14 +1940,6 @@ static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned
 		err = compat_list_ports(dp, compat_ptr(argp));
 		break;
 
-	case ODP_PORT_GROUP_SET32:
-		err = compat_set_port_group(dp, compat_ptr(argp));
-		break;
-
-	case ODP_PORT_GROUP_GET32:
-		err = compat_get_port_group(dp, compat_ptr(argp));
-		break;
-
 	case ODP_FLOW_PUT32:
 		err = compat_put_flow(dp, compat_ptr(argp));
 		break;
diff --git a/datapath/datapath.h b/datapath/datapath.h
index 3a71709..cd8be46 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -30,7 +30,6 @@ struct vport;
 #define VLAN_PCP_SHIFT 13
 
 #define DP_MAX_PORTS 1024
-#define DP_MAX_GROUPS 16
 
 #define DP_N_QUEUES 3
 #define DP_MAX_QUEUE_LEN 100
@@ -56,12 +55,6 @@ struct dp_stats_percpu {
 	seqcount_t seqlock;
 };
 
-struct dp_port_group {
-	struct rcu_head rcu;
-	int n_ports;
-	u16 ports[];
-};
-
 /**
  * struct datapath - datapath for flow-based packet switching
  * @mutex: Mutual exclusion for ioctls.
@@ -72,7 +65,6 @@ struct dp_port_group {
  * @waitqueue: Waitqueue, for waiting for new packets in @queues.
  * @n_flows: Number of flows currently in flow table.
  * @table: Current flow table (RCU protected).
- * @groups: Port groups, used by ODPAT_OUTPUT_GROUP action (RCU protected).
  * @n_ports: Number of ports currently in @ports.
  * @ports: Map from port number to &struct vport.  %ODPP_LOCAL port
  * always exists, other ports may be %NULL.
@@ -96,9 +88,6 @@ struct datapath {
 	/* Flow table. */
 	struct tbl *table;
 
-	/* Port groups. */
-	struct dp_port_group *groups[DP_MAX_GROUPS];
-
 	/* Switch ports. */
 	unsigned int n_ports;
 	struct vport *ports[DP_MAX_PORTS];
diff --git a/datapath/odp-compat.h b/datapath/odp-compat.h
index 086e8ed..d30b05f 100644
--- a/datapath/odp-compat.h
+++ b/datapath/odp-compat.h
@@ -16,8 +16,6 @@
 #include <linux/compat.h>
 
 #define ODP_PORT_LIST32		_IOWR('O', 10, struct compat_odp_portvec)
-#define ODP_PORT_GROUP_SET32	_IOR('O', 11, struct compat_odp_port_group)
-#define ODP_PORT_GROUP_GET32	_IOWR('O', 12, struct compat_odp_port_group)
 #define ODP_FLOW_GET32		_IOWR('O', 13, struct compat_odp_flow)
 #define ODP_FLOW_PUT32		_IOWR('O', 14, struct compat_odp_flow)
 #define ODP_FLOW_LIST32		_IOWR('O', 15, struct compat_odp_flowvec)
@@ -30,12 +28,6 @@ struct compat_odp_portvec {
 	u32 n_ports;
 };
 
-struct compat_odp_port_group {
-	compat_uptr_t ports;
-	u16 n_ports;		/* Number of ports. */
-	u16 group;		/* Group number. */
-};
-
 struct compat_odp_flow {
 	struct odp_flow_stats stats;
 	struct odp_flow_key key;
diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h
index 95cab47..2186562 100644
--- a/include/openvswitch/datapath-protocol.h
+++ b/include/openvswitch/datapath-protocol.h
@@ -79,9 +79,6 @@
 #define ODP_PORT_QUERY          _IOWR('O', 9, struct odp_port)
 #define ODP_PORT_LIST           _IOWR('O', 10, struct odp_portvec)
 
-#define ODP_PORT_GROUP_SET      _IOR('O', 11, struct odp_port_group)
-#define ODP_PORT_GROUP_GET      _IOWR('O', 12, struct odp_port_group)
-
 #define ODP_FLOW_GET            _IOWR('O', 13, struct odp_flow)
 #define ODP_FLOW_PUT            _IOWR('O', 14, struct odp_flow)
 #define ODP_FLOW_LIST           _IOWR('O', 15, struct odp_flowvec)
@@ -110,8 +107,6 @@ struct odp_stats {
     /* Ports. */
     uint32_t n_ports;           /* Current number of ports. */
     uint32_t max_ports;         /* Maximum supported number of ports. */
-    uint16_t max_groups;        /* Maximum number of port groups. */
-    uint16_t reserved;
 
     /* Lookups. */
     uint64_t n_frags;           /* Number of dropped IP fragments. */
@@ -199,12 +194,6 @@ struct odp_portvec {
     uint32_t n_ports;
 };
 
-struct odp_port_group {
-    uint16_t *ports;
-    uint16_t n_ports;           /* Number of ports. */
-    uint16_t group;             /* Group number. */
-};
-
 struct odp_flow_stats {
     uint64_t n_packets;         /* Number of matched packets. */
     uint64_t n_bytes;           /* Number of matched bytes. */
@@ -267,7 +256,6 @@ struct odp_flowvec {
 
 /* Action types. */
 #define ODPAT_OUTPUT            0    /* Output to switch port. */
-#define ODPAT_OUTPUT_GROUP      1    /* Output to all ports in group. */
 #define ODPAT_CONTROLLER        2    /* Send copy to controller. */
 #define ODPAT_SET_VLAN_VID      3    /* Set the 802.1q VLAN id. */
 #define ODPAT_SET_VLAN_PCP      4    /* Set the 802.1q priority. */
@@ -292,13 +280,6 @@ struct odp_action_output {
     uint16_t reserved2;
 };
 
-struct odp_action_output_group {
-    uint16_t type;              /* ODPAT_OUTPUT_GROUP. */
-    uint16_t group;             /* Group number. */
-    uint16_t reserved1;
-    uint16_t reserved2;
-};
-
 struct odp_action_controller {
     uint16_t type;              /* ODPAT_OUTPUT_CONTROLLER. */
     uint16_t reserved;
@@ -367,7 +348,6 @@ struct odp_action_priority {
 union odp_action {
     uint16_t type;
     struct odp_action_output output;
-    struct odp_action_output_group output_group;
     struct odp_action_controller controller;
     struct odp_action_tunnel tunnel;
     struct odp_action_vlan_vid vlan_vid;
@@ -380,10 +360,6 @@ union odp_action {
 };
 
 struct odp_execute {
-    uint16_t in_port;
-    uint16_t reserved1;
-    uint32_t reserved2;
-
     union odp_action *actions;
     uint32_t n_actions;
 
diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index 7f5397d..12d6b5b 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -316,34 +316,6 @@ dpif_linux_port_poll_wait(const struct dpif *dpif_)
 }
 
 static int
-dpif_linux_port_group_get(const struct dpif *dpif_, int group,
-                          uint16_t ports[], int n)
-{
-    struct odp_port_group pg;
-    int error;
-
-    assert(n <= UINT16_MAX);
-    pg.group = group;
-    pg.ports = ports;
-    pg.n_ports = n;
-    error = do_ioctl(dpif_, ODP_PORT_GROUP_GET, &pg);
-    return error ? -error : pg.n_ports;
-}
-
-static int
-dpif_linux_port_group_set(struct dpif *dpif_, int group,
-                          const uint16_t ports[], int n)
-{
-    struct odp_port_group pg;
-
-    assert(n <= UINT16_MAX);
-    pg.group = group;
-    pg.ports = (uint16_t *) ports;
-    pg.n_ports = n;
-    return do_ioctl(dpif_, ODP_PORT_GROUP_SET, &pg);
-}
-
-static int
 dpif_linux_flow_get(const struct dpif *dpif_, struct odp_flow flows[], int n)
 {
     struct odp_flowvec fv;
@@ -377,13 +349,12 @@ dpif_linux_flow_list(const struct dpif *dpif_, struct odp_flow flows[], int n)
 }
 
 static int
-dpif_linux_execute(struct dpif *dpif_, uint16_t in_port,
+dpif_linux_execute(struct dpif *dpif_,
                    const union odp_action actions[], int n_actions,
                    const struct ofpbuf *buf)
 {
     struct odp_execute execute;
     memset(&execute, 0, sizeof execute);
-    execute.in_port = in_port;
     execute.actions = (union odp_action *) actions;
     execute.n_actions = n_actions;
     execute.data = buf->data;
@@ -497,8 +468,6 @@ const struct dpif_class dpif_linux_class = {
     dpif_linux_port_list,
     dpif_linux_port_poll,
     dpif_linux_port_poll_wait,
-    dpif_linux_port_group_get,
-    dpif_linux_port_group_set,
     dpif_linux_flow_get,
     dpif_linux_flow_put,
     dpif_linux_flow_del,
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index fa50311..8371141 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -53,7 +53,6 @@ VLOG_DEFINE_THIS_MODULE(dpif_netdev)
 /* Configuration parameters. */
 enum { N_QUEUES = 2 };          /* Number of queues for dpif_recv(). */
 enum { MAX_QUEUE_LEN = 100 };   /* Maximum number of packets per queue. */
-enum { N_GROUPS = 16 };         /* Number of port groups. */
 enum { MAX_PORTS = 256 };       /* Maximum number of ports. */
 enum { MAX_FLOWS = 65536 };     /* Maximum number of flows in flow table. */
 
@@ -71,7 +70,6 @@ struct dp_netdev {
     bool drop_frags;            /* Drop all IP fragments, if true. */
     struct ovs_queue queues[N_QUEUES]; /* Messages queued for dpif_recv(). */
     struct hmap flow_table;     /* Flow table. */
-    struct odp_port_group groups[N_GROUPS];
 
     /* Statistics. */
     long long int n_frags;      /* Number of dropped IP fragments. */
@@ -230,11 +228,6 @@ create_dp_netdev(const char *name, int dp_idx, struct dpif **dpifp)
         queue_init(&dp->queues[i]);
     }
     hmap_init(&dp->flow_table);
-    for (i = 0; i < N_GROUPS; i++) {
-        dp->groups[i].ports = NULL;
-        dp->groups[i].n_ports = 0;
-        dp->groups[i].group = i;
-    }
     list_init(&dp->port_list);
     error = do_add_port(dp, name, "internal", NULL, ODPP_LOCAL);
     if (error) {
@@ -296,9 +289,6 @@ dp_netdev_free(struct dp_netdev *dp)
         queue_destroy(&dp->queues[i]);
     }
     hmap_destroy(&dp->flow_table);
-    for (i = 0; i < N_GROUPS; i++) {
-        free(dp->groups[i].ports);
-    }
     dp_netdevs[dp->dp_idx] = NULL;
     list_remove(&dp->node);
     free(dp);
@@ -333,7 +323,6 @@ dpif_netdev_get_stats(const struct dpif *dpif, struct odp_stats *stats)
     stats->max_capacity = MAX_FLOWS;
     stats->n_ports = dp->n_ports;
     stats->max_ports = MAX_PORTS;
-    stats->max_groups = N_GROUPS;
     stats->n_frags = dp->n_frags;
     stats->n_hit = dp->n_hit;
     stats->n_missed = dp->n_missed;
@@ -614,62 +603,6 @@ dpif_netdev_port_poll_wait(const struct dpif *dpif_)
     }
 }
 
-static int
-get_port_group(const struct dpif *dpif, int group_no,
-               struct odp_port_group **groupp)
-{
-    struct dp_netdev *dp = get_dp_netdev(dpif);
-
-    if (group_no >= 0 && group_no < N_GROUPS) {
-        *groupp = &dp->groups[group_no];
-        return 0;
-    } else {
-        *groupp = NULL;
-        return EINVAL;
-    }
-}
-
-static int
-dpif_netdev_port_group_get(const struct dpif *dpif, int group_no,
-                           uint16_t ports[], int n)
-{
-    struct odp_port_group *group;
-    int error;
-
-    if (n < 0) {
-        return -EINVAL;
-    }
-
-    error = get_port_group(dpif, group_no, &group);
-    if (!error) {
-        memcpy(ports, group->ports, MIN(n, group->n_ports) * sizeof *ports);
-        return group->n_ports;
-    } else {
-        return -error;
-    }
-}
-
-static int
-dpif_netdev_port_group_set(struct dpif *dpif, int group_no,
-                           const uint16_t ports[], int n)
-{
-    struct odp_port_group *group;
-    int error;
-
-    if (n < 0 || n > MAX_PORTS) {
-        return EINVAL;
-    }
-
-    error = get_port_group(dpif, group_no, &group);
-    if (!error) {
-        free(group->ports);
-        group->ports = xmemdup(ports, n * sizeof *group->ports);
-        group->n_ports = n;
-        group->group = group_no;
-    }
-    return error;
-}
-
 static struct dp_netdev_flow *
 dp_netdev_lookup_flow(const struct dp_netdev *dp, const flow_t *key)
 {
@@ -744,13 +677,6 @@ dpif_netdev_validate_actions(const union odp_action *actions, int n_actions,
             }
             break;
 
-        case ODPAT_OUTPUT_GROUP:
-            *mutates = true;
-            if (a->output_group.group >= N_GROUPS) {
-                return EINVAL;
-            }
-            break;
-
         case ODPAT_CONTROLLER:
             break;
 
@@ -911,7 +837,7 @@ dpif_netdev_flow_list(const struct dpif *dpif, struct odp_flow flows[], int n)
 }
 
 static int
-dpif_netdev_execute(struct dpif *dpif, uint16_t in_port,
+dpif_netdev_execute(struct dpif *dpif,
                     const union odp_action actions[], int n_actions,
                     const struct ofpbuf *packet)
 {
@@ -943,7 +869,7 @@ dpif_netdev_execute(struct dpif *dpif, uint16_t in_port,
          * if we don't. */
         copy = *packet;
     }
-    flow_extract(&copy, 0, in_port, &flow);
+    flow_extract(&copy, 0, -1, &flow);
     error = dp_netdev_execute_actions(dp, &copy, &flow, actions, n_actions);
     if (mutates) {
         ofpbuf_uninit(&copy);
@@ -1247,21 +1173,6 @@ dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
     }
 }
 
-static void
-dp_netdev_output_group(struct dp_netdev *dp, uint16_t group, uint16_t in_port,
-                       struct ofpbuf *packet)
-{
-    struct odp_port_group *g = &dp->groups[group];
-    int i;
-
-    for (i = 0; i < g->n_ports; i++) {
-        uint16_t out_port = g->ports[i];
-        if (out_port != in_port) {
-            dp_netdev_output_port(dp, packet, out_port);
-        }
-    }
-}
-
 static int
 dp_netdev_output_control(struct dp_netdev *dp, const struct ofpbuf *packet,
                          int queue_no, int port_no, uint32_t arg)
@@ -1331,11 +1242,6 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
             dp_netdev_output_port(dp, packet, a->output.port);
             break;
 
-        case ODPAT_OUTPUT_GROUP:
-            dp_netdev_output_group(dp, a->output_group.group, key->in_port,
-                                   packet);
-            break;
-
         case ODPAT_CONTROLLER:
             dp_netdev_output_control(dp, packet, _ODPL_ACTION_NR,
                                      key->in_port, a->controller.arg);
@@ -1406,8 +1312,6 @@ const struct dpif_class dpif_netdev_class = {
     dpif_netdev_port_list,
     dpif_netdev_port_poll,
     dpif_netdev_port_poll_wait,
-    dpif_netdev_port_group_get,
-    dpif_netdev_port_group_set,
     dpif_netdev_flow_get,
     dpif_netdev_flow_put,
     dpif_netdev_flow_del,
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 308550d..8983fe5 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -184,20 +184,6 @@ struct dpif_class {
      * value other than EAGAIN. */
     void (*port_poll_wait)(const struct dpif *dpif);
 
-    /* Stores in 'ports' the port numbers of up to 'n' ports that belong to
-     * 'group' in 'dpif'.  Returns the number of ports in 'group' (not the
-     * number stored), if successful, otherwise a negative errno value. */
-    int (*port_group_get)(const struct dpif *dpif, int group,
-                          uint16_t ports[], int n);
-
-    /* Changes port group 'group' in 'dpif' to consist of the 'n' ports whose
-     * numbers are given in 'ports'.
-     *
-     * Use the get_stats member function to obtain the number of supported port
-     * groups. */
-    int (*port_group_set)(struct dpif *dpif, int group,
-                          const uint16_t ports[], int n);
-
     /* For each flow 'flow' in the 'n' flows in 'flows':
      *
      * - If a flow matching 'flow->key' exists in 'dpif':
@@ -263,14 +249,8 @@ struct dpif_class {
     int (*flow_list)(const struct dpif *dpif, struct odp_flow flows[], int n);
 
     /* Performs the 'n_actions' actions in 'actions' on the Ethernet frame
-     * specified in 'packet'.
-     *
-     * Pretends that the frame was originally received on the port numbered
-     * 'in_port'.  This affects only ODPAT_OUTPUT_GROUP actions, which will not
-     * send a packet out their input port.  Specify the number of an unused
-     * port (e.g. UINT16_MAX is currently always unused) to avoid this
-     * behavior. */
-    int (*execute)(struct dpif *dpif, uint16_t in_port,
+     * specified in 'packet'. */
+    int (*execute)(struct dpif *dpif,
                    const union odp_action actions[], int n_actions,
                    const struct ofpbuf *packet);
 
diff --git a/lib/dpif.c b/lib/dpif.c
index e6da3a1..6c36b48 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -630,68 +630,6 @@ dpif_port_poll_wait(const struct dpif *dpif)
     dpif->dpif_class->port_poll_wait(dpif);
 }
 
-/* Retrieves a list of the port numbers in port group 'group' in 'dpif'.
- *
- * On success, returns 0 and points '*ports' to a newly allocated array of
- * integers, each of which is a 'dpif' port number for a port in
- * 'group'.  Stores the number of elements in the array in '*n_ports'.  The
- * caller is responsible for freeing '*ports' by calling free().
- *
- * On failure, returns a positive errno value and sets '*ports' to NULL and
- * '*n_ports' to 0. */
-int
-dpif_port_group_get(const struct dpif *dpif, uint16_t group,
-                    uint16_t **ports, size_t *n_ports)
-{
-    int error;
-
-    *ports = NULL;
-    *n_ports = 0;
-    for (;;) {
-        int retval = dpif->dpif_class->port_group_get(dpif, group,
-                                                      *ports, *n_ports);
-        if (retval < 0) {
-            /* Hard error. */
-            error = -retval;
-            free(*ports);
-            *ports = NULL;
-            *n_ports = 0;
-            break;
-        } else if (retval <= *n_ports) {
-            /* Success. */
-            error = 0;
-            *n_ports = retval;
-            break;
-        } else {
-            /* Soft error: there were more ports than we expected in the
-             * group.  Try again. */
-            free(*ports);
-            *ports = xcalloc(retval, sizeof **ports);
-            *n_ports = retval;
-        }
-    }
-    log_operation(dpif, "port_group_get", error);
-    return error;
-}
-
-/* Updates port group 'group' in 'dpif', making it contain the 'n_ports' ports
- * whose 'dpif' port numbers are given in 'n_ports'.  Returns 0 if
- * successful, otherwise a positive errno value.
- *
- * Behavior is undefined if the values in ports[] are not unique. */
-int
-dpif_port_group_set(struct dpif *dpif, uint16_t group,
-                    const uint16_t ports[], size_t n_ports)
-{
-    int error;
-
-    COVERAGE_INC(dpif_port_group_set);
-
-    error = dpif->dpif_class->port_group_set(dpif, group, ports, n_ports);
-    log_operation(dpif, "port_group_set", error);
-    return error;
-}
-
 /* Deletes all flows from 'dpif'.  Returns 0 if successful, otherwise a
  * positive errno value.  */
 int
@@ -923,14 +861,9 @@ dpif_flow_list_all(const struct dpif *dpif,
 /* Causes 'dpif' to perform the 'n_actions' actions in 'actions' on the
  * Ethernet frame specified in 'packet'.
  *
- * Pretends that the frame was originally received on the port numbered
- * 'in_port'.  This affects only ODPAT_OUTPUT_GROUP actions, which will not
- * send a packet out their input port.  Specify the number of an unused port
- * (e.g. UINT16_MAX is currently always unused) to avoid this behavior.
- *
  * Returns 0 if successful, otherwise a positive errno value. */
 int
-dpif_execute(struct dpif *dpif, uint16_t in_port,
+dpif_execute(struct dpif *dpif,
              const union odp_action actions[], size_t n_actions,
              const struct ofpbuf *buf)
 {
@@ -938,8 +871,7 @@ dpif_execute(struct dpif *dpif, uint16_t in_port,
 
     COVERAGE_INC(dpif_execute);
     if (n_actions > 0) {
-        error = dpif->dpif_class->execute(dpif, in_port, actions,
-                                          n_actions, buf);
+        error = dpif->dpif_class->execute(dpif, actions, n_actions, buf);
     } else {
         error = 0;
     }
diff --git a/lib/dpif.h b/lib/dpif.h
index 2ed436a..0f956c5 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -74,11 +74,6 @@ int dpif_port_list(const struct dpif *, struct odp_port **, size_t *n_ports);
 int dpif_port_poll(const struct dpif *, char **devnamep);
 void dpif_port_poll_wait(const struct dpif *);
 
-int dpif_port_group_get(const struct dpif *, uint16_t group,
-                        uint16_t **ports, size_t *n_ports);
-int dpif_port_group_set(struct dpif *, uint16_t group,
-                        const uint16_t ports[], size_t n_ports);
-
 int dpif_flow_flush(struct dpif *);
 int dpif_flow_put(struct dpif *, struct odp_flow_put *);
 int dpif_flow_del(struct dpif *, struct odp_flow *);
@@ -89,8 +84,7 @@ int dpif_flow_list(const struct dpif *, struct odp_flow[], size_t n,
 int dpif_flow_list_all(const struct dpif *,
                        struct odp_flow **flowsp, size_t *np);
 
-int dpif_execute(struct dpif *, uint16_t in_port,
-                 const union odp_action[], size_t n_actions,
+int dpif_execute(struct dpif *, const union odp_action[], size_t n_actions,
                  const struct ofpbuf *);
 
 /* Minimum number of bytes of headroom for a packet returned by dpif_recv()
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 442c939..5864714 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -46,9 +46,6 @@ format_odp_action(struct ds *ds, const union odp_action *a)
     case ODPAT_OUTPUT:
         ds_put_format(ds, "%"PRIu16, a->output.port);
         break;
-    case ODPAT_OUTPUT_GROUP:
-        ds_put_format(ds, "g%"PRIu16, a->output_group.group);
-        break;
     case ODPAT_CONTROLLER:
         ds_put_format(ds, "ctl(%"PRIu32")", a->controller.arg);
         break;
diff --git a/ofproto/ofproto-sflow.c b/ofproto/ofproto-sflow.c
index c74c736..3128d0a 100644
--- a/ofproto/ofproto-sflow.c
+++ b/ofproto/ofproto-sflow.c
@@ -547,12 +547,6 @@ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg)
             n_outputs++;
             break;
 
-        case ODPAT_OUTPUT_GROUP:
-            n_outputs += (a->output_group.group == DP_GROUP_FLOOD ? os->n_flood
-                          : a->output_group.group == DP_GROUP_ALL ? os->n_all
-                          : 0);
-            break;
-
         case ODPAT_SET_VLAN_VID:
             switchElem.flowType.sw.dst_vlan = ntohs(a->vlan_vid.vlan_vid);
             break;
@@ -584,14 +578,6 @@ ofproto_sflow_received(struct ofproto_sflow *os, struct odp_msg *msg)
 }
 
 void
-ofproto_sflow_set_group_sizes(struct ofproto_sflow *os,
-                              size_t n_flood, size_t n_all)
-{
-    os->n_flood = n_flood;
-    os->n_all = n_all;
-}
-
-void
 ofproto_sflow_run(struct ofproto_sflow *os)
 {
     if (ofproto_sflow_is_enabled(os)) {
diff --git a/ofproto/ofproto-sflow.h b/ofproto/ofproto-sflow.h
index ec86d11..df89765 100644
--- a/ofproto/ofproto-sflow.h
+++ b/ofproto/ofproto-sflow.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 InMon Corp.
+ * Copyright (c) 2009, 2010 InMon Corp.
  * Copyright (c) 2009 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,8 +35,6 @@ bool ofproto_sflow_is_enabled(const struct ofproto_sflow *);
 void ofproto_sflow_add_port(struct ofproto_sflow *, uint16_t odp_port,
                             const char *netdev_name);
 void ofproto_sflow_del_port(struct ofproto_sflow *, uint16_t odp_port);
-void ofproto_sflow_set_group_sizes(struct ofproto_sflow *,
-                                   size_t n_flood, size_t n_all);
 
 void ofproto_sflow_run(struct ofproto_sflow *);
 void ofproto_sflow_wait(struct ofproto_sflow *);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 844083d..3f490ec 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -334,8 +334,6 @@ static void handle_odp_msg(struct ofproto *, struct ofpbuf *);
 static void handle_openflow(struct ofconn *, struct ofproto *,
                             struct ofpbuf *);
 
-static void refresh_port_groups(struct ofproto *);
-
 static void update_port(struct ofproto *, const char *devname);
 static int init_ports(struct ofproto *);
 static void reinit_ports(struct ofproto *);
@@ -886,7 +884,6 @@ ofproto_set_sflow(struct ofproto *ofproto,
             unsigned int odp_port;
 
             os = ofproto->sflow = ofproto_sflow_create(ofproto->dpif);
-            refresh_port_groups(ofproto);
             PORT_ARRAY_FOR_EACH (ofport, &ofproto->ports, odp_port) {
                 ofproto_sflow_add_port(os, odp_port,
                                        netdev_get_name(ofport->netdev));
@@ -1278,8 +1275,7 @@ ofproto_send_packet(struct ofproto *p, const flow_t *flow,
 
     /* XXX Should we translate the dpif_execute() errno value into an OpenFlow
      * error code? */
-    dpif_execute(p->dpif, flow->in_port, odp_actions.actions,
-                 odp_actions.n_actions, packet);
+    dpif_execute(p->dpif, odp_actions.actions, odp_actions.n_actions, packet);
     return 0;
 }
 
@@ -1367,39 +1363,6 @@ reinit_ports(struct ofproto *p)
     svec_destroy(&devnames);
 }
 
-static size_t
-refresh_port_group(struct ofproto *p, unsigned int group)
-{
-    uint16_t *ports;
-    size_t n_ports;
-    struct ofport *port;
-    unsigned int port_no;
-
-    assert(group == DP_GROUP_ALL || group == DP_GROUP_FLOOD);
-
-    ports = xmalloc(port_array_count(&p->ports) * sizeof *ports);
-    n_ports = 0;
-    PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) {
-        if (group == DP_GROUP_ALL || !(port->opp.config & OFPPC_NO_FLOOD)) {
-            ports[n_ports++] = port_no;
-        }
-    }
-    dpif_port_group_set(p->dpif, group, ports, n_ports);
-    free(ports);
-
-    return n_ports;
-}
-
-static void
-refresh_port_groups(struct ofproto *p)
-{
-    size_t n_flood = refresh_port_group(p, DP_GROUP_FLOOD);
-    size_t n_all = refresh_port_group(p, DP_GROUP_ALL);
-    if (p->sflow) {
-        ofproto_sflow_set_group_sizes(p->sflow, n_flood, n_all);
-    }
-}
-
 static struct ofport *
 make_ofport(const struct odp_port *odp_port)
 {
@@ -1606,9 +1569,6 @@ update_port(struct ofproto *p, const char *devname)
                       : !new_ofport ? OFPPR_DELETE
                       : OFPPR_MODIFY));
     ofport_free(old_ofport);
-
-    /* Update port groups. */
-    refresh_port_groups(p);
 }
 
 static int
@@ -1634,7 +1594,6 @@ init_ports(struct ofproto *p)
         }
     }
     free(ports);
-    refresh_port_groups(p);
     return 0;
 }
 
@@ -1955,8 +1914,7 @@ execute_odp_actions(struct ofproto *ofproto, uint16_t in_port,
     } else {
         int error;
 
-        error = dpif_execute(ofproto->dpif, in_port,
-                             actions, n_actions, packet);
+        error = dpif_execute(ofproto->dpif, actions, n_actions, packet);
         ofpbuf_delete(packet);
         return !error;
     }
@@ -2427,17 +2385,6 @@ handle_set_config(struct ofproto *p, struct ofconn *ofconn,
 }
 
 static void
-add_output_group_action(struct odp_actions *actions, uint16_t group,
-                        uint16_t *nf_output_iface)
-{
-    odp_actions_add(actions, ODPAT_OUTPUT_GROUP)->output_group.group = group;
-
-    if (group == DP_GROUP_ALL || group == DP_GROUP_FLOOD) {
-        *nf_output_iface = NF_OUT_FLOOD;
-    }
-}
-
-static void
 add_controller_action(struct odp_actions *actions, uint16_t max_len)
 {
     union odp_action *a = odp_actions_add(actions, ODPAT_CONTROLLER);
@@ -2542,6 +2489,21 @@ xlate_table_action(struct action_xlate_ctx *ctx, uint16_t in_port)
 }
 
 static void
+flood_packets(struct ofproto *ofproto, uint16_t odp_in_port, uint32_t mask,
+              uint16_t *nf_output_iface, struct odp_actions *actions)
+{
+    struct ofport *ofport;
+    unsigned int odp_port;
+
+    PORT_ARRAY_FOR_EACH (ofport, &ofproto->ports, odp_port) {
+        if (odp_port != odp_in_port && !(ofport->opp.config & mask)) {
+            odp_actions_add(actions, ODPAT_OUTPUT)->output.port = odp_port;
+        }
+    }
+    *nf_output_iface = NF_OUT_FLOOD;
+}
+
+static void
 xlate_output_action__(struct action_xlate_ctx *ctx,
                       uint16_t port, uint16_t max_len)
 {
@@ -2567,11 +2529,11 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
         }
         break;
     case OFPP_FLOOD:
-        add_output_group_action(ctx->out, DP_GROUP_FLOOD,
-                                &ctx->nf_output_iface);
-        break;
+        flood_packets(ctx->ofproto, ctx->flow.in_port, OFPPC_NO_FLOOD,
+                      &ctx->nf_output_iface, ctx->out);
     case OFPP_ALL:
-        add_output_group_action(ctx->out, DP_GROUP_ALL, &ctx->nf_output_iface);
+        flood_packets(ctx->ofproto, ctx->flow.in_port, 0,
+                      &ctx->nf_output_iface, ctx->out);
         break;
     case OFPP_CONTROLLER:
         add_controller_action(ctx->out, max_len);
@@ -2897,8 +2859,7 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn,
         return error;
     }
 
-    dpif_execute(p->dpif, flow.in_port, actions.actions, actions.n_actions,
-                 &payload);
+    dpif_execute(p->dpif, actions.actions, actions.n_actions, &payload);
     ofpbuf_delete(buffer);
 
     return 0;
@@ -2916,17 +2877,14 @@ update_port_config(struct ofproto *p, struct ofport *port,
             netdev_turn_flags_on(port->netdev, NETDEV_UP, true);
         }
     }
-#define REVALIDATE_BITS (OFPPC_NO_RECV | OFPPC_NO_RECV_STP | OFPPC_NO_FWD)
+#define REVALIDATE_BITS (OFPPC_NO_RECV | OFPPC_NO_RECV_STP |    \
+                         OFPPC_NO_FWD | OFPPC_NO_FLOOD)
     if (mask & REVALIDATE_BITS) {
         COVERAGE_INC(ofproto_costly_flags);
         port->opp.config ^= mask & REVALIDATE_BITS;
         p->need_revalidate = true;
     }
 #undef REVALIDATE_BITS
-    if (mask & OFPPC_NO_FLOOD) {
-        port->opp.config ^= OFPPC_NO_FLOOD;
-        refresh_port_groups(p);
-    }
     if (mask & OFPPC_NO_PACKET_IN) {
         port->opp.config ^= OFPPC_NO_PACKET_IN;
     }
@@ -4106,7 +4064,7 @@ handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet)
         memset(&action, 0, sizeof(action));
         action.output.type = ODPAT_OUTPUT;
         action.output.port = ODPP_LOCAL;
-        dpif_execute(p->dpif, flow.in_port, &action, 1, &payload);
+        dpif_execute(p->dpif, &action, 1, &payload);
     }
 
     rule = lookup_valid_rule(p, &flow);
@@ -4624,7 +4582,8 @@ default_normal_ofhook_cb(const flow_t *flow, const struct ofpbuf *packet,
     out_port = mac_learning_lookup_tag(ofproto->ml, flow->dl_dst, 0, tags,
                                        NULL);
     if (out_port < 0) {
-        add_output_group_action(actions, DP_GROUP_FLOOD, nf_output_iface);
+        flood_packets(ofproto, flow->in_port, OFPPC_NO_FLOOD,
+                      nf_output_iface, actions);
     } else if (out_port != flow->in_port) {
         odp_actions_add(actions, ODPAT_OUTPUT)->output.port = out_port;
         *nf_output_iface = out_port;
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 2248451..4ef4a4c 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -35,11 +35,6 @@ struct ofhooks;
 struct ofproto;
 struct svec;
 
-enum {
-    DP_GROUP_FLOOD = 0,
-    DP_GROUP_ALL = 1
-};
-
 struct ofexpired {
     flow_t flow;
     uint64_t packet_count;      /* Packets from subrules. */
diff --git a/utilities/ovs-dpctl.8.in b/utilities/ovs-dpctl.8.in
index 03420b7..230eb26 100644
--- a/utilities/ovs-dpctl.8.in
+++ b/utilities/ovs-dpctl.8.in
@@ -110,16 +110,6 @@ discussed in \fBdump\-flows\fR, these entries are
 not OpenFlow flow entries.  By deleting them, the process that set them
 up may be confused about their disappearance.
 .
-.IP "\fBdump\-groups \fIdp\fR"
-Prints to the console the sets of port groups maintained by datapath
-\fIdp\fR.  Ordinarily there are at least 2 port groups in a datapath
-that \fBovs\-openflowd\fR or \fBovs\-vswitch\fR is controlling: group
-0 contains
-all ports except those disabled by STP, and group 1 contains all
-ports.  Additional or different groups might be used in the future.
-.IP
-This command is primarily useful for debugging Open vSwitch.  OpenFlow
-does not have a concept of port groups.
 .SH OPTIONS
 .TP
 \fB\-t\fR, \fB\-\-timeout=\fIsecs\fR
diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c
index 25f0b04..88f738c 100644
--- a/utilities/ovs-dpctl.c
+++ b/utilities/ovs-dpctl.c
@@ -128,8 +128,7 @@ usage(void)
            "  show                     show basic info on all datapaths\n"
            "  show DP...               show basic info on each DP\n"
            "  dump-flows DP            display flows in DP\n"
-           "  del-flows DP             delete all flows from DP\n"
-           "  dump-groups DP           display port groups in DP\n",
+           "  del-flows DP             delete all flows from DP\n",
            program_name, program_name);
     vlog_usage();
     printf("\nOther options:\n"
@@ -353,7 +352,6 @@ show_dpif(struct dpif *dpif)
                stats.n_flows, stats.cur_capacity, stats.max_capacity);
         printf("\tports: cur:%"PRIu32", max:%"PRIu32"\n",
                stats.n_ports, stats.max_ports);
-        printf("\tgroups: max:%"PRIu16"\n", stats.max_groups);
         printf("\tlookups: frags:%llu, hit:%llu, missed:%llu, lost:%llu\n",
                (unsigned long long int) stats.n_frags,
                (unsigned long long int) stats.n_hit,
@@ -494,33 +492,6 @@ do_del_flows(int argc OVS_UNUSED, char *argv[])
 }
 
 static void
-do_dump_groups(int argc OVS_UNUSED, char *argv[])
-{
-    struct odp_stats stats;
-    struct dpif *dpif;
-    unsigned int i;
-
-    run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
-    run(dpif_get_dp_stats(dpif, &stats), "get datapath stats");
-    for (i = 0; i < stats.max_groups; i++) {
-        uint16_t *ports;
-        size_t n_ports;
-
-        if (!dpif_port_group_get(dpif, i, &ports, &n_ports) && n_ports) {
-            size_t j;
-
-            printf("group %u:", i);
-            for (j = 0; j < n_ports; j++) {
-                printf(" %"PRIu16, ports[j]);
-            }
-            printf("\n");
-        }
-        free(ports);
-    }
-    dpif_close(dpif);
-}
-
-static void
 do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
     usage();
@@ -535,7 +506,6 @@ static const struct command all_commands[] = {
     { "show", 0, INT_MAX, do_show },
     { "dump-flows", 1, 1, do_dump_flows },
     { "del-flows", 1, 1, do_del_flows },
-    { "dump-groups", 1, 1, do_dump_groups },
     { "help", 0, INT_MAX, do_help },
     { NULL, 0, 0, NULL },
 };
-- 
1.7.1





More information about the dev mailing list