diff --git a/config/common_base b/config/common_base
index 0b4297c..92e97ef 100644
--- a/config/common_base
+++ b/config/common_base
@@ -709,6 +709,11 @@ CONFIG_RTE_LIBRTE_VHOST_DEBUG=n
 CONFIG_RTE_LIBRTE_PMD_VHOST=n
 
 #
+# Compile GRO library
+#
+CONFIG_RTE_LIBRTE_GRO=y
+
+#
 #Compile Xen domain0 support
 #
 CONFIG_RTE_LIBRTE_XEN_DOM0=n
diff --git a/lib/Makefile b/lib/Makefile
index 07e1fd0..e253053 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -106,6 +106,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
 DEPDIRS-librte_reorder := librte_eal librte_mempool librte_mbuf
 DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump
 DEPDIRS-librte_pdump := librte_eal librte_mempool librte_mbuf librte_ether
+DIRS-$(CONFIG_RTE_LIBRTE_GRO) += librte_gro
 
 ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_gro/Makefile b/lib/librte_gro/Makefile
new file mode 100644
index 0000000..fb3a36c
--- /dev/null
+++ b/lib/librte_gro/Makefile
@@ -0,0 +1,50 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_gro.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR)
+
+EXPORT_MAP := rte_gro_version.map
+
+LIBABIVER := 1
+
+#source files
+SRCS-$(CONFIG_RTE_LIBRTE_GRO) += rte_gro.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_GRO)-include += rte_gro.h
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_gro/rte_gro.c b/lib/librte_gro/rte_gro.c
new file mode 100644
index 0000000..996b382
--- /dev/null
+++ b/lib/librte_gro/rte_gro.c
@@ -0,0 +1,219 @@
+#include <rte_ethdev.h>
+#include <rte_mbuf.h>
+#include <rte_hash.h>
+#include <stdint.h>
+#include <rte_malloc.h>
+
+#include "rte_gro.h"
+#include "rte_gro_common.h"
+
+gro_reassemble_fn reassemble_functions[GRO_TYPE_MAX_NB] = {NULL};
+gro_tbl_create_fn tbl_create_functions[GRO_TYPE_MAX_NB] = {NULL};
+
+struct rte_gro_status *gro_status;
+
+/**
+ * Internal function. It creates one hashing table for all
+ * DPDK-supported GRO types, and all of them are stored in an object
+ * of struct rte_gro_tbl.
+ *
+ * @param name
+ *  Name for GRO lookup table
+ * @param nb_entries
+ *  Element number of each hashing table
+ * @param socket_id
+ *  socket id
+ * @param gro_tbl
+ *  gro_tbl points to a rte_gro_tbl object, which will be initalized
+ *  inside rte_gro_tbl_setup.
+ * @return
+ *  If create successfully, return a positive value; if not, return
+ *  a negative value.
+ */
+static int
+rte_gro_tbl_setup(char *name, uint32_t nb_entries,
+		uint16_t socket_id, struct rte_gro_tbl *gro_tbl)
+{
+	gro_tbl_create_fn create_tbl_fn;
+	const uint32_t len = strlen(name) + 10;
+	char tbl_name[len];
+	int i;
+
+	for (i = 0; i < GRO_SUPPORT_TYPE_NB; i++) {
+		sprintf(tbl_name, "%s_%u", name, i);
+		create_tbl_fn = tbl_create_functions[i];
+		if (create_tbl_fn && (create_tbl_fn(name,
+						nb_entries,
+						socket_id,
+						&(gro_tbl->
+							lkp_tbls[i].hash_tbl))
+					< 0)) {
+			return -1;
+		}
+		gro_tbl->lkp_tbls[i].gro_type = i;
+	}
+	return 1;
+}
+
+/**
+ * Internal function. It frees all the hashing tables stored in
+ * the given struct rte_gro_tbl object.
+ */
+static void
+rte_gro_tbl_destroy(struct rte_gro_tbl *gro_tbl)
+{
+	int i;
+
+	if (gro_tbl == NULL)
+		return;
+	for (i = 0; i < GRO_SUPPORT_TYPE_NB; i++) {
+		rte_hash_free(gro_tbl->lkp_tbls[i].hash_tbl);
+		gro_tbl->lkp_tbls[i].hash_tbl = NULL;
+		gro_tbl->lkp_tbls[i].gro_type = GRO_EMPTY_TYPE;
+	}
+}
+
+/**
+ * Internal function. It performs all supported GRO types on inputted
+ * packets. For example, if current DPDK GRO supports TCP/IPv4 and
+ * TCP/IPv6 GRO, this functions just reassembles TCP/IPv4 and TCP/IPv6
+ * packets. Packets of unsupported GRO types won't be processed. For
+ * ethernet devices, which want to support GRO, this function is used to
+ * registered as RX callback for all queues.
+ *
+ * @param pkts
+ *  Packets to reassemble.
+ * @param nb_pkts
+ *  The number of packets to reassemble.
+ * @param gro_tbl
+ *  pointer points to an object of struct rte_gro_tbl, which has been
+ *  initialized by rte_gro_tbl_setup.
+ * @return
+ *  Packet number after GRO. If reassemble successfully, the value is
+ *  less than nb_pkts; if not, the value is equal to nb_pkts. If the
+ *  parameters are invalid, return 0.
+ */
+static uint16_t
+rte_gro_reassemble_burst(uint8_t port __rte_unused,
+		uint16_t queue __rte_unused,
+		struct rte_mbuf **pkts,
+		uint16_t nb_pkts,
+		uint16_t max_pkts __rte_unused,
+		void *gro_tbl)
+{
+	if ((gro_tbl == NULL) || (pkts == NULL)) {
+		printf("invalid parameters for GRO.\n");
+		return 0;
+	}
+	uint16_t nb_after_gro = nb_pkts;
+
+	return nb_after_gro;
+}
+
+void
+rte_gro_init(void)
+{
+	uint8_t nb_port, i;
+	uint16_t nb_queue;
+	struct rte_eth_dev_info dev_info;
+
+	/* if init already, return immediately */
+	if (gro_status) {
+		printf("repeatly init GRO environment\n");
+		return;
+	}
+
+	gro_status = (struct rte_gro_status *)rte_zmalloc(
+			NULL,
+			sizeof(struct rte_gro_status),
+			0);
+
+	nb_port = rte_eth_dev_count();
+	gro_status->ports = (struct gro_port_status *)rte_zmalloc(
+			NULL,
+			nb_port * sizeof(struct gro_port_status),
+			0);
+	gro_status->nb_port = nb_port;
+
+	for (i = 0; i < nb_port; i++) {
+		rte_eth_dev_info_get(i, &dev_info);
+		nb_queue = dev_info.nb_rx_queues;
+		gro_status->ports[i].gro_tbls =
+			(struct rte_gro_tbl **)rte_zmalloc(
+					NULL,
+					nb_queue * sizeof(struct rte_gro_tbl *),
+					0);
+		gro_status->ports[i].gro_cbs =
+			(struct rte_eth_rxtx_callback **)
+			rte_zmalloc(
+					NULL,
+					nb_queue *
+					sizeof(struct rte_eth_rxtx_callback *),
+					0);
+	}
+}
+
+void
+rte_gro_enable(uint8_t port_id, uint16_t socket_id)
+{
+	if (gro_status->ports[port_id].gro_enable) {
+		printf("port %u has enabled GRO\n", port_id);
+		return;
+	}
+	uint16_t nb_queue, i;
+	struct rte_eth_dev_info dev_info;
+	char tbl_name[20];
+
+	rte_eth_dev_info_get(port_id, &dev_info);
+	nb_queue = dev_info.nb_rx_queues;
+
+	for (i = 0; i < nb_queue; i++) {
+		struct rte_gro_tbl *gro_tbl;
+
+		/* allocate hashing tables for this port */
+		sprintf(tbl_name, "GRO_TBL_%u", port_id);
+		gro_tbl = (struct rte_gro_tbl *)rte_malloc
+			(NULL, sizeof(struct rte_gro_tbl), 0);
+		rte_gro_tbl_setup(tbl_name,
+				GRO_DEFAULT_LOOKUP_TABLE_ENTRY_NB,
+				socket_id,
+				gro_tbl);
+		gro_status->ports[port_id].gro_tbls[i] = gro_tbl;
+		/**
+		 * register GRO reassembly function as a rx callback for each
+		 * queue of this port.
+		 */
+		gro_status->ports[port_id].gro_cbs[i] =
+			rte_eth_add_rx_callback
+			(port_id, i,
+			 rte_gro_reassemble_burst,
+			 gro_tbl);
+	}
+	gro_status->ports[port_id].gro_enable = 1;
+}
+
+void
+rte_gro_disable(uint8_t port_id)
+{
+	if (gro_status->ports[port_id].gro_enable == 0) {
+		printf("port %u has disabled GRO\n", port_id);
+		return;
+	}
+	uint16_t nb_queue, i;
+	struct rte_eth_dev_info dev_info;
+
+	rte_eth_dev_info_get(port_id, &dev_info);
+	nb_queue = dev_info.nb_rx_queues;
+
+	for (i = 0; i < nb_queue; i++) {
+		/* free all hashing tables */
+		rte_gro_tbl_destroy(gro_status->ports[port_id].gro_tbls[i]);
+		gro_status->ports[port_id].gro_tbls[i] = NULL;
+
+		/* remove GRO rx callback */
+		rte_eth_remove_rx_callback(port_id, i,
+				gro_status->ports[port_id].gro_cbs[i]);
+		gro_status->ports[port_id].gro_cbs[i] = NULL;
+	}
+	gro_status->ports[port_id].gro_enable = 0;
+}
diff --git a/lib/librte_gro/rte_gro.h b/lib/librte_gro/rte_gro.h
new file mode 100644
index 0000000..c84378e
--- /dev/null
+++ b/lib/librte_gro/rte_gro.h
@@ -0,0 +1,29 @@
+#ifndef _RTE_GRO_H_
+#define _RTE_GRO_H_
+
+/**
+ * Initialize GRO environment for all ports. It should be called after
+ * configuring all ethernet devices, and should be called just once.
+ */
+void
+rte_gro_init(void);
+
+/**
+ * Enable GRO for a given port.
+ * @param port_id
+ *  The id of the port that is to enable GRO.
+ * @param socket_id
+ *  The NUMA socket id to which the ethernet device is connected.
+ *  By default, it's value is SOCKET_ID_ANY.
+ */
+void
+rte_gro_enable(uint8_t port_id, uint16_t socket_id);
+
+/**
+ * Disable GRO for a given port.
+ * @param port_id
+ *  The idd of the port that disables GRO.
+ */
+void
+rte_gro_disable(uint8_t port_id);
+#endif
diff --git a/lib/librte_gro/rte_gro_common.h b/lib/librte_gro/rte_gro_common.h
new file mode 100644
index 0000000..611d833
--- /dev/null
+++ b/lib/librte_gro/rte_gro_common.h
@@ -0,0 +1,75 @@
+#ifndef _GRO_COMMON_H_
+#define _GRO_COMMON_H_
+
+/**
+ * the maximum number of supported GRO types
+ */
+#define GRO_TYPE_MAX_NB 256
+/**
+ * flag indicates empty GRO type
+ */
+#define GRO_EMPTY_TYPE 255
+/**
+ * current supported GRO types number
+ */
+#define GRO_SUPPORT_TYPE_NB 0
+
+/**
+ * default element number of the hashing table
+ */
+#define GRO_DEFAULT_LOOKUP_TABLE_ENTRY_NB 64
+
+/**
+ * Structure to store addresses of all hashing tables.
+ */
+struct rte_gro_lkp_tbl {
+	struct rte_hash *hash_tbl;
+	uint8_t gro_type;
+};
+struct rte_gro_tbl {
+	struct rte_gro_lkp_tbl lkp_tbls[GRO_SUPPORT_TYPE_NB];
+};
+
+/**
+ * Item-list structure.
+ */
+struct gro_item_list {
+	void *items;	/**< item array */
+	uint16_t nb_item;	/**< item number */
+};
+
+/**
+ * Each packet has an object of gro_info, which records the GRO
+ * information related to this packet.
+ */
+struct gro_info {
+	struct gro_item_list item_list;	/**< pre-allocated item-list */
+	/**< packets number that are merged with it */
+	uint16_t nb_merged_packets;
+	uint8_t gro_type;	/**< GRO type that the packet is performed */
+};
+
+/**
+ * Record GRO information for each port.
+ */
+struct gro_port_status {
+	struct rte_gro_tbl **gro_tbls;
+	struct rte_eth_rxtx_callback **gro_cbs;
+	uint8_t gro_enable;	/* flag indicates if the port enables GRO */
+};
+
+struct rte_gro_status {
+	struct gro_port_status *ports;
+	uint8_t nb_port;
+};
+
+typedef int (*gro_tbl_create_fn)(
+		char *name,
+		uint32_t nb_entries,
+		uint16_t socket_id,
+		struct rte_hash **hash_tbl);
+
+typedef int32_t (*gro_reassemble_fn)(
+		struct rte_hash *hash_tbl,
+		struct gro_item_list *item_list);
+#endif
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index b5215c0..8956821 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -98,6 +98,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EAL)            += -lrte_eal
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE)        += -lrte_cmdline
 _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER)        += -lrte_reorder
+_LDLIBS-$(CONFIG_RTE_LIBRTE_GRO)        	+= -lrte_gro
 
 ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI)            += -lrte_kni
