diff --git a/include/uapi/linux/netfilter_ipv6/ip6t_SEG6.h b/include/uapi/linux/netfilter_ipv6/ip6t_SEG6.h
new file mode 100644
index 000000000000..443805d0d1b2
--- /dev/null
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_SEG6.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef _IP6T_SEG6_H
+#define _IP6T_SEG6_H
+
+#include <linux/types.h>
+
+/* SEG6 action options */
+enum ip6t_seg6_action {
+	IP6T_SEG6_GO_NEXT,
+	IP6T_SEG6_SKIP_NEXT,
+	IP6T_SEG6_GO_LAST,
+	IP6T_SEG6_BSID,
+};
+
+struct ip6t_seg6_info {
+	__u32			action; /* SEG6 action */
+	struct	in6_addr	bsid;	/* SRv6 Bind SID */
+	unsigned int		tbl;	/* Routing table of bsid */
+};
+
+#endif /*_IP6T_SEG6_H*/
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 339d0762b027..a2502c54a837 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -344,6 +344,21 @@ config IP6_NF_TARGET_NPT
 
 endif # IP6_NF_NAT
 
+if IPV6_SEG6_LWTUNNEL
+
+config IP6_NF_TARGET_SEG6
+	tristate 'IPv6 Segment Routing "SEG6" target support'
+	depends on NETFILTER_ADVANCED
+	help
+	 SEG6 is an ip6tables target for IPv6 Segment Routing encapsualted
+	 packets. It supports a set of Segment Routing specific actions
+	 that can be applied based on SRH information. It is useful for
+	 SRv6 Service Function chaining use-cases.
+
+	 To compile it as a module, choose M here.  If unsure, say N.
+
+endif # IPV6_SEG6_LWTUNNEL
+
 endif # IP6_NF_IPTABLES
 endmenu
 
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index 200c0c235565..68e86e18f15f 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -58,3 +58,4 @@ obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
 obj-$(CONFIG_IP6_NF_TARGET_NPT) += ip6t_NPT.o
 obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
 obj-$(CONFIG_IP6_NF_TARGET_SYNPROXY) += ip6t_SYNPROXY.o
+obj-$(CONFIG_IP6_NF_TARGET_SEG6) += ip6t_SEG6.o
diff --git a/net/ipv6/netfilter/ip6t_SEG6.c b/net/ipv6/netfilter/ip6t_SEG6.c
new file mode 100644
index 000000000000..03b5f1a1c8bf
--- /dev/null
+++ b/net/ipv6/netfilter/ip6t_SEG6.c
@@ -0,0 +1,116 @@
+/**
+ * IPv6 Segment Routing target module (SEG6).
+ *
+ * Author:
+ * Ahmed Abdelsalam <amsalam20@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version 2
+ *	of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/icmpv6.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_SEG6.h>
+
+#include <net/flow.h>
+#include <net/seg6.h>
+#include <net/ip6_route.h>
+
+static int seg6_go_next(struct sk_buff *skb, struct ipv6_sr_hdr *srh)
+{
+	if (srh->segments_left == 0)
+		return NF_DROP;
+	seg6_advance_nextseg(srh, &ipv6_hdr(skb)->daddr);
+	seg6_lookup_nexthop(skb, NULL, 0);
+	dst_input(skb);
+	return NF_STOLEN;
+}
+
+static int seg6_skip_next(struct sk_buff *skb, struct ipv6_sr_hdr *srh)
+{
+	if (srh->segments_left < 2)
+		return NF_DROP;
+	seg6_advance_nextseg(srh, &ipv6_hdr(skb)->daddr);
+	seg6_advance_nextseg(srh, &ipv6_hdr(skb)->daddr);
+	seg6_lookup_nexthop(skb, NULL, 0);
+	dst_input(skb);
+	return NF_STOLEN;
+}
+
+static int seg6_go_last(struct sk_buff *skb, struct ipv6_sr_hdr *srh)
+{
+	if (srh->segments_left == 0)
+		return NF_DROP;
+	srh->segments_left = 1;
+	seg6_advance_nextseg(srh, &ipv6_hdr(skb)->daddr);
+	seg6_lookup_nexthop(skb, NULL, 0);
+	dst_input(skb);
+	return NF_STOLEN;
+}
+
+static unsigned int
+seg6_tg6(struct sk_buff *skb, const struct xt_action_param *par)
+{
+	struct ipv6_sr_hdr *srh;
+	const struct ip6t_seg6_info *seg6 = par->targinfo;
+
+	srh = seg6_get_srh(skb);
+	if (!srh)
+		return NF_DROP;
+
+	switch (seg6->action) {
+	case IP6T_SEG6_GO_NEXT:
+		return seg6_go_next(skb, srh);
+	case IP6T_SEG6_SKIP_NEXT:
+		return seg6_skip_next(skb, srh);
+	case IP6T_SEG6_GO_LAST:
+		return seg6_go_last(skb, srh);
+	}
+
+	pr_err("Unknown SEG6 action\n");
+	return NF_DROP;
+}
+
+static int seg6_check(const struct xt_tgchk_param *par)
+{
+	/**
+	 * In the future, some new action may require using
+	 * this function for doing some checks
+	 */
+	return 0;
+}
+
+static struct xt_target seg6_tg6_reg __read_mostly = {
+	.name		= "SEG6",
+	.family		= NFPROTO_IPV6,
+	.target		= seg6_tg6,
+	.targetsize	= sizeof(struct ip6t_seg6_info),
+	.checkentry	= seg6_check,
+	.me		= THIS_MODULE
+};
+
+static int __init seg6_tg6_init(void)
+{
+	return xt_register_target(&seg6_tg6_reg);
+}
+
+static void __exit seg6_tg6_exit(void)
+{
+	xt_unregister_target(&seg6_tg6_reg);
+}
+
+module_init(seg6_tg6_init);
+module_exit(seg6_tg6_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Xtables: IPv6 Segment Routing Target (SEG6)");
+MODULE_AUTHOR("Ahmed Abdelsalam <amsalam20@gmail.com>");
