diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 10d0848f5b8aa85b47803506f7a70c2dcd5c1364..29023a93c87b447ec801816f24b957a47bc82a63 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -66,6 +66,7 @@ struct netns_ipv6 {
 	unsigned long		 ip6_rt_last_gc;
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 	struct rt6_info         *ip6_prohibit_entry;
+	struct rt6_info		*ip6_policy_failed_entry;
 	struct rt6_info         *ip6_blk_hole_entry;
 	struct fib6_table       *fib6_local_tbl;
 	struct fib_rules_ops    *fib6_rules_ops;
diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
index 14404b3ebb89a54e9437ddeb2748907b0ff73d64..813fbe7899987d6848902eb08f10f8c0cbdb62ce 100644
--- a/include/uapi/linux/fib_rules.h
+++ b/include/uapi/linux/fib_rules.h
@@ -66,6 +66,10 @@ enum {
 	FR_ACT_BLACKHOLE,	/* Drop without notification */
 	FR_ACT_UNREACHABLE,	/* Drop with ENETUNREACH */
 	FR_ACT_PROHIBIT,	/* Drop with EACCES */
+	FR_ACT_RES9,
+	FR_ACT_RES10,
+	FR_ACT_RES11,
+	FR_ACT_POLICY_FAILED,	/* Drop with EACCES */
 	__FR_ACT_MAX,
 };
 
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index 5a78be51810123a000bfad4d62a5e6e58c987a2d..7d65056a6568c162f516ae7add2d7974362dd472 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -215,6 +215,7 @@ enum {
 	RTN_THROW,		/* Not in this table		*/
 	RTN_NAT,		/* Translate this address	*/
 	RTN_XRESOLVE,		/* Use external resolver	*/
+	RTN_POLICY_FAILED,	/* Failed ingress/egress policy */
 	__RTN_MAX
 };
 
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index d476b7950adf823ac1ad61537f39c201dab22771..5e4320c1d242cc08c06982ddc0e881f484147f8d 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX + 1] = {
 		.error	= -EINVAL,
 		.scope	= RT_SCOPE_NOWHERE,
 	},
+	[RTN_POLICY_FAILED] = {
+		.error	= -EACCES,
+		.scope	= RT_SCOPE_UNIVERSE,
+	},
 };
 
 static void rt_fibinfo_free(struct rtable __rcu **rtp)
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index ef40bb659a7a7e5e9f60cb24bd6bb33bb5e45af8..e3dd1d9c1377790b707c8388aa460a5197f3697b 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2396,6 +2396,7 @@ static const char *const rtn_type_names[__RTN_MAX] = {
 	[RTN_THROW] = "THROW",
 	[RTN_NAT] = "NAT",
 	[RTN_XRESOLVE] = "XRESOLVE",
+	[RTN_POLICY_FAILED] = "POLICY_FAILED",
 };
 
 static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index e9a40d127d26c68bd11bc1f12f4af117b715a1f6..40c21b7b8cbcb53005abb891c997d9eb4cc09728 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -163,6 +163,7 @@ static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp,
 	case FR_ACT_UNREACHABLE:
 		return -ENETUNREACH;
 	case FR_ACT_PROHIBIT:
+	case FR_ACT_POLICY_FAILED:
 		return -EACCES;
 	case FR_ACT_BLACKHOLE:
 	default:
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index ec849d88a66205742b1a58c4959c08eeffc3f6d7..12d011da14bbdd5b4db4937d7a7e26c2ee824c0e 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -77,6 +77,10 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
 		err = -EACCES;
 		rt = net->ipv6.ip6_prohibit_entry;
 		goto discard_pkt;
+       case FR_ACT_POLICY_FAILED:
+               err = -EACCES;
+               rt = net->ipv6.ip6_policy_failed_entry;
+               goto discard_pkt;
 	}
 
 	tb_id = fib_rule_get_table(rule, arg);
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index aeb8c64478c1240aef41c8bef6eb8b46198bb4d0..8064effcdd5e086993f6716143d3861e91f89c68 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -172,6 +172,8 @@ static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
 		return -ENETUNREACH;
 	case FR_ACT_PROHIBIT:
 		return -EACCES;
+	case FR_ACT_POLICY_FAILED:
+		return -EACCES;
 	case FR_ACT_BLACKHOLE:
 	default:
 		return -EINVAL;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index f6ac472acd0f0ea954b82151745a15fcf6fabedb..d442b7365bcd50167d34b2056c072546dc548732 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -91,6 +91,8 @@ static int		ip6_pkt_discard(struct sk_buff *skb);
 static int		ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
 static int		ip6_pkt_prohibit(struct sk_buff *skb);
 static int		ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
+static int              ip6_pkt_policy_failed(struct sk_buff *skb);
+static int              ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb);
 static void		ip6_link_failure(struct sk_buff *skb);
 static void		ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
 					   struct sk_buff *skb, u32 mtu);
@@ -300,6 +302,22 @@ static const struct rt6_info ip6_prohibit_entry_template = {
 	.rt6i_ref	= ATOMIC_INIT(1),
 };
 
+static const struct rt6_info ip6_policy_failed_entry_template = {
+       .dst = {
+               .__refcnt       = ATOMIC_INIT(1),
+               .__use          = 1,
+               .obsolete       = DST_OBSOLETE_FORCE_CHK,
+               .error          = -EACCES,
+               .input          = ip6_pkt_policy_failed,
+               .output         = ip6_pkt_policy_failed_out,
+       },
+       .rt6i_flags     = (RTF_REJECT | RTF_NONEXTHOP),
+       .rt6i_protocol  = RTPROT_KERNEL,
+       .rt6i_metric    = ~(u32) 0,
+       .rt6i_ref       = ATOMIC_INIT(1),
+};
+
+
 static const struct rt6_info ip6_blk_hole_entry_template = {
 	.dst = {
 		.__refcnt	= ATOMIC_INIT(1),
@@ -1970,6 +1988,11 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg)
 			rt->dst.output = ip6_pkt_prohibit_out;
 			rt->dst.input = ip6_pkt_prohibit;
 			break;
+		case RTN_POLICY_FAILED:
+			rt->dst.error = -EACCES;
+			rt->dst.output = ip6_pkt_policy_failed_out;
+			rt->dst.input = ip6_pkt_policy_failed;
+			break;
 		case RTN_THROW:
 		case RTN_UNREACHABLE:
 		default:
@@ -2613,6 +2636,17 @@ static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff
 	return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
 }
 
+static int ip6_pkt_policy_failed(struct sk_buff *skb)
+{
+	return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES);
+}
+
+static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb)
+{
+	skb->dev = skb_dst(skb)->dev;
+	return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES);
+}
+
 /*
  *	Allocate a dst for local (unicast / anycast) address.
  */
@@ -2850,7 +2884,8 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
 	if (rtm->rtm_type == RTN_UNREACHABLE ||
 	    rtm->rtm_type == RTN_BLACKHOLE ||
 	    rtm->rtm_type == RTN_PROHIBIT ||
-	    rtm->rtm_type == RTN_THROW)
+            rtm->rtm_type == RTN_THROW ||
+            rtm->rtm_type == RTN_POLICY_FAILED)
 		cfg->fc_flags |= RTF_REJECT;
 
 	if (rtm->rtm_type == RTN_LOCAL)
@@ -3222,6 +3257,9 @@ static int rt6_fill_node(struct net *net,
 		case -EACCES:
 			rtm->rtm_type = RTN_PROHIBIT;
 			break;
+		case -EPERM:
+			rtm->rtm_type = RTN_POLICY_FAILED;
+			break;
 		case -EAGAIN:
 			rtm->rtm_type = RTN_THROW;
 			break;
@@ -3498,6 +3536,8 @@ static int ip6_route_dev_notify(struct notifier_block *this,
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 		net->ipv6.ip6_prohibit_entry->dst.dev = dev;
 		net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
+		net->ipv6.ip6_policy_failed_entry->dst.dev = dev;
+		net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev);
 		net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
 		net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
 #endif
@@ -3724,6 +3764,17 @@ static int __net_init ip6_route_net_init(struct net *net)
 	net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
 	dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
 			 ip6_template_metrics, true);
+
+	net->ipv6.ip6_policy_failed_entry =
+		kmemdup(&ip6_policy_failed_entry_template,
+			sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL);
+	if (!net->ipv6.ip6_policy_failed_entry)
+		goto out_ip6_blk_hole_entry;
+	net->ipv6.ip6_policy_failed_entry->dst.path =
+		(struct dst_entry *)net->ipv6.ip6_policy_failed_entry;
+	net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops;
+	dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst,
+			 ip6_template_metrics, true);
 #endif
 
 	net->ipv6.sysctl.flush_delay = 0;
@@ -3742,6 +3793,8 @@ out:
 	return ret;
 
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+out_ip6_blk_hole_entry:
+	kfree(net->ipv6.ip6_blk_hole_entry);
 out_ip6_prohibit_entry:
 	kfree(net->ipv6.ip6_prohibit_entry);
 out_ip6_null_entry:
@@ -3759,6 +3812,7 @@ static void __net_exit ip6_route_net_exit(struct net *net)
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 	kfree(net->ipv6.ip6_prohibit_entry);
 	kfree(net->ipv6.ip6_blk_hole_entry);
+	kfree(net->ipv6.ip6_policy_failed_entry);
 #endif
 	dst_entries_destroy(&net->ipv6.ip6_dst_ops);
 }
@@ -3861,6 +3915,20 @@ int __init ip6_route_init(void)
 
 	ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
 
+	/* Registering of the loopback is done before this portion of code,
+	 * the loopback reference in rt6_info will not be taken, do it
+	 * manually for init_net */
+	init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+	init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+	init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+	init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_policy_failed_entry->rt6i_idev =
+		in6_dev_get(init_net.loopback_dev);
+  #endif
 	ret = fib6_init();
 	if (ret)
 		goto out_register_subsys;