diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 6e2fbda..4787519 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -8434,8 +8434,9 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
    <xref linkend="cidr-inet-operators-table"> shows the operators
    available for the <type>cidr</type> and <type>inet</type> types.
    The operators <literal>&lt;&lt;</literal>,
-   <literal>&lt;&lt;=</literal>, <literal>&gt;&gt;</literal>, and
-   <literal>&gt;&gt;=</literal> test for subnet inclusion.  They
+   <literal>&lt;&lt;=</literal>, <literal>&gt;&gt;</literal>,
+   <literal>&gt;&gt;=</literal> and <literal>&amp;&amp;</literal>
+   test for subnet inclusion.  They
    consider only the network parts of the two addresses (ignoring any
    host part) and determine whether one network is identical to
    or a subnet of the other.
@@ -8503,6 +8504,11 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
         <entry><literal>inet '192.168.1/24' &gt;&gt;= inet '192.168.1/24'</literal></entry>
        </row>
        <row>
+        <entry> <literal>&amp;&amp;</literal> </entry>
+        <entry>overlaps</entry>
+        <entry><literal>inet '192.168.1/24' &amp;&amp; inet '192.168.1.80/28'</literal></entry>
+       </row>
+       <row>
         <entry> <literal>~</literal> </entry>
         <entry>bitwise NOT</entry>
         <entry><literal>~ inet '192.168.1.6'</literal></entry>
@@ -8537,6 +8543,18 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
     </table>
 
   <para>
+   GiST operator class is included for the <type>cidr</type> and
+   <type>inet</type> types, which support indexed queries using
+   <literal>&lt;</literal>, <literal>&lt;=</literal>,
+   <literal>=</literal>, <literal>&gt;=</literal>, <literal>&gt;</literal>,
+   <literal>&lt;&gt;</literal>, <literal>&lt;&lt;</literal>,
+   <literal>&lt;&lt;=</literal>, <literal>&gt;&gt;</literal>,
+   <literal>&gt;&gt;=</literal> and <literal>&amp;&amp;</literal>
+   operators. The operator class considers only the network parts
+   of the addresses while creating and using the tree.
+  </para>
+
+  <para>
    <xref linkend="cidr-inet-functions-table"> shows the functions
    available for use with the <type>cidr</type> and <type>inet</type>
    types.  The <function>abbrev</function>, <function>host</function>,
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 6b23069..722830a 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -23,7 +23,7 @@ OBJS = acl.o arrayfuncs.o array_selfuncs.o array_typanalyze.o \
 	geo_ops.o geo_selfuncs.o inet_cidr_ntop.o inet_net_pton.o int.o \
 	int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \
 	jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \
-	network.o numeric.o numutils.o oid.o oracle_compat.o \
+	network.o network_gist.o numeric.o numutils.o oid.o oracle_compat.o \
 	orderedsetaggs.o pg_lzcompress.o pg_locale.o pg_lsn.o \
 	pgstatfuncs.o pseudotypes.o quote.o rangetypes.o rangetypes_gist.o \
 	rangetypes_selfuncs.o rangetypes_spgist.o rangetypes_typanalyze.o \
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index 5e837fa..4f40fbf 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -23,41 +23,10 @@
 
 
 static int32 network_cmp_internal(inet *a1, inet *a2);
-static int	bitncmp(void *l, void *r, int n);
 static bool addressOK(unsigned char *a, int bits, int family);
 static int	ip_addrsize(inet *inetptr);
 static inet *internal_inetpl(inet *ip, int64 addend);
 
-/*
- *	Access macros.	We use VARDATA_ANY so that we can process short-header
- *	varlena values without detoasting them.  This requires a trick:
- *	VARDATA_ANY assumes the varlena header is already filled in, which is
- *	not the case when constructing a new value (until SET_INET_VARSIZE is
- *	called, which we typically can't do till the end).  Therefore, we
- *	always initialize the newly-allocated value to zeroes (using palloc0).
- *	A zero length word will look like the not-1-byte case to VARDATA_ANY,
- *	and so we correctly construct an uncompressed value.
- *
- *	Note that ip_maxbits() and SET_INET_VARSIZE() require
- *	the family field to be set correctly.
- */
-
-#define ip_family(inetptr) \
-	(((inet_struct *) VARDATA_ANY(inetptr))->family)
-
-#define ip_bits(inetptr) \
-	(((inet_struct *) VARDATA_ANY(inetptr))->bits)
-
-#define ip_addr(inetptr) \
-	(((inet_struct *) VARDATA_ANY(inetptr))->ipaddr)
-
-#define ip_maxbits(inetptr) \
-	(ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128)
-
-#define SET_INET_VARSIZE(dst) \
-	SET_VARSIZE(dst, VARHDRSZ + offsetof(inet_struct, ipaddr) + \
-				ip_addrsize(dst))
-
 
 /*
  * Return the number of bytes of address storage needed for this data type.
@@ -596,6 +565,21 @@ network_supeq(PG_FUNCTION_ARGS)
 	PG_RETURN_BOOL(false);
 }
 
+Datum
+network_overlap(PG_FUNCTION_ARGS)
+{
+	inet	   *a1 = PG_GETARG_INET_PP(0);
+	inet	   *a2 = PG_GETARG_INET_PP(1);
+
+	if (ip_family(a1) == ip_family(a2))
+	{
+		PG_RETURN_BOOL(bitncmp(ip_addr(a1), ip_addr(a2),
+					   Min(ip_bits(a1), ip_bits(a2))) == 0);
+	}
+
+	PG_RETURN_BOOL(false);
+}
+
 /*
  * Extract data from a network datatype.
  */
@@ -962,7 +946,7 @@ convert_network_to_scalar(Datum value, Oid typid)
  * author:
  *		Paul Vixie (ISC), June 1996
  */
-static int
+int
 bitncmp(void *l, void *r, int n)
 {
 	u_int		lb,
@@ -991,6 +975,44 @@ bitncmp(void *l, void *r, int n)
 	return 0;
 }
 
+/*
+ * Compare bit masks l and r for n bits
+ *
+ * Return the common bit count from the beginning. Additional bits on the
+ * right would not effect the return value as expected. The return
+ * value is always less than the input n.
+ */
+int
+bitncommon(unsigned char *l, unsigned char *r, int n)
+{
+	int			byte,
+				nbits;
+	unsigned char diff;
+
+	nbits = n % 8;
+
+	for (byte = 0; byte < n / 8; byte++)
+		if (l[byte] != r[byte])
+		{
+			/* At least one more bit in the last byte is not common */
+			nbits = 7;
+			break;
+		}
+
+	/* Set the bits to discard */
+	if (nbits != 0)
+	{
+		/* Set the diff for the first byte which is not common */
+		diff = l[byte] ^ r[byte];
+
+		/* Compare the bits from the most to the least */
+		while (diff >> (8 - nbits) != 0)
+			nbits--;
+	}
+
+	return (8 * byte) + nbits;
+}
+
 static bool
 addressOK(unsigned char *a, int bits, int family)
 {
diff --git a/src/backend/utils/adt/network_gist.c b/src/backend/utils/adt/network_gist.c
new file mode 100644
index 0000000..d41dd19
--- /dev/null
+++ b/src/backend/utils/adt/network_gist.c
@@ -0,0 +1,582 @@
+/*-------------------------------------------------------------------------
+ *
+ * network_gist.c
+ *	  GiST support for network types.
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/utils/adt/network_gist.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include <sys/socket.h>
+
+#include "access/gist.h"
+#include "access/skey.h"
+#include "utils/inet.h"
+
+/*
+ * The GiST query consistency check
+ */
+Datum
+inet_gist_consistent(PG_FUNCTION_ARGS)
+{
+	GISTENTRY	   *ent = (GISTENTRY *) PG_GETARG_POINTER(0);
+	inet		   *orig = DatumGetInetP(ent->key),
+				   *query = PG_GETARG_INET_PP(1);
+	StrategyNumber  strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+	/* Oid 			subtype = PG_GETARG_OID(3); */
+	bool	   	   *recheck = (bool *) PG_GETARG_POINTER(4);
+	int 			minbits,
+					order;
+
+	/* All operators served by this function are exact. */
+	*recheck = false;
+
+	/*
+	 * Check 0: different families
+	 *
+	 * 0 is the special number for the family field. It means sub nodes
+	 * include networks with different address families. The index should
+	 * only have this node on the top. Proper inet type has no chance
+	 * to have 0 on the family field.
+	 */
+	if (ip_family(orig) == 0)
+		PG_RETURN_BOOL(true);
+
+	/*
+	 * Check 1: different families
+	 *
+	 * Matching families do not help any of the strategies.
+	 */
+	if (ip_family(orig) != ip_family(query))
+	{
+		switch (strategy)
+		{
+			case INETSTRAT_LT:
+			case INETSTRAT_LE:
+				if (ip_family(orig) < ip_family(query))
+					PG_RETURN_BOOL(true);
+				break;
+
+			case INETSTRAT_GE:
+			case INETSTRAT_GT:
+				if (ip_family(orig) > ip_family(query))
+					PG_RETURN_BOOL(true);
+				break;
+
+			case INETSTRAT_NE:
+				PG_RETURN_BOOL(true);
+		}
+
+		PG_RETURN_BOOL(false);
+	}
+
+	/*
+	 * Check 2: network bit count
+	 *
+	 * Network bit count (ip_bits) helps to check leaves for sub network
+	 * and sup network operators.
+	 */
+	switch (strategy)
+	{
+		case INETSTRAT_SUB:
+			if (GIST_LEAF(ent) && ip_bits(orig) <= ip_bits(query))
+				PG_RETURN_BOOL(false);
+			break;
+
+		case INETSTRAT_SUBEQ:
+			if (GIST_LEAF(ent) && ip_bits(orig) < ip_bits(query))
+				PG_RETURN_BOOL(false);
+			break;
+
+		case INETSTRAT_SUPEQ:
+		case INETSTRAT_EQ:
+			if (ip_bits(orig) > ip_bits(query))
+				PG_RETURN_BOOL(false);
+			break;
+
+		case INETSTRAT_SUP:
+			if (ip_bits(orig) >= ip_bits(query))
+				PG_RETURN_BOOL(false);
+			break;
+	}
+
+	/*
+	 * Check 3: empty address
+	 *
+	 * If there are not any possible common bits, do not go futher
+	 * return true as the leaves under this node can contain any address.
+	 */
+	minbits = Min(ip_bits(orig), ip_bits(query));
+
+	if (minbits == 0)
+	{
+		switch (strategy)
+		{
+			case INETSTRAT_SUB:
+			case INETSTRAT_SUBEQ:
+			case INETSTRAT_OVERLAPS:
+			case INETSTRAT_SUPEQ:
+			case INETSTRAT_SUP:
+				PG_RETURN_BOOL(true);
+		}
+
+		if (!GIST_LEAF(ent))
+			PG_RETURN_BOOL(true);
+	}
+
+	/*
+	 * Check 4: common network bits
+	 *
+	 * Common network bits is the final check for operators which
+	 * only consider the network part of the address.
+	 */
+	if (minbits > 0)
+	{
+		order = bitncmp(ip_addr(orig), ip_addr(query), minbits);
+
+		switch (strategy)
+		{
+			case INETSTRAT_SUB:
+			case INETSTRAT_SUBEQ:
+			case INETSTRAT_OVERLAPS:
+			case INETSTRAT_SUPEQ:
+			case INETSTRAT_SUP:
+				PG_RETURN_BOOL(order == 0);
+
+			case INETSTRAT_LT:
+			case INETSTRAT_LE:
+				if (order > 0)
+					PG_RETURN_BOOL(false);
+				if (order < 0 || !GIST_LEAF(ent))
+					PG_RETURN_BOOL(true);
+				break;
+
+			case INETSTRAT_EQ:
+				if (order != 0)
+					PG_RETURN_BOOL(false);
+				if (!GIST_LEAF(ent))
+					PG_RETURN_BOOL(true);
+				break;
+
+			case INETSTRAT_GE:
+			case INETSTRAT_GT:
+				if (order < 0)
+					PG_RETURN_BOOL(false);
+				if (order > 0 || !GIST_LEAF(ent))
+					PG_RETURN_BOOL(true);
+				break;
+
+			case INETSTRAT_NE:
+				if (order != 0 || !GIST_LEAF(ent))
+					PG_RETURN_BOOL(true);
+				break;
+		}
+	}
+
+	/* Remaining checks are only for leaves and basic comparison strategies. */
+	Assert(GIST_LEAF(ent));
+
+	/*
+	 * Check 5: network bit count
+	 *
+	 * Bits are used on the basic comparison of the addresses. Whole
+	 * addresses only compared if their network bits are the same.
+	 * See backend/utils/adt/network.c:network_cmp_internal for
+	 * the original comparison.
+	 */
+	switch (strategy)
+	{
+		case INETSTRAT_LT:
+		case INETSTRAT_LE:
+			if (ip_bits(orig) < ip_bits(query))
+				PG_RETURN_BOOL(true);
+			if (ip_bits(orig) > ip_bits(query))
+				PG_RETURN_BOOL(false);
+			break;
+
+		case INETSTRAT_EQ:
+			if (ip_bits(orig) != ip_bits(query))
+				PG_RETURN_BOOL(false);
+			break;
+
+		case INETSTRAT_GE:
+		case INETSTRAT_GT:
+			if (ip_bits(orig) > ip_bits(query))
+				PG_RETURN_BOOL(true);
+			if (ip_bits(orig) < ip_bits(query))
+				PG_RETURN_BOOL(false);
+			break;
+
+		case INETSTRAT_NE:
+			if (ip_bits(orig) != ip_bits(query))
+				PG_RETURN_BOOL(true);
+			break;
+	}
+
+	order = bitncmp(ip_addr(orig), ip_addr(query), ip_maxbits(orig));
+
+	/*
+	 * Check 6: whole address
+	 *
+	 * Whole address check would not be required for most of the
+	 * strategies.
+	 */
+	switch (strategy)
+	{
+		case INETSTRAT_LT:
+			PG_RETURN_BOOL(order < 0);
+
+		case INETSTRAT_LE:
+			PG_RETURN_BOOL(order <= 0);
+
+		case INETSTRAT_EQ:
+			PG_RETURN_BOOL(order == 0);
+
+		case INETSTRAT_GE:
+			PG_RETURN_BOOL(order >= 0);
+
+		case INETSTRAT_GT:
+			PG_RETURN_BOOL(order > 0);
+
+		case INETSTRAT_NE:
+			PG_RETURN_BOOL(order != 0);
+	}
+
+	elog(ERROR, "unknown strategy for inet GiST");
+}
+
+/*
+ * The GiST union function
+ *
+ * The union of the networks is the network which contain all of them.
+ * The important part of calculating the union is to find that how many
+ * bits they have in common on the network part of their addresses.
+ * After finding the common bits, address of any of them can be used as
+ * the union by discarding the host bits.
+ */
+Datum
+inet_gist_union(PG_FUNCTION_ARGS)
+{
+	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	GISTENTRY	   *ent = entryvec->vector;
+	int				family,
+					bits;
+	unsigned char  *addr;
+	inet		   *tmp,
+				   *result;
+	OffsetNumber 	i,
+					numranges = entryvec->n;
+
+	/* Initilize variables using the first key. */
+	tmp = DatumGetInetP(ent[0].key);
+	family = ip_family(tmp);
+	bits = ip_bits(tmp);
+	addr = ip_addr(tmp);
+
+	for (i = 1; i < numranges; i++)
+	{
+		tmp = DatumGetInetP(ent[i].key);
+
+		/*
+		 * Return a network with the special number 0 on the family field
+		 * for addresses from different familes.
+		 */
+		if (ip_family(tmp) != family)
+		{
+			family = 0;
+			bits = 0;
+			break;
+		}
+
+		if (bits > ip_bits(tmp))
+			bits = ip_bits(tmp);
+
+		if (bits != 0)
+			bits = bitncommon(addr, ip_addr(tmp), bits);
+	}
+
+	/* Make sure any unused bits are zeroed. */
+	result = (inet *) palloc0(sizeof(inet));
+
+	/* Initilize the union as inet. */
+	ip_family(result) = family;
+	ip_bits(result) = bits;
+
+	/* Clone maximum bytes of the address. */
+	if (bits != 0)
+		memcpy(ip_addr(result), addr, (bits + 7) / 8);
+
+	/* Clean the partial byte. */
+	if (bits % 8 != 0)
+		ip_addr(result)[bits / 8] &= ~(0xFF >> (bits % 8));
+
+	SET_INET_VARSIZE(result);
+
+	PG_RETURN_INET_P(result);
+}
+
+/*
+ * The GiST compress function
+ */
+Datum
+inet_gist_compress(PG_FUNCTION_ARGS)
+{
+	GISTENTRY	   *ent = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(ent);
+}
+
+/*
+ * The GiST decompress function
+ */
+Datum
+inet_gist_decompress(PG_FUNCTION_ARGS)
+{
+	GISTENTRY	   *ent = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(ent);
+}
+
+/*
+ * The GiST page split penalty function
+ *
+ * Penalty is inverse of the common IP bits of the two addresses. Values
+ * bigger than 1 are used when the common bits cannot be calculated.
+ */
+Datum
+inet_gist_penalty(PG_FUNCTION_ARGS)
+{
+	GISTENTRY	   *origent = (GISTENTRY *) PG_GETARG_POINTER(0);
+	GISTENTRY	   *newent = (GISTENTRY *) PG_GETARG_POINTER(1);
+	float		   *penalty = (float *) PG_GETARG_POINTER(2);
+	inet		   *orig = DatumGetInetP(origent->key),
+				   *new = DatumGetInetP(newent->key);
+	unsigned int	minbits,
+					commonbits;
+
+	if (ip_family(orig) == ip_family(new))
+	{
+		minbits = Min(ip_bits(orig), ip_bits(new));
+
+		if (minbits > 0)
+		{
+			commonbits = bitncommon(ip_addr(orig), ip_addr(new), minbits);
+
+			if (commonbits > 0)
+				*penalty = ((float) 1) / commonbits;
+			else
+				*penalty = 2;
+		}
+		else
+			*penalty = 3;
+	}
+	else
+		*penalty = 4;
+
+	PG_RETURN_POINTER(penalty);
+}
+
+/*
+ * The GiST PickSplit method
+ *
+ * There are two ways to split. First one is to split by address families.
+ * In this case, addresses of one first appeared family will be put to the
+ * left bucket, addresses of the other family will be put to right bucket.
+ * Only the root should contain addresses from different families, so only
+ * the root should be split this way.
+ *
+ * The second and the regular way is to split by the network part of the
+ * keys. To achieve this, the union of the keys calculated with the method
+ * on the inet_gist_union function. The first and the last biggest subnets
+ * created from the calculated union. Keys contained by the first subnet put
+ * to the left bucket, keys contained by the last subnet put to the right
+ * bucket.
+ */
+Datum
+inet_gist_picksplit(PG_FUNCTION_ARGS)
+{
+	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	GISTENTRY	   *ent = entryvec->vector;
+	GIST_SPLITVEC  *splitvec = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+	int				minfamily,
+					maxfamily,
+					minbits,
+					commonbits,
+					real_index;
+	unsigned char  *addr;
+	inet		   *tmp,
+				   *left_union,
+				   *right_union;
+	OffsetNumber 	maxoff,
+					nbytes,
+					i,
+				   *left,
+				   *right;
+	GISTENTRY	  **raw_entryvec;
+
+	maxoff = entryvec->n - 1;
+	nbytes = (maxoff + 1) * sizeof(OffsetNumber);
+
+	left = (OffsetNumber *) palloc(nbytes);
+	right = (OffsetNumber *) palloc(nbytes);
+
+	splitvec->spl_left = left;
+	splitvec->spl_right = right;
+
+	splitvec->spl_nleft = 0;
+	splitvec->spl_nright = 0;
+
+	/* Initialize the raw entry vector. */
+	raw_entryvec = (GISTENTRY **) malloc(entryvec->n * sizeof(void *));
+	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+		raw_entryvec[i] = &(entryvec->vector[i]);
+
+	/* Initilize variables using the first key. */
+	tmp = DatumGetInetP(ent[FirstOffsetNumber].key);
+	minfamily = ip_family(tmp);
+	maxfamily = minfamily;
+	commonbits = ip_bits(tmp);
+	minbits = commonbits;
+	addr = ip_addr(tmp);
+
+	/* Start comparing from the second one to find the common bit count. */
+	for (i = OffsetNumberNext(FirstOffsetNumber); i <= maxoff;
+			i = OffsetNumberNext(i))
+	{
+		real_index = raw_entryvec[i] - entryvec->vector;
+
+		tmp = DatumGetInetP(entryvec->vector[real_index].key);
+		Assert(tmp != NULL);
+
+		/*
+		 * If there are networks from different address families the split
+		 * will be based on the family. So, first set the common bit count
+		 * to 0. Then, update the minfamily and the maxfamily variables.
+		 */
+		if (ip_family(tmp) != minfamily && ip_family(tmp) != maxfamily)
+		{
+			commonbits = 0;
+
+			if (ip_family(tmp) < minfamily)
+				minfamily = ip_family(tmp);
+
+			if (ip_family(tmp) > maxfamily)
+				maxfamily = ip_family(tmp);
+		}
+
+		if (minbits > ip_bits(tmp))
+			minbits = ip_bits(tmp);
+
+		if (commonbits > ip_bits(tmp))
+			commonbits = ip_bits(tmp);
+
+		if (commonbits != 0)
+			commonbits = bitncommon(addr, ip_addr(tmp), commonbits);
+	}
+
+	/* Make sure any unused bits are zeroed. */
+	left_union = (inet *) palloc0(sizeof(inet));
+	right_union = (inet *) palloc0(sizeof(inet));
+
+	ip_family(left_union) = minfamily;
+	ip_family(right_union) = maxfamily;
+
+	if (minfamily != maxfamily)
+	{
+		Assert(minfamily < maxfamily);
+
+		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+		{
+			real_index = raw_entryvec[i] - entryvec->vector;
+			tmp = DatumGetInetP(entryvec->vector[real_index].key);
+
+			if (ip_family(tmp) != maxfamily)
+			{
+				if (ip_family(tmp) != minfamily)
+					ip_family(left_union) = 0;
+
+				left[splitvec->spl_nleft++] = real_index;
+			}
+			else
+				right[splitvec->spl_nright++] = real_index;
+		}
+	}
+	else
+	{
+		Assert(minfamily > 0);
+
+		/*
+		 * If all of the bits are common; there is no chance to split
+		 * properly. It should mean that all of the elements have the same
+		 * network address.
+		 */
+		if (commonbits != minbits)
+			++commonbits;
+		else
+			ereport(DEBUG1,
+					(errmsg("inet GiST cannot pict to split"),
+					 errmsg_internal("all %d bits are the same for all items",
+							commonbits)));
+
+		ip_bits(left_union) = commonbits;
+		ip_bits(right_union) = commonbits;
+
+		/* Clone maximum bytes of the address to the left side. */
+		memcpy(ip_addr(left_union), addr, (commonbits + 6) / 8);
+		addr = ip_addr(left_union);
+
+		/* Clean the partial byte on the left side. */
+		if ((commonbits - 1) % 8 != 0)
+			addr[(commonbits - 1) / 8] &= ~(0xFF >> ((commonbits - 1) % 8));
+
+		/* Clone maximum bytes of the address to the right side. */
+		memcpy(ip_addr(right_union), addr, (commonbits + 6) / 8);
+		addr = ip_addr(right_union);
+
+		/* Set the last network bit of the address for the one on the right side. */
+		addr[(commonbits - 1) / 8] |= 1 << ((8 - (commonbits % 8)) % 8);
+
+		for (i = FirstOffsetNumber; i < entryvec->n; i = OffsetNumberNext(i))
+		{
+			real_index = raw_entryvec[i] - entryvec->vector;
+			tmp = DatumGetInetP(entryvec->vector[real_index].key);
+
+			if (bitncmp(addr, ip_addr(tmp), commonbits) != 0)
+				left[splitvec->spl_nleft++] = real_index;
+			else
+				right[splitvec->spl_nright++] = real_index;
+		}
+	}
+
+	SET_INET_VARSIZE(left_union);
+	SET_INET_VARSIZE(right_union);
+
+	splitvec->spl_ldatum = InetPGetDatum(left_union);
+	splitvec->spl_rdatum = InetPGetDatum(right_union);
+
+	PG_RETURN_POINTER(splitvec);
+}
+
+/*
+ * The GiST equality function
+ */
+Datum
+inet_gist_same(PG_FUNCTION_ARGS)
+{
+	inet		   *left = PG_GETARG_INET_P(0);
+	inet		   *right = PG_GETARG_INET_P(1);
+	bool		   *result = (bool *) PG_GETARG_POINTER(2);
+
+	*result = (ip_family(right) == ip_family(left) &&
+			   ip_bits(right) == ip_bits(left) &&
+			   memcmp(ip_addr(left), ip_addr(right), ip_maxbytes(left)) == 0);
+
+	PG_RETURN_POINTER(result);
+}
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index 2623113..b8e8750 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -818,4 +818,19 @@ DATA(insert (	3474   3831 3831 8 s	3892 4000 0 ));
 DATA(insert (	3474   3831 2283 16 s	3889 4000 0 ));
 DATA(insert (	3474   3831 3831 18 s	3882 4000 0 ));
 
+/*
+ * GiST inet_ops
+ */
+DATA(insert (	4060	869	869	3 s		4052 783 0 ));
+DATA(insert (	4060	869	869	7 s		933 783 0 ));
+DATA(insert (	4060	869	869	8 s		931 783 0 ));
+DATA(insert (	4060	869	869	9 s		934 783 0 ));
+DATA(insert (	4060	869	869	10 s	932 783 0 ));
+DATA(insert (	4060	869	869	11 s	1203 783 0 ));
+DATA(insert (	4060	869	869	12 s	1204 783 0 ));
+DATA(insert (	4060	869	869	14 s	1206 783 0 ));
+DATA(insert (	4060	869	869	15 s	1205 783 0 ));
+DATA(insert (	4060	869	869	18 s	1201 783 0 ));
+DATA(insert (	4060	869	869	19 s	1202 783 0 ));
+
 #endif   /* PG_AMOP_H */
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index b28dd56..a47ce9f 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -399,6 +399,13 @@ DATA(insert (	4037   3802 3802 2 3485 ));
 DATA(insert (	4037   3802 3802 3 3486 ));
 DATA(insert (	4037   3802 3802 4 3487 ));
 DATA(insert (	4037   3802 3802 6 3489 ));
+DATA(insert (	4060   869  869  1 4053 ));
+DATA(insert (	4060   869  869  2 4054 ));
+DATA(insert (	4060   869  869  3 4055 ));
+DATA(insert (	4060   869  869  4 4056 ));
+DATA(insert (	4060   869  869  5 4057 ));
+DATA(insert (	4060   869  869  6 4058 ));
+DATA(insert (	4060   869  869  7 4059 ));
 
 /* sp-gist */
 DATA(insert (	3474   3831 3831 1 3469 ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 63a40a8..22098de 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -112,6 +112,7 @@ DATA(insert OID = 3123 ( 403	float8_ops	PGNSP PGUID 1970  701 t 0 ));
 DATA(insert (	405		float8_ops			PGNSP PGUID 1971  701 t 0 ));
 DATA(insert (	403		inet_ops			PGNSP PGUID 1974  869 t 0 ));
 DATA(insert (	405		inet_ops			PGNSP PGUID 1975  869 t 0 ));
+DATA(insert (	783		inet_ops			PGNSP PGUID 4060  869 f 869 ));
 DATA(insert OID = 1979 ( 403	int2_ops	PGNSP PGUID 1976   21 t 0 ));
 #define INT2_BTREE_OPS_OID 1979
 DATA(insert (	405		int2_ops			PGNSP PGUID 1977   21 t 0 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index ac09034..ce179ae 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1140,18 +1140,21 @@ DATA(insert OID = 1205 (  ">"	   PGNSP PGUID b f f 869 869	 16 1203 1204 network
 DESCR("greater than");
 DATA(insert OID = 1206 (  ">="	   PGNSP PGUID b f f 869 869	 16 1204 1203 network_ge scalargtsel scalargtjoinsel ));
 DESCR("greater than or equal");
-DATA(insert OID = 931  (  "<<"	   PGNSP PGUID b f f 869 869	 16 933		0 network_sub - - ));
+DATA(insert OID = 931  (  "<<"	   PGNSP PGUID b f f 869 869	 16 933		0 network_sub contsel contjoinsel ));
 DESCR("is subnet");
 #define OID_INET_SUB_OP				  931
-DATA(insert OID = 932  (  "<<="    PGNSP PGUID b f f 869 869	 16 934		0 network_subeq - - ));
+DATA(insert OID = 932  (  "<<="    PGNSP PGUID b f f 869 869	 16 934		0 network_subeq contsel contjoinsel ));
 DESCR("is subnet or equal");
 #define OID_INET_SUBEQ_OP				932
-DATA(insert OID = 933  (  ">>"	   PGNSP PGUID b f f 869 869	 16 931		0 network_sup - - ));
+DATA(insert OID = 933  (  ">>"	   PGNSP PGUID b f f 869 869	 16 931		0 network_sup contsel contjoinsel ));
 DESCR("is supernet");
 #define OID_INET_SUP_OP				  933
-DATA(insert OID = 934  (  ">>="    PGNSP PGUID b f f 869 869	 16 932		0 network_supeq - - ));
+DATA(insert OID = 934  (  ">>="    PGNSP PGUID b f f 869 869	 16 932		0 network_supeq contsel contjoinsel ));
 DESCR("is supernet or equal");
-#define OID_INET_SUPEQ_OP				934
+#define OID_INET_SUPEQ_OP				94
+DATA(insert OID = 4052  (  "&&"    PGNSP PGUID b f f 869 869	 16 4052  	0 network_overlap areasel areajoinsel));
+DESCR("overlaps (is subnet or supernet)");
+#define OID_INET_OVERLAP_OP				4052
 
 DATA(insert OID = 2634 (  "~"	   PGNSP PGUID l f f	  0 869 869 0 0 inetnot - - ));
 DESCR("bitwise not");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index 775be86..db0c6df 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -78,6 +78,7 @@ DATA(insert OID = 1971 (	405		float_ops		PGNSP PGUID ));
 DATA(insert OID = 1974 (	403		network_ops		PGNSP PGUID ));
 #define NETWORK_BTREE_FAM_OID 1974
 DATA(insert OID = 1975 (	405		network_ops		PGNSP PGUID ));
+DATA(insert OID = 4060 (	783		network_ops		PGNSP PGUID ));
 DATA(insert OID = 1976 (	403		integer_ops		PGNSP PGUID ));
 #define INTEGER_BTREE_FAM_OID 1976
 DATA(insert OID = 1977 (	405		integer_ops		PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 334e6b8..4d7d0ef 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2118,6 +2118,23 @@ DATA(insert OID = 927 (  network_sub		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1
 DATA(insert OID = 928 (  network_subeq		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_	network_subeq _null_ _null_ _null_ ));
 DATA(insert OID = 929 (  network_sup		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_	network_sup _null_ _null_ _null_ ));
 DATA(insert OID = 930 (  network_supeq		PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_	network_supeq _null_ _null_ _null_ ));
+DATA(insert OID = 4051 (  network_overlap	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_	network_overlap	_null_ _null_ _null_ ));
+
+/* GiST support for inet and cidr */
+DATA(insert OID = 4053 (  inet_gist_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 5 0 16 "2281 869 23 26 2281" _null_ _null_ _null_ _null_ inet_gist_consistent _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 4054 (  inet_gist_union	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ inet_gist_union _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 4055 (  inet_gist_compress	PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ inet_gist_compress _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 4056 (  inet_gist_decompress PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ inet_gist_decompress _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 4057 (  inet_gist_penalty	PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ inet_gist_penalty _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 4058 (  inet_gist_picksplit	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ inet_gist_picksplit _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 4059 (  inet_gist_same	PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 2281 "869 869 2281" _null_ _null_ _null_ _null_ inet_gist_same _null_ _null_ _null_ ));
+DESCR("GiST support");
 
 /* inet/cidr functions */
 DATA(insert OID = 598 (  abbrev				PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "869" _null_ _null_ _null_ _null_	inet_abbrev _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 031a43a..beec002 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -902,6 +902,7 @@ extern Datum network_sub(PG_FUNCTION_ARGS);
 extern Datum network_subeq(PG_FUNCTION_ARGS);
 extern Datum network_sup(PG_FUNCTION_ARGS);
 extern Datum network_supeq(PG_FUNCTION_ARGS);
+extern Datum network_overlap(PG_FUNCTION_ARGS);
 extern Datum network_network(PG_FUNCTION_ARGS);
 extern Datum network_netmask(PG_FUNCTION_ARGS);
 extern Datum network_hostmask(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 330f32d..008197c 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -82,4 +82,71 @@ typedef struct macaddr
 #define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
 #define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
 
+/*
+ * Access macros
+ *
+ * We use VARDATA_ANY so that we can process short-header varlena values
+ * without detoasting them. This requires a trick: VARDATA_ANY assumes
+ * the varlena header is already filled in, which is not the case when
+ * constructing a new value (until SET_INET_VARSIZE is called, which we
+ * typically can't do till the end). Therefore, we always initialize
+ * the newly-allocated value to zeroes (using palloc0). A zero length
+ * word look like the not-1-byte case to VARDATA_ANY,  and so we correctly
+ * construct an uncompressed value.
+ *
+ * Note that ip_maxbits(), ip_maxbytes() and SET_INET_VARSIZE() require
+ * the family field to be set correctly.
+ */
+
+#define ip_family(inetptr) \
+	(((inet_struct *) VARDATA_ANY(inetptr))->family)
+
+#define ip_bits(inetptr) \
+	(((inet_struct *) VARDATA_ANY(inetptr))->bits)
+
+#define ip_addr(inetptr) \
+	(((inet_struct *) VARDATA_ANY(inetptr))->ipaddr)
+
+#define ip_maxbits(inetptr) \
+	(ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128)
+
+#define ip_maxbytes(inetptr) \
+	(ip_family(inetptr) == PGSQL_AF_INET ? 4 : 16)
+
+#define SET_INET_VARSIZE(inetptr) \
+	SET_VARSIZE(inetptr, VARHDRSZ + offsetof(inet_struct, ipaddr) + \
+						 ip_maxbytes(inetptr))
+
+/*
+ * Operator strategy numbers used in the GiST network opclass
+ */
+#define INETSTRAT_SUB			8
+#define INETSTRAT_SUBEQ			10
+#define INETSTRAT_OVERLAPS		3
+#define INETSTRAT_SUPEQ			9
+#define INETSTRAT_SUP			7
+#define INETSTRAT_LT			11
+#define INETSTRAT_LE			12
+#define INETSTRAT_EQ			18
+#define INETSTRAT_GE			14
+#define INETSTRAT_GT			15
+#define INETSTRAT_NE			19
+
+/*
+ * Static functions in network.c
+ */
+extern int		bitncmp(void *l, void *r, int n);
+extern int		bitncommon(unsigned char *l, unsigned char *r, int n);
+
+/*
+ * GiST support functions in network_gist.c
+ */
+extern Datum	inet_gist_consistent(PG_FUNCTION_ARGS);
+extern Datum	inet_gist_compress(PG_FUNCTION_ARGS);
+extern Datum	inet_gist_decompress(PG_FUNCTION_ARGS);
+extern Datum	inet_gist_union(PG_FUNCTION_ARGS);
+extern Datum	inet_gist_penalty(PG_FUNCTION_ARGS);
+extern Datum	inet_gist_picksplit(PG_FUNCTION_ARGS);
+extern Datum	inet_gist_same(PG_FUNCTION_ARGS);
+
 #endif   /* INET_H */
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index 356a397..d8a6232 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -179,28 +179,28 @@ SELECT '' AS six, c AS cidr, i AS inet FROM INET_TBL
 SELECT '' AS ten, i, c,
   i < c AS lt, i <= c AS le, i = c AS eq,
   i >= c AS ge, i > c AS gt, i <> c AS ne,
-  i << c AS sb, i <<= c AS sbe,
-  i >> c AS sup, i >>= c AS spe
+  i << c AS sb, i <<= c AS sbe, i >> c AS sup,
+  i >>= c AS spe, i && c AS ovr
   FROM INET_TBL;
- ten |        i         |         c          | lt | le | eq | ge | gt | ne | sb | sbe | sup | spe 
------+------------------+--------------------+----+----+----+----+----+----+----+-----+-----+-----
-     | 192.168.1.226/24 | 192.168.1.0/24     | f  | f  | f  | t  | t  | t  | f  | t   | f   | t
-     | 192.168.1.226    | 192.168.1.0/26     | f  | f  | f  | t  | t  | t  | f  | f   | f   | f
-     | 192.168.1.0/24   | 192.168.1.0/24     | f  | t  | t  | t  | f  | f  | f  | t   | f   | t
-     | 192.168.1.0/25   | 192.168.1.0/24     | f  | f  | f  | t  | t  | t  | t  | t   | f   | f
-     | 192.168.1.255/24 | 192.168.1.0/24     | f  | f  | f  | t  | t  | t  | f  | t   | f   | t
-     | 192.168.1.255/25 | 192.168.1.0/24     | f  | f  | f  | t  | t  | t  | t  | t   | f   | f
-     | 10.1.2.3/8       | 10.0.0.0/8         | f  | f  | f  | t  | t  | t  | f  | t   | f   | t
-     | 10.1.2.3/8       | 10.0.0.0/32        | t  | t  | f  | f  | f  | t  | f  | f   | t   | t
-     | 10.1.2.3         | 10.1.2.3/32        | f  | t  | t  | t  | f  | f  | f  | t   | f   | t
-     | 10.1.2.3/24      | 10.1.2.0/24        | f  | f  | f  | t  | t  | t  | f  | t   | f   | t
-     | 10.1.2.3/16      | 10.1.0.0/16        | f  | f  | f  | t  | t  | t  | f  | t   | f   | t
-     | 10.1.2.3/8       | 10.0.0.0/8         | f  | f  | f  | t  | t  | t  | f  | t   | f   | t
-     | 11.1.2.3/8       | 10.0.0.0/8         | f  | f  | f  | t  | t  | t  | f  | f   | f   | f
-     | 9.1.2.3/8        | 10.0.0.0/8         | t  | t  | f  | f  | f  | t  | f  | f   | f   | f
-     | 10:23::f1/64     | 10:23::f1/128      | t  | t  | f  | f  | f  | t  | f  | f   | t   | t
-     | 10:23::ffff      | 10:23::8000/113    | f  | f  | f  | t  | t  | t  | t  | t   | f   | f
-     | ::4.3.2.1/24     | ::ffff:1.2.3.4/128 | t  | t  | f  | f  | f  | t  | f  | f   | t   | t
+ ten |        i         |         c          | lt | le | eq | ge | gt | ne | sb | sbe | sup | spe | ovr 
+-----+------------------+--------------------+----+----+----+----+----+----+----+-----+-----+-----+-----
+     | 192.168.1.226/24 | 192.168.1.0/24     | f  | f  | f  | t  | t  | t  | f  | t   | f   | t   | t
+     | 192.168.1.226    | 192.168.1.0/26     | f  | f  | f  | t  | t  | t  | f  | f   | f   | f   | f
+     | 192.168.1.0/24   | 192.168.1.0/24     | f  | t  | t  | t  | f  | f  | f  | t   | f   | t   | t
+     | 192.168.1.0/25   | 192.168.1.0/24     | f  | f  | f  | t  | t  | t  | t  | t   | f   | f   | t
+     | 192.168.1.255/24 | 192.168.1.0/24     | f  | f  | f  | t  | t  | t  | f  | t   | f   | t   | t
+     | 192.168.1.255/25 | 192.168.1.0/24     | f  | f  | f  | t  | t  | t  | t  | t   | f   | f   | t
+     | 10.1.2.3/8       | 10.0.0.0/8         | f  | f  | f  | t  | t  | t  | f  | t   | f   | t   | t
+     | 10.1.2.3/8       | 10.0.0.0/32        | t  | t  | f  | f  | f  | t  | f  | f   | t   | t   | t
+     | 10.1.2.3         | 10.1.2.3/32        | f  | t  | t  | t  | f  | f  | f  | t   | f   | t   | t
+     | 10.1.2.3/24      | 10.1.2.0/24        | f  | f  | f  | t  | t  | t  | f  | t   | f   | t   | t
+     | 10.1.2.3/16      | 10.1.0.0/16        | f  | f  | f  | t  | t  | t  | f  | t   | f   | t   | t
+     | 10.1.2.3/8       | 10.0.0.0/8         | f  | f  | f  | t  | t  | t  | f  | t   | f   | t   | t
+     | 11.1.2.3/8       | 10.0.0.0/8         | f  | f  | f  | t  | t  | t  | f  | f   | f   | f   | f
+     | 9.1.2.3/8        | 10.0.0.0/8         | t  | t  | f  | f  | f  | t  | f  | f   | f   | f   | f
+     | 10:23::f1/64     | 10:23::f1/128      | t  | t  | f  | f  | f  | t  | f  | f   | t   | t   | t
+     | 10:23::ffff      | 10:23::8000/113    | f  | f  | f  | t  | t  | t  | t  | t   | f   | f   | t
+     | ::4.3.2.1/24     | ::ffff:1.2.3.4/128 | t  | t  | f  | f  | f  | t  | f  | f   | t   | t   | t
 (17 rows)
 
 -- check the conversion to/from text and set_netmask
@@ -226,7 +226,7 @@ SELECT '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL;
      | ::4.3.2.1/24
 (17 rows)
 
--- check that index works correctly
+-- check that btree index works correctly
 CREATE INDEX inet_idx1 ON inet_tbl(i);
 SET enable_seqscan TO off;
 SELECT * FROM inet_tbl WHERE i<<'192.168.1.0/24'::cidr;
@@ -250,6 +250,135 @@ SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr;
 
 SET enable_seqscan TO on;
 DROP INDEX inet_idx1;
+-- check that gist index works correctly
+CREATE INDEX inet_idx2 ON inet_tbl using gist (i inet_ops);
+SET enable_seqscan TO off;
+SELECT * FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i;
+       c        |        i         
+----------------+------------------
+ 192.168.1.0/24 | 192.168.1.0/25
+ 192.168.1.0/24 | 192.168.1.255/25
+ 192.168.1.0/26 | 192.168.1.226
+(3 rows)
+
+SELECT * FROM inet_tbl WHERE i <<= '192.168.1.0/24'::cidr ORDER BY i;
+       c        |        i         
+----------------+------------------
+ 192.168.1.0/24 | 192.168.1.0/24
+ 192.168.1.0/24 | 192.168.1.226/24
+ 192.168.1.0/24 | 192.168.1.255/24
+ 192.168.1.0/24 | 192.168.1.0/25
+ 192.168.1.0/24 | 192.168.1.255/25
+ 192.168.1.0/26 | 192.168.1.226
+(6 rows)
+
+SELECT * FROM inet_tbl WHERE i && '192.168.1.0/24'::cidr ORDER BY i;
+       c        |        i         
+----------------+------------------
+ 192.168.1.0/24 | 192.168.1.0/24
+ 192.168.1.0/24 | 192.168.1.226/24
+ 192.168.1.0/24 | 192.168.1.255/24
+ 192.168.1.0/24 | 192.168.1.0/25
+ 192.168.1.0/24 | 192.168.1.255/25
+ 192.168.1.0/26 | 192.168.1.226
+(6 rows)
+
+SELECT * FROM inet_tbl WHERE i >>= '192.168.1.0/24'::cidr ORDER BY i;
+       c        |        i         
+----------------+------------------
+ 192.168.1.0/24 | 192.168.1.0/24
+ 192.168.1.0/24 | 192.168.1.226/24
+ 192.168.1.0/24 | 192.168.1.255/24
+(3 rows)
+
+SELECT * FROM inet_tbl WHERE i >> '192.168.1.0/24'::cidr ORDER BY i;
+ c | i 
+---+---
+(0 rows)
+
+SELECT * FROM inet_tbl WHERE i < '192.168.1.0/24'::cidr ORDER BY i;
+      c      |      i      
+-------------+-------------
+ 10.0.0.0/8  | 9.1.2.3/8
+ 10.0.0.0/32 | 10.1.2.3/8
+ 10.0.0.0/8  | 10.1.2.3/8
+ 10.0.0.0/8  | 10.1.2.3/8
+ 10.1.0.0/16 | 10.1.2.3/16
+ 10.1.2.0/24 | 10.1.2.3/24
+ 10.1.2.3/32 | 10.1.2.3
+ 10.0.0.0/8  | 11.1.2.3/8
+(8 rows)
+
+SELECT * FROM inet_tbl WHERE i <= '192.168.1.0/24'::cidr ORDER BY i;
+       c        |       i        
+----------------+----------------
+ 10.0.0.0/8     | 9.1.2.3/8
+ 10.0.0.0/8     | 10.1.2.3/8
+ 10.0.0.0/32    | 10.1.2.3/8
+ 10.0.0.0/8     | 10.1.2.3/8
+ 10.1.0.0/16    | 10.1.2.3/16
+ 10.1.2.0/24    | 10.1.2.3/24
+ 10.1.2.3/32    | 10.1.2.3
+ 10.0.0.0/8     | 11.1.2.3/8
+ 192.168.1.0/24 | 192.168.1.0/24
+(9 rows)
+
+SELECT * FROM inet_tbl WHERE i = '192.168.1.0/24'::cidr ORDER BY i;
+       c        |       i        
+----------------+----------------
+ 192.168.1.0/24 | 192.168.1.0/24
+(1 row)
+
+SELECT * FROM inet_tbl WHERE i >= '192.168.1.0/24'::cidr ORDER BY i;
+         c          |        i         
+--------------------+------------------
+ 192.168.1.0/24     | 192.168.1.0/24
+ 192.168.1.0/24     | 192.168.1.226/24
+ 192.168.1.0/24     | 192.168.1.255/24
+ 192.168.1.0/24     | 192.168.1.0/25
+ 192.168.1.0/24     | 192.168.1.255/25
+ 192.168.1.0/26     | 192.168.1.226
+ ::ffff:1.2.3.4/128 | ::4.3.2.1/24
+ 10:23::f1/128      | 10:23::f1/64
+ 10:23::8000/113    | 10:23::ffff
+(9 rows)
+
+SELECT * FROM inet_tbl WHERE i > '192.168.1.0/24'::cidr ORDER BY i;
+         c          |        i         
+--------------------+------------------
+ 192.168.1.0/24     | 192.168.1.226/24
+ 192.168.1.0/24     | 192.168.1.255/24
+ 192.168.1.0/24     | 192.168.1.0/25
+ 192.168.1.0/24     | 192.168.1.255/25
+ 192.168.1.0/26     | 192.168.1.226
+ ::ffff:1.2.3.4/128 | ::4.3.2.1/24
+ 10:23::f1/128      | 10:23::f1/64
+ 10:23::8000/113    | 10:23::ffff
+(8 rows)
+
+SELECT * FROM inet_tbl WHERE i <> '192.168.1.0/24'::cidr ORDER BY i;
+         c          |        i         
+--------------------+------------------
+ 10.0.0.0/8         | 9.1.2.3/8
+ 10.0.0.0/8         | 10.1.2.3/8
+ 10.0.0.0/32        | 10.1.2.3/8
+ 10.0.0.0/8         | 10.1.2.3/8
+ 10.1.0.0/16        | 10.1.2.3/16
+ 10.1.2.0/24        | 10.1.2.3/24
+ 10.1.2.3/32        | 10.1.2.3
+ 10.0.0.0/8         | 11.1.2.3/8
+ 192.168.1.0/24     | 192.168.1.226/24
+ 192.168.1.0/24     | 192.168.1.255/24
+ 192.168.1.0/24     | 192.168.1.0/25
+ 192.168.1.0/24     | 192.168.1.255/25
+ 192.168.1.0/26     | 192.168.1.226
+ ::ffff:1.2.3.4/128 | ::4.3.2.1/24
+ 10:23::f1/128      | 10:23::f1/64
+ 10:23::8000/113    | 10:23::ffff
+(16 rows)
+
+SET enable_seqscan TO on;
+DROP INDEX inet_idx2;
 -- simple tests of inet boolean and arithmetic operators
 SELECT i, ~i AS "~i" FROM inet_tbl;
         i         |                     ~i                     
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index bf76501..2428a2c 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1105,19 +1105,28 @@ ORDER BY 1, 2, 3;
         783 |            5 | >>
         783 |            6 | -|-
         783 |            6 | ~=
+        783 |            7 | >>
         783 |            7 | @>
+        783 |            8 | <<
         783 |            8 | <@
         783 |            9 | &<|
+        783 |            9 | >>=
+        783 |           10 | <<=
         783 |           10 | <<|
         783 |           10 | <^
+        783 |           11 | <
         783 |           11 | >^
         783 |           11 | |>>
+        783 |           12 | <=
         783 |           12 | |&>
         783 |           13 | ~
+        783 |           14 | >=
         783 |           14 | @
         783 |           15 | <->
+        783 |           15 | >
         783 |           16 | @>
         783 |           18 | =
+        783 |           19 | <>
         783 |           28 | <@
         783 |           48 | <@
         783 |           68 | <@
@@ -1153,7 +1162,7 @@ ORDER BY 1, 2, 3;
        4000 |           15 | >
        4000 |           16 | @>
        4000 |           18 | =
-(71 rows)
+(80 rows)
 
 -- Check that all opclass search operators have selectivity estimators.
 -- This is not absolutely required, but it seems a reasonable thing
diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql
index 328f149..850a319 100644
--- a/src/test/regress/sql/inet.sql
+++ b/src/test/regress/sql/inet.sql
@@ -51,13 +51,14 @@ SELECT '' AS six, c AS cidr, i AS inet FROM INET_TBL
 SELECT '' AS ten, i, c,
   i < c AS lt, i <= c AS le, i = c AS eq,
   i >= c AS ge, i > c AS gt, i <> c AS ne,
-  i << c AS sb, i <<= c AS sbe,
-  i >> c AS sup, i >>= c AS spe
+  i << c AS sb, i <<= c AS sbe, i >> c AS sup,
+  i >>= c AS spe, i && c AS ovr
   FROM INET_TBL;
 
 -- check the conversion to/from text and set_netmask
 SELECT '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL;
--- check that index works correctly
+
+-- check that btree index works correctly
 CREATE INDEX inet_idx1 ON inet_tbl(i);
 SET enable_seqscan TO off;
 SELECT * FROM inet_tbl WHERE i<<'192.168.1.0/24'::cidr;
@@ -65,6 +66,23 @@ SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr;
 SET enable_seqscan TO on;
 DROP INDEX inet_idx1;
 
+-- check that gist index works correctly
+CREATE INDEX inet_idx2 ON inet_tbl using gist (i inet_ops);
+SET enable_seqscan TO off;
+SELECT * FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i <<= '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i && '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i >>= '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i >> '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i < '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i <= '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i = '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i >= '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i > '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i <> '192.168.1.0/24'::cidr ORDER BY i;
+SET enable_seqscan TO on;
+DROP INDEX inet_idx2;
+
 -- simple tests of inet boolean and arithmetic operators
 SELECT i, ~i AS "~i" FROM inet_tbl;
 SELECT i, c, i & c AS "and" FROM inet_tbl;
