diff --git a/SOURCES/0001-Update-kernel-headers.patch b/SOURCES/0001-Update-kernel-headers.patch
new file mode 100644
index 0000000..4d6f5d2
--- /dev/null
+++ b/SOURCES/0001-Update-kernel-headers.patch
@@ -0,0 +1,226 @@
+From 4cd2ea662ae3255713a7de44e496e6ed32ade0c9 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 16 Apr 2020 12:41:48 +0200
+Subject: [PATCH] Update kernel headers
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1770671
+Upstream Status: iproute2.git commit e3af717a8d410
+
+commit e3af717a8d410c97d9e0b985219ab8fc9ff18b79
+Author: David Ahern <dsahern@gmail.com>
+Date:   Sun Aug 18 11:48:02 2019 -0700
+
+    Update kernel headers
+
+    Update kernel headers to commit:
+        d83d508b74c4 ("Merge branch 'stmmac-next'")
+
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ include/uapi/linux/bpf.h         | 37 ++++++++++++++++++-
+ include/uapi/linux/can/netlink.h |  6 ++--
+ include/uapi/linux/devlink.h     | 62 ++++++++++++++++++++++++++++++++
+ include/uapi/linux/if_bridge.h   |  1 +
+ 4 files changed, 102 insertions(+), 4 deletions(-)
+
+diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
+index 1e08475275702..79701d3e66f0b 100644
+--- a/include/uapi/linux/bpf.h
++++ b/include/uapi/linux/bpf.h
+@@ -134,6 +134,7 @@ enum bpf_map_type {
+ 	BPF_MAP_TYPE_QUEUE,
+ 	BPF_MAP_TYPE_STACK,
+ 	BPF_MAP_TYPE_SK_STORAGE,
++	BPF_MAP_TYPE_DEVMAP_HASH,
+ };
+ 
+ /* Note that tracing related programs such as
+@@ -2713,6 +2714,33 @@ union bpf_attr {
+  *		**-EPERM** if no permission to send the *sig*.
+  *
+  *		**-EAGAIN** if bpf program can try again.
++ *
++ * s64 bpf_tcp_gen_syncookie(struct bpf_sock *sk, void *iph, u32 iph_len, struct tcphdr *th, u32 th_len)
++ *	Description
++ *		Try to issue a SYN cookie for the packet with corresponding
++ *		IP/TCP headers, *iph* and *th*, on the listening socket in *sk*.
++ *
++ *		*iph* points to the start of the IPv4 or IPv6 header, while
++ *		*iph_len* contains **sizeof**\ (**struct iphdr**) or
++ *		**sizeof**\ (**struct ip6hdr**).
++ *
++ *		*th* points to the start of the TCP header, while *th_len*
++ *		contains the length of the TCP header.
++ *
++ *	Return
++ *		On success, lower 32 bits hold the generated SYN cookie in
++ *		followed by 16 bits which hold the MSS value for that cookie,
++ *		and the top 16 bits are unused.
++ *
++ *		On failure, the returned value is one of the following:
++ *
++ *		**-EINVAL** SYN cookie cannot be issued due to error
++ *
++ *		**-ENOENT** SYN cookie should not be issued (no SYN flood)
++ *
++ *		**-EOPNOTSUPP** kernel configuration does not enable SYN cookies
++ *
++ *		**-EPROTONOSUPPORT** IP packet version is not 4 or 6
+  */
+ #define __BPF_FUNC_MAPPER(FN)		\
+ 	FN(unspec),			\
+@@ -2824,7 +2852,8 @@ union bpf_attr {
+ 	FN(strtoul),			\
+ 	FN(sk_storage_get),		\
+ 	FN(sk_storage_delete),		\
+-	FN(send_signal),
++	FN(send_signal),		\
++	FN(tcp_gen_syncookie),
+ 
+ /* integer value in 'imm' field of BPF_CALL instruction selects which helper
+  * function eBPF program intends to call
+@@ -3507,6 +3536,10 @@ enum bpf_task_fd_type {
+ 	BPF_FD_TYPE_URETPROBE,		/* filename + offset */
+ };
+ 
++#define BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG		(1U << 0)
++#define BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL		(1U << 1)
++#define BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP		(1U << 2)
++
+ struct bpf_flow_keys {
+ 	__u16	nhoff;
+ 	__u16	thoff;
+@@ -3528,6 +3561,8 @@ struct bpf_flow_keys {
+ 			__u32	ipv6_dst[4];	/* in6_addr; network order */
+ 		};
+ 	};
++	__u32	flags;
++	__be32	flow_label;
+ };
+ 
+ struct bpf_func_info {
+diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h
+index f0c5e58b8ee76..c1f62640e87bc 100644
+--- a/include/uapi/linux/can/netlink.h
++++ b/include/uapi/linux/can/netlink.h
+@@ -40,15 +40,15 @@ struct can_bittiming {
+ };
+ 
+ /*
+- * CAN harware-dependent bit-timing constant
++ * CAN hardware-dependent bit-timing constant
+  *
+  * Used for calculating and checking bit-timing parameters
+  */
+ struct can_bittiming_const {
+ 	char name[16];		/* Name of the CAN controller hardware */
+-	__u32 tseg1_min;	/* Time segement 1 = prop_seg + phase_seg1 */
++	__u32 tseg1_min;	/* Time segment 1 = prop_seg + phase_seg1 */
+ 	__u32 tseg1_max;
+-	__u32 tseg2_min;	/* Time segement 2 = phase_seg2 */
++	__u32 tseg2_min;	/* Time segment 2 = phase_seg2 */
+ 	__u32 tseg2_max;
+ 	__u32 sjw_max;		/* Synchronisation jump width */
+ 	__u32 brp_min;		/* Bit-rate prescaler */
+diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
+index fc195cbd66f45..3fb683bee6ba1 100644
+--- a/include/uapi/linux/devlink.h
++++ b/include/uapi/linux/devlink.h
+@@ -107,6 +107,16 @@ enum devlink_command {
+ 	DEVLINK_CMD_FLASH_UPDATE_END,		/* notification only */
+ 	DEVLINK_CMD_FLASH_UPDATE_STATUS,	/* notification only */
+ 
++	DEVLINK_CMD_TRAP_GET,		/* can dump */
++	DEVLINK_CMD_TRAP_SET,
++	DEVLINK_CMD_TRAP_NEW,
++	DEVLINK_CMD_TRAP_DEL,
++
++	DEVLINK_CMD_TRAP_GROUP_GET,	/* can dump */
++	DEVLINK_CMD_TRAP_GROUP_SET,
++	DEVLINK_CMD_TRAP_GROUP_NEW,
++	DEVLINK_CMD_TRAP_GROUP_DEL,
++
+ 	/* add new commands above here */
+ 	__DEVLINK_CMD_MAX,
+ 	DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
+@@ -194,6 +204,47 @@ enum devlink_param_fw_load_policy_value {
+ 	DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
+ };
+ 
++enum {
++	DEVLINK_ATTR_STATS_RX_PACKETS,		/* u64 */
++	DEVLINK_ATTR_STATS_RX_BYTES,		/* u64 */
++
++	__DEVLINK_ATTR_STATS_MAX,
++	DEVLINK_ATTR_STATS_MAX = __DEVLINK_ATTR_STATS_MAX - 1
++};
++
++/**
++ * enum devlink_trap_action - Packet trap action.
++ * @DEVLINK_TRAP_ACTION_DROP: Packet is dropped by the device and a copy is not
++ *                            sent to the CPU.
++ * @DEVLINK_TRAP_ACTION_TRAP: The sole copy of the packet is sent to the CPU.
++ */
++enum devlink_trap_action {
++	DEVLINK_TRAP_ACTION_DROP,
++	DEVLINK_TRAP_ACTION_TRAP,
++};
++
++/**
++ * enum devlink_trap_type - Packet trap type.
++ * @DEVLINK_TRAP_TYPE_DROP: Trap reason is a drop. Trapped packets are only
++ *                          processed by devlink and not injected to the
++ *                          kernel's Rx path.
++ * @DEVLINK_TRAP_TYPE_EXCEPTION: Trap reason is an exception. Packet was not
++ *                               forwarded as intended due to an exception
++ *                               (e.g., missing neighbour entry) and trapped to
++ *                               control plane for resolution. Trapped packets
++ *                               are processed by devlink and injected to
++ *                               the kernel's Rx path.
++ */
++enum devlink_trap_type {
++	DEVLINK_TRAP_TYPE_DROP,
++	DEVLINK_TRAP_TYPE_EXCEPTION,
++};
++
++enum {
++	/* Trap can report input port as metadata */
++	DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT,
++};
++
+ enum devlink_attr {
+ 	/* don't change the order or add anything between, this is ABI! */
+ 	DEVLINK_ATTR_UNSPEC,
+@@ -348,6 +399,17 @@ enum devlink_attr {
+ 	DEVLINK_ATTR_PORT_PCI_PF_NUMBER,	/* u16 */
+ 	DEVLINK_ATTR_PORT_PCI_VF_NUMBER,	/* u16 */
+ 
++	DEVLINK_ATTR_STATS,				/* nested */
++
++	DEVLINK_ATTR_TRAP_NAME,				/* string */
++	/* enum devlink_trap_action */
++	DEVLINK_ATTR_TRAP_ACTION,			/* u8 */
++	/* enum devlink_trap_type */
++	DEVLINK_ATTR_TRAP_TYPE,				/* u8 */
++	DEVLINK_ATTR_TRAP_GENERIC,			/* flag */
++	DEVLINK_ATTR_TRAP_METADATA,			/* nested */
++	DEVLINK_ATTR_TRAP_GROUP_NAME,			/* string */
++
+ 	/* add new attributes above here, update the policy in devlink.c */
+ 
+ 	__DEVLINK_ATTR_MAX,
+diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
+index 04f763cf53029..31fc51bdedb3c 100644
+--- a/include/uapi/linux/if_bridge.h
++++ b/include/uapi/linux/if_bridge.h
+@@ -237,6 +237,7 @@ struct br_mdb_entry {
+ #define MDB_PERMANENT 1
+ 	__u8 state;
+ #define MDB_FLAGS_OFFLOAD	(1 << 0)
++#define MDB_FLAGS_FAST_LEAVE	(1 << 1)
+ 	__u8 flags;
+ 	__u16 vid;
+ 	struct {
+-- 
+2.25.4
+
diff --git a/SOURCES/0002-Update-kernel-headers.patch b/SOURCES/0002-Update-kernel-headers.patch
new file mode 100644
index 0000000..3ffe6a3
--- /dev/null
+++ b/SOURCES/0002-Update-kernel-headers.patch
@@ -0,0 +1,140 @@
+From 864c5a906ccfe205f886aa4bfb69f738a9a4fb45 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 16 Apr 2020 12:41:49 +0200
+Subject: [PATCH] Update kernel headers
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1770671
+Upstream Status: iproute2.git commit 17a948c80af57
+
+commit 17a948c80af57da2fa86a8e34153f755f86e9c9c
+Author: David Ahern <dsahern@gmail.com>
+Date:   Sat Nov 2 07:43:01 2019 -0700
+
+    Update kernel headers
+
+    Update kernel headers to commit:
+        c23fcbbc6aa4 ("tc-testing: added tests with cookie for conntrack TC action")
+
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ include/uapi/linux/bpf.h     | 28 +++++++++++++++++++++++++++-
+ include/uapi/linux/pkt_cls.h |  5 +++++
+ include/uapi/linux/tcp.h     | 10 +++++++++-
+ include/uapi/linux/tipc.h    |  1 +
+ 4 files changed, 42 insertions(+), 2 deletions(-)
+
+diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
+index 79701d3e66f0b..3e195ff43fa01 100644
+--- a/include/uapi/linux/bpf.h
++++ b/include/uapi/linux/bpf.h
+@@ -413,6 +413,7 @@ union bpf_attr {
+ 		__u32		line_info_rec_size;	/* userspace bpf_line_info size */
+ 		__aligned_u64	line_info;	/* line info */
+ 		__u32		line_info_cnt;	/* number of bpf_line_info records */
++		__u32		attach_btf_id;	/* in-kernel BTF type id to attach to */
+ 	};
+ 
+ 	struct { /* anonymous struct used by BPF_OBJ_* commands */
+@@ -2741,6 +2742,30 @@ union bpf_attr {
+  *		**-EOPNOTSUPP** kernel configuration does not enable SYN cookies
+  *
+  *		**-EPROTONOSUPPORT** IP packet version is not 4 or 6
++ *
++ * int bpf_skb_output(void *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)
++ * 	Description
++ * 		Write raw *data* blob into a special BPF perf event held by
++ * 		*map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf
++ * 		event must have the following attributes: **PERF_SAMPLE_RAW**
++ * 		as **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and
++ * 		**PERF_COUNT_SW_BPF_OUTPUT** as **config**.
++ *
++ * 		The *flags* are used to indicate the index in *map* for which
++ * 		the value must be put, masked with **BPF_F_INDEX_MASK**.
++ * 		Alternatively, *flags* can be set to **BPF_F_CURRENT_CPU**
++ * 		to indicate that the index of the current CPU core should be
++ * 		used.
++ *
++ * 		The value to write, of *size*, is passed through eBPF stack and
++ * 		pointed by *data*.
++ *
++ * 		*ctx* is a pointer to in-kernel struct sk_buff.
++ *
++ * 		This helper is similar to **bpf_perf_event_output**\ () but
++ * 		restricted to raw_tracepoint bpf programs.
++ * 	Return
++ * 		0 on success, or a negative error in case of failure.
+  */
+ #define __BPF_FUNC_MAPPER(FN)		\
+ 	FN(unspec),			\
+@@ -2853,7 +2878,8 @@ union bpf_attr {
+ 	FN(sk_storage_get),		\
+ 	FN(sk_storage_delete),		\
+ 	FN(send_signal),		\
+-	FN(tcp_gen_syncookie),
++	FN(tcp_gen_syncookie),		\
++	FN(skb_output),
+ 
+ /* integer value in 'imm' field of BPF_CALL instruction selects which helper
+  * function eBPF program intends to call
+diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
+index b057aeeb63386..0a9ab625cba7b 100644
+--- a/include/uapi/linux/pkt_cls.h
++++ b/include/uapi/linux/pkt_cls.h
+@@ -16,9 +16,14 @@ enum {
+ 	TCA_ACT_STATS,
+ 	TCA_ACT_PAD,
+ 	TCA_ACT_COOKIE,
++	TCA_ACT_FLAGS,
+ 	__TCA_ACT_MAX
+ };
+ 
++#define TCA_ACT_FLAGS_NO_PERCPU_STATS 1 /* Don't use percpu allocator for
++					 * actions stats.
++					 */
++
+ #define TCA_ACT_MAX __TCA_ACT_MAX
+ #define TCA_OLD_COMPAT (TCA_ACT_MAX+1)
+ #define TCA_ACT_MAX_PRIO 32
+diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h
+index 3fd9b29146b17..acb15ca8558c0 100644
+--- a/include/uapi/linux/tcp.h
++++ b/include/uapi/linux/tcp.h
+@@ -155,6 +155,14 @@ enum {
+ 	TCP_QUEUES_NR,
+ };
+ 
++/* why fastopen failed from client perspective */
++enum tcp_fastopen_client_fail {
++	TFO_STATUS_UNSPEC, /* catch-all */
++	TFO_COOKIE_UNAVAILABLE, /* if not in TFO_CLIENT_NO_COOKIE mode */
++	TFO_DATA_NOT_ACKED, /* SYN-ACK did not ack SYN data */
++	TFO_SYN_RETRANSMITTED, /* SYN-ACK did not ack SYN data after timeout */
++};
++
+ /* for TCP_INFO socket option */
+ #define TCPI_OPT_TIMESTAMPS	1
+ #define TCPI_OPT_SACK		2
+@@ -211,7 +219,7 @@ struct tcp_info {
+ 	__u8	tcpi_backoff;
+ 	__u8	tcpi_options;
+ 	__u8	tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
+-	__u8	tcpi_delivery_rate_app_limited:1;
++	__u8	tcpi_delivery_rate_app_limited:1, tcpi_fastopen_client_fail:2;
+ 
+ 	__u32	tcpi_rto;
+ 	__u32	tcpi_ato;
+diff --git a/include/uapi/linux/tipc.h b/include/uapi/linux/tipc.h
+index e16cb4e2af587..0f6f28b2e3010 100644
+--- a/include/uapi/linux/tipc.h
++++ b/include/uapi/linux/tipc.h
+@@ -191,6 +191,7 @@ struct sockaddr_tipc {
+ #define TIPC_GROUP_JOIN         135     /* Takes struct tipc_group_req* */
+ #define TIPC_GROUP_LEAVE        136     /* No argument */
+ #define TIPC_SOCK_RECVQ_USED    137     /* Default: none (read only) */
++#define TIPC_NODELAY            138     /* Default: false */
+ 
+ /*
+  * Flag values
+-- 
+2.25.4
+
diff --git a/SOURCES/0003-tc-implement-support-for-action-flags.patch b/SOURCES/0003-tc-implement-support-for-action-flags.patch
new file mode 100644
index 0000000..aef92b7
--- /dev/null
+++ b/SOURCES/0003-tc-implement-support-for-action-flags.patch
@@ -0,0 +1,116 @@
+From a3d12445422afa12a67a7cd121b7add89f6c7d67 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 16 Apr 2020 12:41:49 +0200
+Subject: [PATCH] tc: implement support for action flags
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1770671
+Upstream Status: iproute2.git commit fb2e033add073
+
+commit fb2e033add073893dea71bb483353790fe8c5354
+Author: Vlad Buslov <vladbu@mellanox.com>
+Date:   Wed Oct 30 16:20:40 2019 +0200
+
+    tc: implement support for action flags
+
+    Implement setting and printing of action flags with single available flag
+    value "no_percpu" that translates to kernel UAPI TCA_ACT_FLAGS value
+    TCA_ACT_FLAGS_NO_PERCPU_STATS. Update man page with information regarding
+    usage of action flags.
+
+    Example usage:
+
+     # tc actions add action gact drop no_percpu
+     # sudo tc actions list action gact
+     total acts 1
+
+            action order 0: gact action drop
+             random type none pass val 0
+             index 1 ref 1 bind 0
+            no_percpu
+
+    Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ man/man8/tc-actions.8 | 14 ++++++++++++++
+ tc/m_action.c         | 19 +++++++++++++++++++
+ 2 files changed, 33 insertions(+)
+
+diff --git a/man/man8/tc-actions.8 b/man/man8/tc-actions.8
+index f46166e3f6859..bee59f7247fae 100644
+--- a/man/man8/tc-actions.8
++++ b/man/man8/tc-actions.8
+@@ -47,6 +47,8 @@ actions \- independently defined actions in tc
+ ] [
+ .I COOKIESPEC
+ ] [
++.I FLAGS
++] [
+ .I CONTROL
+ ]
+ 
+@@ -71,6 +73,10 @@ ACTNAME
+ :=
+ .BI cookie " COOKIE"
+ 
++.I FLAGS
++:=
++.I no_percpu
++
+ .I ACTDETAIL
+ :=
+ .I ACTNAME ACTPARAMS
+@@ -186,6 +192,14 @@ As such, it can be used as a correlating value for maintaining user state.
+ The value to be stored is completely arbitrary and does not require a specific
+ format. It is stored inside the action structure itself.
+ 
++.TP
++.I FLAGS
++Action-specific flags. Currently, the only supported flag is
++.I no_percpu
++which indicates that action is expected to have minimal software data-path
++traffic and doesn't need to allocate stat counters with percpu allocator.
++This option is intended to be used by hardware-offloaded actions.
++
+ .TP
+ .BI since " MSTIME"
+ When dumping large number of actions, a millisecond time-filter can be
+diff --git a/tc/m_action.c b/tc/m_action.c
+index bdc62720879c1..c46aeaafa8ebf 100644
+--- a/tc/m_action.c
++++ b/tc/m_action.c
+@@ -249,6 +249,16 @@ done0:
+ 				addattr_l(n, MAX_MSG, TCA_ACT_COOKIE,
+ 					  &act_ck, act_ck_len);
+ 
++			if (*argv && strcmp(*argv, "no_percpu") == 0) {
++				struct nla_bitfield32 flags =
++					{ TCA_ACT_FLAGS_NO_PERCPU_STATS,
++					  TCA_ACT_FLAGS_NO_PERCPU_STATS };
++
++				addattr_l(n, MAX_MSG, TCA_ACT_FLAGS, &flags,
++					  sizeof(struct nla_bitfield32));
++				NEXT_ARG_FWD();
++			}
++
+ 			addattr_nest_end(n, tail);
+ 			ok++;
+ 		}
+@@ -317,6 +327,15 @@ static int tc_print_one_action(FILE *f, struct rtattr *arg)
+ 					   strsz, b1, sizeof(b1)));
+ 		print_string(PRINT_FP, NULL, "%s", _SL_);
+ 	}
++	if (tb[TCA_ACT_FLAGS]) {
++		struct nla_bitfield32 *flags = RTA_DATA(tb[TCA_ACT_FLAGS]);
++
++		if (flags->selector & TCA_ACT_FLAGS_NO_PERCPU_STATS)
++			print_bool(PRINT_ANY, "no_percpu", "\tno_percpu",
++				   flags->value &
++				   TCA_ACT_FLAGS_NO_PERCPU_STATS);
++		print_string(PRINT_FP, NULL, "%s", _SL_);
++	}
+ 
+ 	return 0;
+ }
+-- 
+2.25.4
+
diff --git a/SOURCES/0004-man-rdma-statistic-Add-filter-description.patch b/SOURCES/0004-man-rdma-statistic-Add-filter-description.patch
new file mode 100644
index 0000000..9b805b9
--- /dev/null
+++ b/SOURCES/0004-man-rdma-statistic-Add-filter-description.patch
@@ -0,0 +1,110 @@
+From f0596659bb2ba71bbe6ec80df9d54ea02775f40f Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 23 Apr 2020 12:47:12 +0200
+Subject: [PATCH] man: rdma-statistic: Add filter description
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1786565
+Upstream Status: iproute2.git commit 31824e2299bf5
+
+commit 31824e2299bf5dc609026436db629b0c25cc1a10
+Author: Andrea Claudi <aclaudi@redhat.com>
+Date:   Fri Feb 28 18:36:25 2020 +0100
+
+    man: rdma-statistic: Add filter description
+
+    Add description for filters on rdma statistics show command.
+    Also add a filter description on the help message of the command.
+    Additionally, fix some whitespace issue in the man page.
+
+    Reported-by: Zhaojuan Guo <zguo@redhat.com>
+    Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
+    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+---
+ man/man8/rdma-statistic.8 | 16 ++++++++++++----
+ rdma/stat.c               |  1 +
+ 2 files changed, 13 insertions(+), 4 deletions(-)
+
+diff --git a/man/man8/rdma-statistic.8 b/man/man8/rdma-statistic.8
+index dea6ff24b499b..cd85ca46993a0 100644
+--- a/man/man8/rdma-statistic.8
++++ b/man/man8/rdma-statistic.8
+@@ -9,7 +9,7 @@ rdma-statistic \- RDMA statistic counter configuration
+ .B rdma
+ .RI "[ " OPTIONS " ]"
+ .B statistic
+-.RI  " { " COMMAND " | "
++.RI  "{ " COMMAND " | "
+ .BR help " }"
+ .sp
+ 
+@@ -23,6 +23,7 @@ rdma-statistic \- RDMA statistic counter configuration
+ .RI "[ " OBJECT " ]"
+ .B show link
+ .RI "[ " DEV/PORT_INDX " ]"
++.RI "[ " FILTER_NAME " " FILTER_VALUE " ]"
+ 
+ .ti -8
+ .B rdma statistic
+@@ -34,7 +35,7 @@ rdma-statistic \- RDMA statistic counter configuration
+ .IR OBJECT
+ .B set
+ .IR COUNTER_SCOPE
+-.RI "[ " DEV/PORT_INDEX "]"
++.RI "[ " DEV/PORT_INDEX " ]"
+ .B auto
+ .RI "{ " CRITERIA " | "
+ .BR off " }"
+@@ -44,7 +45,7 @@ rdma-statistic \- RDMA statistic counter configuration
+ .IR OBJECT
+ .B bind
+ .IR COUNTER_SCOPE
+-.RI "[ " DEV/PORT_INDEX "]"
++.RI "[ " DEV/PORT_INDEX " ]"
+ .RI "[ " OBJECT-ID " ]"
+ .RI "[ " COUNTER-ID " ]"
+ 
+@@ -53,7 +54,7 @@ rdma-statistic \- RDMA statistic counter configuration
+ .IR OBJECT
+ .B unbind
+ .IR COUNTER_SCOPE
+-.RI "[ " DEV/PORT_INDEX "]"
++.RI "[ " DEV/PORT_INDEX " ]"
+ .RI "[ " COUNTER-ID " ]"
+ .RI "[ " OBJECT-ID " ]"
+ 
+@@ -69,6 +70,10 @@ rdma-statistic \- RDMA statistic counter configuration
+ .IR CRITERIA " := "
+ .RB "{ " type " }"
+ 
++.ti -8
++.IR FILTER_NAME " := "
++.RB "{ " cntn " | " lqpn " | " pid " }"
++
+ .SH "DESCRIPTION"
+ .SS rdma statistic [object] show - Queries the specified RDMA device for RDMA and driver-specific statistics. Show the default hw counters if object is not specified
+ 
+@@ -79,6 +84,9 @@ rdma-statistic \- RDMA statistic counter configuration
+ .I "PORT_INDEX"
+ - specifies counters on this RDMA port to show.
+ 
++.I "FILTER_NAME
++- specifies a filter to show only the results matching it.
++
+ .SS rdma statistic <object> set - configure counter statistic auto-mode for a specific device/port
+ In auto mode all objects belong to one category are bind automatically to a single counter set.
+ 
+diff --git a/rdma/stat.c b/rdma/stat.c
+index ef0bbcf147a70..cd99b7ace73fc 100644
+--- a/rdma/stat.c
++++ b/rdma/stat.c
+@@ -22,6 +22,7 @@ static int stat_help(struct rd *rd)
+ 	pr_out("where  OBJECT: = { qp }\n");
+ 	pr_out("       CRITERIA : = { type }\n");
+ 	pr_out("       COUNTER_SCOPE: = { link | dev }\n");
++	pr_out("       FILTER_NAME: = { cntn | lqpn | pid }\n");
+ 	pr_out("Examples:\n");
+ 	pr_out("       %s statistic qp show\n", rd->filename);
+ 	pr_out("       %s statistic qp show link mlx5_2/1\n", rd->filename);
+-- 
+2.25.4
+
diff --git a/SOURCES/0005-man-rdma.8-Add-missing-resource-subcommand-descripti.patch b/SOURCES/0005-man-rdma.8-Add-missing-resource-subcommand-descripti.patch
new file mode 100644
index 0000000..2a64a79
--- /dev/null
+++ b/SOURCES/0005-man-rdma.8-Add-missing-resource-subcommand-descripti.patch
@@ -0,0 +1,51 @@
+From 44362b42a40ed0f3a3598f55318ed4b0c9f8eb94 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 23 Apr 2020 12:49:03 +0200
+Subject: [PATCH] man: rdma.8: Add missing resource subcommand description
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1786576
+Upstream Status: iproute2.git commit 8f1c9d4a3c0d4
+
+commit 8f1c9d4a3c0d4e720026b942c922372b3c12e110
+Author: Andrea Claudi <aclaudi@redhat.com>
+Date:   Fri Feb 28 18:36:24 2020 +0100
+
+    man: rdma.8: Add missing resource subcommand description
+
+    Add resource subcommand in the OBJECT section and a short
+    description for it.
+
+    Reported-by: Zhaojuan Guo <zguo@redhat.com>
+    Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
+    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+---
+ man/man8/rdma.8 | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/man/man8/rdma.8 b/man/man8/rdma.8
+index ef29b1c633644..221bf3343bf4c 100644
+--- a/man/man8/rdma.8
++++ b/man/man8/rdma.8
+@@ -19,7 +19,7 @@ rdma \- RDMA tool
+ 
+ .ti -8
+ .IR OBJECT " := { "
+-.BR dev " | " link " | " system " | " statistic " }"
++.BR dev " | " link " | " resource " | " system " | " statistic " }"
+ .sp
+ 
+ .ti -8
+@@ -70,6 +70,10 @@ Generate JSON output.
+ .B link
+ - RDMA port related.
+ 
++.TP
++.B resource
++- RDMA resource configuration.
++
+ .TP
+ .B sys
+ - RDMA subsystem related.
+-- 
+2.25.4
+
diff --git a/SOURCES/0006-ip-xfrm-Fix-help-messages.patch b/SOURCES/0006-ip-xfrm-Fix-help-messages.patch
new file mode 100644
index 0000000..11858c1
--- /dev/null
+++ b/SOURCES/0006-ip-xfrm-Fix-help-messages.patch
@@ -0,0 +1,108 @@
+From 028ce3bafd9c8415a0cd72ff135f9498d833db21 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Wed, 15 Apr 2020 19:09:48 +0200
+Subject: [PATCH] ip-xfrm: Fix help messages
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1796045
+Upstream Status: iproute2.git commit 38dd041bfe773
+
+commit 38dd041bfe773e481ebf9c8250e49c665af2e215
+Author: Andrea Claudi <aclaudi@redhat.com>
+Date:   Wed Jan 29 15:56:40 2020 +0100
+
+    ip-xfrm: Fix help messages
+
+    After commit 8589eb4efdf2a ("treewide: refactor help messages") help
+    messages for xfrm state and policy are broken, printing many times the
+    same protocol in UPSPEC section:
+
+    $ ip xfrm state help
+    [...]
+    UPSPEC := proto { { tcp | tcp | tcp | tcp } [ sport PORT ] [ dport PORT ] |
+                      { icmp | icmp | icmp } [ type NUMBER ] [ code NUMBER ] |
+                      gre [ key { DOTTED-QUAD | NUMBER } ] | PROTO }
+
+    This happens because strxf_proto function is non-reentrant and gets called
+    multiple times in the same fprintf instruction.
+
+    This commit fix the issue avoiding calls to strxf_proto() with a constant
+    param, just hardcoding strings for protocol names.
+
+    Fixes: 8589eb4efdf2a ("treewide: refactor help messages")
+    Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
+    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+---
+ ip/xfrm_policy.c | 21 +++------------------
+ ip/xfrm_state.c  | 24 +++---------------------
+ 2 files changed, 6 insertions(+), 39 deletions(-)
+
+diff --git a/ip/xfrm_policy.c b/ip/xfrm_policy.c
+index 7c0233c182902..d3c706d3225f0 100644
+--- a/ip/xfrm_policy.c
++++ b/ip/xfrm_policy.c
+@@ -66,24 +66,9 @@ static void usage(void)
+ 		"Usage: ip xfrm policy count\n"
+ 		"Usage: ip xfrm policy set [ hthresh4 LBITS RBITS ] [ hthresh6 LBITS RBITS ]\n"
+ 		"SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n"
+-		"UPSPEC := proto { { ");
+-	fprintf(stderr, "%s | %s | %s | %s } ",
+-		strxf_proto(IPPROTO_TCP),
+-		strxf_proto(IPPROTO_UDP),
+-		strxf_proto(IPPROTO_SCTP),
+-		strxf_proto(IPPROTO_DCCP));
+-	fprintf(stderr,
+-		"[ sport PORT ] [ dport PORT ] |\n"
+-		"                  { %s | %s | %s } ",
+-		strxf_proto(IPPROTO_ICMP),
+-		strxf_proto(IPPROTO_ICMPV6),
+-		strxf_proto(IPPROTO_MH));
+-	fprintf(stderr,
+-		"[ type NUMBER ] [ code NUMBER ] |\n"
+-		"                  %s",
+-		strxf_proto(IPPROTO_GRE));
+-	fprintf(stderr,
+-		" [ key { DOTTED-QUAD | NUMBER } ] | PROTO }\n"
++		"UPSPEC := proto { { tcp | udp | sctp | dccp } [ sport PORT ] [ dport PORT ] |\n"
++		"                  { icmp | ipv6-icmp | mobility-header } [ type NUMBER ] [ code NUMBER ] |\n"
++		"                  gre [ key { DOTTED-QUAD | NUMBER } ] | PROTO }\n"
+ 		"DIR := in | out | fwd\n"
+ 		"PTYPE := main | sub\n"
+ 		"ACTION := allow | block\n"
+diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
+index b03ccc5807e90..7b413cd9b9a22 100644
+--- a/ip/xfrm_state.c
++++ b/ip/xfrm_state.c
+@@ -106,27 +106,9 @@ static void usage(void)
+ 		"EXTRA-FLAG-LIST := [ EXTRA-FLAG-LIST ] EXTRA-FLAG\n"
+ 		"EXTRA-FLAG := dont-encap-dscp\n"
+ 		"SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n"
+-		"UPSPEC := proto { { ");
+-	fprintf(stderr,
+-		"%s | %s | %s | %s",
+-		strxf_proto(IPPROTO_TCP),
+-		strxf_proto(IPPROTO_UDP),
+-		strxf_proto(IPPROTO_SCTP),
+-		strxf_proto(IPPROTO_DCCP));
+-	fprintf(stderr,
+-		" } [ sport PORT ] [ dport PORT ] |\n"
+-		"                  { ");
+-	fprintf(stderr,
+-		"%s | %s | %s",
+-		strxf_proto(IPPROTO_ICMP),
+-		strxf_proto(IPPROTO_ICMPV6),
+-		strxf_proto(IPPROTO_MH));
+-	fprintf(stderr,
+-		" } [ type NUMBER ] [ code NUMBER ] |\n");
+-	fprintf(stderr,
+-		"                  %s", strxf_proto(IPPROTO_GRE));
+-	fprintf(stderr,
+-		" [ key { DOTTED-QUAD | NUMBER } ] | PROTO }\n"
++		"UPSPEC := proto { { tcp | udp | sctp | dccp } [ sport PORT ] [ dport PORT ] |\n"
++		"                  { icmp | ipv6-icmp | mobility-header } [ type NUMBER ] [ code NUMBER ] |\n"
++		"                  gre [ key { DOTTED-QUAD | NUMBER } ] | PROTO }\n"
+ 		"LIMIT-LIST := [ LIMIT-LIST ] limit LIMIT\n"
+ 		"LIMIT := { time-soft | time-hard | time-use-soft | time-use-hard } SECONDS |\n"
+ 		"         { byte-soft | byte-hard } SIZE | { packet-soft | packet-hard } COUNT\n"
+-- 
+2.25.4
+
diff --git a/SOURCES/0007-xfrm-not-try-to-delete-ipcomp-states-when-using-dele.patch b/SOURCES/0007-xfrm-not-try-to-delete-ipcomp-states-when-using-dele.patch
new file mode 100644
index 0000000..66d479f
--- /dev/null
+++ b/SOURCES/0007-xfrm-not-try-to-delete-ipcomp-states-when-using-dele.patch
@@ -0,0 +1,55 @@
+From 7c1351ea866ec811ade4452b5f1791b34b0effe3 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 16 Apr 2020 12:10:23 +0200
+Subject: [PATCH] xfrm: not try to delete ipcomp states when using deleteall
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1808634
+Upstream Status: iproute2.git commit f9d696cf414c2
+
+commit f9d696cf414c2c475764aa3b29cf288350f1e21f
+Author: Xin Long <lucien.xin@gmail.com>
+Date:   Mon Feb 24 09:57:01 2020 -0500
+
+    xfrm: not try to delete ipcomp states when using deleteall
+
+    In kernel space, ipcomp(sub) states used by main states are not
+    allowed to be deleted by users, they would be freed only when
+    all main states are destroyed and no one uses them.
+
+    In user space, ip xfrm sta deleteall doesn't filter these ipcomp
+    states out, and it causes errors:
+
+      # ip xfrm state add src 192.168.0.1 dst 192.168.0.2 spi 0x1000 \
+          proto comp comp deflate mode tunnel sel src 192.168.0.1 dst \
+          192.168.0.2 proto gre
+      # ip xfrm sta deleteall
+      Failed to send delete-all request
+      : Operation not permitted
+
+    This patch is to fix it by filtering ipcomp states with a check
+    xsinfo->id.proto == IPPROTO_IPIP.
+
+    Fixes: c7699875bee0 ("Import patch ipxfrm-20040707_2.diff")
+    Signed-off-by: Xin Long <lucien.xin@gmail.com>
+    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+---
+ ip/xfrm_state.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
+index 7b413cd9b9a22..d014444e9af4f 100644
+--- a/ip/xfrm_state.c
++++ b/ip/xfrm_state.c
+@@ -1131,6 +1131,9 @@ static int xfrm_state_keep(struct nlmsghdr *n, void *arg)
+ 	if (!xfrm_state_filter_match(xsinfo))
+ 		return 0;
+ 
++	if (xsinfo->id.proto == IPPROTO_IPIP)
++		return 0;
++
+ 	if (xb->offset > xb->size) {
+ 		fprintf(stderr, "State buffer overflow\n");
+ 		return -1;
+-- 
+2.25.4
+
diff --git a/SOURCES/0008-man-ip.8-Add-missing-vrf-subcommand-description.patch b/SOURCES/0008-man-ip.8-Add-missing-vrf-subcommand-description.patch
new file mode 100644
index 0000000..0a36572
--- /dev/null
+++ b/SOURCES/0008-man-ip.8-Add-missing-vrf-subcommand-description.patch
@@ -0,0 +1,59 @@
+From 310becad3223411bc26e0401a838f2a7063406f3 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 23 Apr 2020 18:56:14 +0200
+Subject: [PATCH] man: ip.8: Add missing vrf subcommand description
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1780010
+Upstream Status: iproute2.git commit 229bb886a3c44
+
+commit 229bb886a3c4444521eca16c7ab74a539aaf9cb4
+Author: Andrea Claudi <aclaudi@redhat.com>
+Date:   Thu Feb 27 17:45:43 2020 +0100
+
+    man: ip.8: Add missing vrf subcommand description
+
+    Add description to the vrf subcommand and a reference to the
+    dedicated man page.
+
+    Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
+    Reviewed-by: David Ahern <dsahern@gmail.com>
+    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+---
+ man/man8/ip.8 | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/man/man8/ip.8 b/man/man8/ip.8
+index e2bda2a2ea904..c425aaf1d506e 100644
+--- a/man/man8/ip.8
++++ b/man/man8/ip.8
+@@ -22,7 +22,7 @@ ip \- show / manipulate routing, network devices, interfaces and tunnels
+ .BR link " | " address " | " addrlabel " | " route " | " rule " | " neigh " | "\
+  ntable " | " tunnel " | " tuntap " | " maddress " | "  mroute " | " mrule " | "\
+  monitor " | " xfrm " | " netns " | "  l2tp " | "  tcp_metrics " | " token " | "\
+- macsec " }"
++ macsec " | " vrf " }"
+ .sp
+ 
+ .ti -8
+@@ -312,6 +312,10 @@ readability.
+ .B tuntap
+ - manage TUN/TAP devices.
+ 
++.TP
++.B vrf
++- manage virtual routing and forwarding devices.
++
+ .TP
+ .B xfrm
+ - manage IPSec policies.
+@@ -411,6 +415,7 @@ was written by Alexey N. Kuznetsov and added in Linux 2.2.
+ .BR ip-tcp_metrics (8),
+ .BR ip-token (8),
+ .BR ip-tunnel (8),
++.BR ip-vrf (8),
+ .BR ip-xfrm (8)
+ .br
+ .RB "IP Command reference " ip-cref.ps
+-- 
+2.25.4
+
diff --git a/SOURCES/0009-nstat-print-useful-error-messages-in-abort-cases.patch b/SOURCES/0009-nstat-print-useful-error-messages-in-abort-cases.patch
new file mode 100644
index 0000000..8e439d5
--- /dev/null
+++ b/SOURCES/0009-nstat-print-useful-error-messages-in-abort-cases.patch
@@ -0,0 +1,122 @@
+From 5723280683d940b33647b8dc92a3aa3b1a9a5466 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 30 Apr 2020 12:20:17 +0200
+Subject: [PATCH] nstat: print useful error messages in abort() cases
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1824896
+Upstream Status: iproute2.git commit 2c7056ac26412
+
+commit 2c7056ac26412fe99443a283f0c1261cb81ccea2
+Author: Andrea Claudi <aclaudi@redhat.com>
+Date:   Mon Feb 17 14:46:18 2020 +0100
+
+    nstat: print useful error messages in abort() cases
+
+    When nstat temporary file is corrupted or in some other corner cases,
+    nstat use abort() to stop its execution. This can puzzle some users,
+    wondering what is the reason for the crash.
+
+    This commit replaces abort() with some meaningful error messages and exit()
+
+    Reported-by: Renaud Métrich <rmetrich@redhat.com>
+    Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
+    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+---
+ misc/nstat.c | 47 +++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 33 insertions(+), 14 deletions(-)
+
+diff --git a/misc/nstat.c b/misc/nstat.c
+index 23113b223b22d..425e75ef461ec 100644
+--- a/misc/nstat.c
++++ b/misc/nstat.c
+@@ -142,14 +142,19 @@ static void load_good_table(FILE *fp)
+ 		}
+ 		/* idbuf is as big as buf, so this is safe */
+ 		nr = sscanf(buf, "%s%llu%lg", idbuf, &val, &rate);
+-		if (nr < 2)
+-			abort();
++		if (nr < 2) {
++			fprintf(stderr, "%s:%d: error parsing history file\n",
++				__FILE__, __LINE__);
++			exit(-2);
++		}
+ 		if (nr < 3)
+ 			rate = 0;
+ 		if (useless_number(idbuf))
+ 			continue;
+-		if ((n = malloc(sizeof(*n))) == NULL)
+-			abort();
++		if ((n = malloc(sizeof(*n))) == NULL) {
++			perror("nstat: malloc");
++			exit(-1);
++		}
+ 		n->id = strdup(idbuf);
+ 		n->val = val;
+ 		n->rate = rate;
+@@ -190,8 +195,11 @@ static void load_ugly_table(FILE *fp)
+ 		int count1, count2, skip = 0;
+ 
+ 		p = strchr(buf, ':');
+-		if (!p)
+-			abort();
++		if (!p) {
++			fprintf(stderr, "%s:%d: error parsing history file\n",
++				__FILE__, __LINE__);
++			exit(-2);
++		}
+ 		count1 = count_spaces(buf);
+ 		*p = 0;
+ 		idbuf[0] = 0;
+@@ -211,8 +219,10 @@ static void load_ugly_table(FILE *fp)
+ 				strncat(idbuf, p, sizeof(idbuf) - off - 1);
+ 			}
+ 			n = malloc(sizeof(*n));
+-			if (!n)
+-				abort();
++			if (!n) {
++				perror("nstat: malloc");
++				exit(-1);
++			}
+ 			n->id = strdup(idbuf);
+ 			n->rate = 0;
+ 			n->next = db;
+@@ -221,18 +231,27 @@ static void load_ugly_table(FILE *fp)
+ 		}
+ 		n = db;
+ 		nread = getline(&buf, &buflen, fp);
+-		if (nread == -1)
+-			abort();
++		if (nread == -1) {
++			fprintf(stderr, "%s:%d: error parsing history file\n",
++				__FILE__, __LINE__);
++			exit(-2);
++		}
+ 		count2 = count_spaces(buf);
+ 		if (count2 > count1)
+ 			skip = count2 - count1;
+ 		do {
+ 			p = strrchr(buf, ' ');
+-			if (!p)
+-				abort();
++			if (!p) {
++				fprintf(stderr, "%s:%d: error parsing history file\n",
++					__FILE__, __LINE__);
++				exit(-2);
++			}
+ 			*p = 0;
+-			if (sscanf(p+1, "%llu", &n->val) != 1)
+-				abort();
++			if (sscanf(p+1, "%llu", &n->val) != 1) {
++				fprintf(stderr, "%s:%d: error parsing history file\n",
++					__FILE__, __LINE__);
++				exit(-2);
++			}
+ 			/* Trick to skip "dummy" trailing ICMP MIB in 2.4 */
+ 			if (skip)
+ 				skip--;
+-- 
+2.25.4
+
diff --git a/SOURCES/0010-ip-link-xstats-fix-TX-IGMP-reports-string.patch b/SOURCES/0010-ip-link-xstats-fix-TX-IGMP-reports-string.patch
new file mode 100644
index 0000000..0ab0707
--- /dev/null
+++ b/SOURCES/0010-ip-link-xstats-fix-TX-IGMP-reports-string.patch
@@ -0,0 +1,40 @@
+From 28a6ef808bd5c196c2259f7841a97c1ba703479d Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 30 Apr 2020 12:32:41 +0200
+Subject: [PATCH] ip link: xstats: fix TX IGMP reports string
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1796041
+Upstream Status: iproute2.git commit 5cdeb77cd6ec2
+
+commit 5cdeb77cd6ec26f0a7103dfb21494a6a43903206
+Author: Andrea Claudi <aclaudi@redhat.com>
+Date:   Wed Jan 29 15:31:11 2020 +0100
+
+    ip link: xstats: fix TX IGMP reports string
+
+    This restore the string format we have before jsonification, adding a
+    missing space between v2 and v3 on TX IGMP reports string.
+
+    Fixes: a9bc23a79227a ("ip: bridge: add xstats json support")
+    Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
+    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+---
+ ip/iplink_bridge.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c
+index 06f736d4dc710..868ea6e266ebe 100644
+--- a/ip/iplink_bridge.c
++++ b/ip/iplink_bridge.c
+@@ -742,7 +742,7 @@ static void bridge_print_stats_attr(struct rtattr *attr, int ifindex)
+ 			print_string(PRINT_FP, NULL, "%-16s      ", "");
+ 			print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
+ 				  mstats->igmp_v1reports[BR_MCAST_DIR_TX]);
+-			print_u64(PRINT_ANY, "tx_v2", "v2 %llu",
++			print_u64(PRINT_ANY, "tx_v2", "v2 %llu ",
+ 				  mstats->igmp_v2reports[BR_MCAST_DIR_TX]);
+ 			print_u64(PRINT_ANY, "tx_v3", "v3 %llu\n",
+ 				  mstats->igmp_v3reports[BR_MCAST_DIR_TX]);
+-- 
+2.25.4
+
diff --git a/SOURCES/0011-ip-fix-ip-route-show-json-output-for-multipath-nexth.patch b/SOURCES/0011-ip-fix-ip-route-show-json-output-for-multipath-nexth.patch
new file mode 100644
index 0000000..c82b769
--- /dev/null
+++ b/SOURCES/0011-ip-fix-ip-route-show-json-output-for-multipath-nexth.patch
@@ -0,0 +1,148 @@
+From 65d5e933e5162c3464857ee233a2f20e778ee1b6 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 30 Apr 2020 12:35:47 +0200
+Subject: [PATCH] ip: fix ip route show json output for multipath nexthops
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1738633
+Upstream Status: iproute2.git commit 4ecefff3cf250
+
+commit 4ecefff3cf250c1e4499dff14c80ed38bec6d7de
+Author: Julien Fortin <julien@cumulusnetworks.com>
+Date:   Thu Sep 26 17:29:34 2019 +0200
+
+    ip: fix ip route show json output for multipath nexthops
+
+    print_rta_multipath doesn't support JSON output:
+
+    {
+        "dst":"27.0.0.13",
+        "protocol":"bgp",
+        "metric":20,
+        "flags":[],
+        "gateway":"169.254.0.1"dev uplink-1 weight 1 ,
+        "flags":["onlink"],
+        "gateway":"169.254.0.1"dev uplink-2 weight 1 ,
+        "flags":["onlink"]
+    },
+
+    since RTA_MULTIPATH has nested objects we should print them
+    in a json array.
+
+    With the path we have the following output:
+
+    {
+        "flags": [],
+        "dst": "36.0.0.13",
+        "protocol": "bgp",
+        "metric": 20,
+        "nexthops": [
+            {
+                "weight": 1,
+                "flags": [
+                    "onlink"
+                ],
+                "gateway": "169.254.0.1",
+                "dev": "uplink-1"
+            },
+            {
+                "weight": 1,
+                "flags": [
+                    "onlink"
+                ],
+                "gateway": "169.254.0.1",
+                "dev": "uplink-2"
+            }
+        ]
+    }
+
+    Fixes: 663c3cb23103f4 ("iproute: implement JSON and color output")
+
+    Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ ip/iproute.c | 46 ++++++++++++++++++++++++++++------------------
+ 1 file changed, 28 insertions(+), 18 deletions(-)
+
+diff --git a/ip/iproute.c b/ip/iproute.c
+index a453385113cb9..32bb52df250c2 100644
+--- a/ip/iproute.c
++++ b/ip/iproute.c
+@@ -649,24 +649,26 @@ static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
+ 	int len = RTA_PAYLOAD(rta);
+ 	int first = 1;
+ 
++	open_json_array(PRINT_JSON, "nexthops");
++
+ 	while (len >= sizeof(*nh)) {
+ 		struct rtattr *tb[RTA_MAX + 1];
+ 
+ 		if (nh->rtnh_len > len)
+ 			break;
+ 
+-		if (!is_json_context()) {
+-			if ((r->rtm_flags & RTM_F_CLONED) &&
+-			    r->rtm_type == RTN_MULTICAST) {
+-				if (first) {
+-					fprintf(fp, "Oifs: ");
+-					first = 0;
+-				} else {
+-					fprintf(fp, " ");
+-				}
+-			} else
+-				fprintf(fp, "%s\tnexthop ", _SL_);
+-		}
++		open_json_object(NULL);
++
++		if ((r->rtm_flags & RTM_F_CLONED) &&
++		    r->rtm_type == RTN_MULTICAST) {
++			if (first) {
++				print_string(PRINT_FP, NULL, "Oifs: ", NULL);
++				first = 0;
++			} else {
++				print_string(PRINT_FP, NULL, " ", NULL);
++			}
++		} else
++			print_string(PRINT_FP, NULL, "%s\tnexthop ", _SL_);
+ 
+ 		if (nh->rtnh_len > sizeof(*nh)) {
+ 			parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh),
+@@ -689,22 +691,30 @@ static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
+ 
+ 		if ((r->rtm_flags & RTM_F_CLONED) &&
+ 		    r->rtm_type == RTN_MULTICAST) {
+-			fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
++			print_string(PRINT_ANY, "dev",
++				     "%s", ll_index_to_name(nh->rtnh_ifindex));
++
+ 			if (nh->rtnh_hops != 1)
+-				fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
+-			fprintf(fp, " ");
++				print_int(PRINT_ANY, "ttl", "(ttl>%d)", nh->rtnh_hops);
++
++			print_string(PRINT_FP, NULL, " ", NULL);
+ 		} else {
+-			fprintf(fp, "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
++			print_string(PRINT_ANY, "dev",
++				     "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
++
+ 			if (r->rtm_family != AF_MPLS)
+-				fprintf(fp, "weight %d ",
+-					nh->rtnh_hops+1);
++				print_int(PRINT_ANY, "weight",
++					  "weight %d ", nh->rtnh_hops + 1);
+ 		}
+ 
+ 		print_rt_flags(fp, nh->rtnh_flags);
+ 
+ 		len -= NLMSG_ALIGN(nh->rtnh_len);
+ 		nh = RTNH_NEXT(nh);
++
++		close_json_object();
+ 	}
++	close_json_array(PRINT_JSON, NULL);
+ }
+ 
+ int print_route(struct nlmsghdr *n, void *arg)
+-- 
+2.25.4
+
diff --git a/SOURCES/0012-man-bridge.8-fix-bridge-link-show-description.patch b/SOURCES/0012-man-bridge.8-fix-bridge-link-show-description.patch
new file mode 100644
index 0000000..7e0c378
--- /dev/null
+++ b/SOURCES/0012-man-bridge.8-fix-bridge-link-show-description.patch
@@ -0,0 +1,48 @@
+From 12bf930c542feeb9578d9320bc39a34365747127 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 30 Apr 2020 12:43:30 +0200
+Subject: [PATCH] man: bridge.8: fix bridge link show description
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1817571
+Upstream Status: iproute2.git commit 0641bed8a3c77
+
+commit 0641bed8a3c779c37746c4d7be9e01a35e920841
+Author: Andrea Claudi <aclaudi@redhat.com>
+Date:   Fri Mar 27 11:45:12 2020 +0100
+
+    man: bridge.8: fix bridge link show description
+
+    When multiple bridges are present, 'bridge link show' diplays ports
+    for all bridges. Make this clear in the command description, and
+    point out the user to the ip command to display ports for a specific
+    bridge.
+
+    Reported-by: Marc Muehlfeld <mmuehlfe@redhat.com>
+    Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
+    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+---
+ man/man8/bridge.8 | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
+index bb4fb521f8e57..d750e54a17b8b 100644
+--- a/man/man8/bridge.8
++++ b/man/man8/bridge.8
+@@ -409,9 +409,12 @@ link setting is configured on the software bridge (default)
+ .BR "\-t" , " \-timestamp"
+ display current time when using monitor option.
+ 
+-.SS bridge link show - list bridge port configuration.
++.SS bridge link show - list ports configuration for all bridges.
+ 
+-This command displays the current bridge port configuration and flags.
++This command displays port configuration and flags for all bridges.
++
++To display port configuration and flags for a specific bridge, use the
++"ip link show master <bridge_device>" command.
+ 
+ .SH bridge fdb - forwarding database management
+ 
+-- 
+2.25.4
+
diff --git a/SOURCES/0013-xfrm-also-check-for-ipv6-state-in-xfrm_state_keep.patch b/SOURCES/0013-xfrm-also-check-for-ipv6-state-in-xfrm_state_keep.patch
new file mode 100644
index 0000000..8d5b4b4
--- /dev/null
+++ b/SOURCES/0013-xfrm-also-check-for-ipv6-state-in-xfrm_state_keep.patch
@@ -0,0 +1,53 @@
+From 40dda2fc9fb2597996e443117df18995c58444a9 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 30 Apr 2020 12:46:30 +0200
+Subject: [PATCH] xfrm: also check for ipv6 state in xfrm_state_keep
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1828033
+Upstream Status: iproute2.git commit d27fc6390ce32
+
+commit d27fc6390ce32ecdba6324e22b1c341791c5c63f
+Author: Xin Long <lucien.xin@gmail.com>
+Date:   Mon Apr 27 15:14:24 2020 +0800
+
+    xfrm: also check for ipv6 state in xfrm_state_keep
+
+    As commit f9d696cf414c ("xfrm: not try to delete ipcomp states when using
+    deleteall") does, this patch is to fix the same issue for ip6 state where
+    xsinfo->id.proto == IPPROTO_IPV6.
+
+      # ip xfrm state add src 2000::1 dst 2000::2 spi 0x1000 \
+        proto comp comp deflate mode tunnel sel src 2000::1 dst \
+        2000::2 proto gre
+      # ip xfrm sta deleteall
+      Failed to send delete-all request
+      : Operation not permitted
+
+    Note that the xsinfo->proto in common states can never be IPPROTO_IPV6.
+
+    Fixes: f9d696cf414c ("xfrm: not try to delete ipcomp states when using deleteall")
+    Reported-by: Xiumei Mu <xmu@redhat.com>
+    Signed-off-by: Xin Long <lucien.xin@gmail.com>
+    Acked-by: Andrea Claudi <aclaudi@redhat.com>
+    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+---
+ ip/xfrm_state.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
+index d014444e9af4f..44f08ceed24dd 100644
+--- a/ip/xfrm_state.c
++++ b/ip/xfrm_state.c
+@@ -1131,7 +1131,8 @@ static int xfrm_state_keep(struct nlmsghdr *n, void *arg)
+ 	if (!xfrm_state_filter_match(xsinfo))
+ 		return 0;
+ 
+-	if (xsinfo->id.proto == IPPROTO_IPIP)
++	if (xsinfo->id.proto == IPPROTO_IPIP ||
++	    xsinfo->id.proto == IPPROTO_IPV6)
+ 		return 0;
+ 
+ 	if (xb->offset > xb->size) {
+-- 
+2.25.4
+
diff --git a/SOURCES/0014-Update-kernel-headers-and-import-udp.h.patch b/SOURCES/0014-Update-kernel-headers-and-import-udp.h.patch
new file mode 100644
index 0000000..cef917b
--- /dev/null
+++ b/SOURCES/0014-Update-kernel-headers-and-import-udp.h.patch
@@ -0,0 +1,115 @@
+From 90897540c719814eca34ce6b5b78b3bb76c4a43a Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Fri, 5 Jun 2020 15:42:49 +0200
+Subject: [PATCH] Update kernel headers and import udp.h
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1844045
+Upstream Status: iproute2.git commit 4df5ad933ca8c
+
+commit 4df5ad933ca8cebf23a4868061b28ab869e9b77a
+Author: David Ahern <dsahern@gmail.com>
+Date:   Wed Jan 22 03:40:26 2020 +0000
+
+    Update kernel headers and import udp.h
+
+    Update kernel headers to commit:
+        4f2c17e0f332 ("Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next")
+
+    and import udp.h for the next patch.
+
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ include/uapi/linux/hdlc/ioctl.h |  9 +++++++
+ include/uapi/linux/if.h         |  1 +
+ include/uapi/linux/udp.h        | 47 +++++++++++++++++++++++++++++++++
+ 3 files changed, 57 insertions(+)
+ create mode 100644 include/uapi/linux/udp.h
+
+diff --git a/include/uapi/linux/hdlc/ioctl.h b/include/uapi/linux/hdlc/ioctl.h
+index 0fe4238e82462..b06341acab5ec 100644
+--- a/include/uapi/linux/hdlc/ioctl.h
++++ b/include/uapi/linux/hdlc/ioctl.h
+@@ -79,6 +79,15 @@ typedef struct {
+     unsigned int timeout;
+ } cisco_proto;
+ 
++typedef struct {
++	unsigned short dce; /* 1 for DCE (network side) operation */
++	unsigned int modulo; /* modulo (8 = basic / 128 = extended) */
++	unsigned int window; /* frame window size */
++	unsigned int t1; /* timeout t1 */
++	unsigned int t2; /* timeout t2 */
++	unsigned int n2; /* frame retry counter */
++} x25_hdlc_proto;
++
+ /* PPP doesn't need any info now - supply length = 0 to ioctl */
+ 
+ #endif /* __ASSEMBLY__ */
+diff --git a/include/uapi/linux/if.h b/include/uapi/linux/if.h
+index 495cdd2324428..626da393123b6 100644
+--- a/include/uapi/linux/if.h
++++ b/include/uapi/linux/if.h
+@@ -210,6 +210,7 @@ struct if_settings {
+ 		fr_proto		*fr;
+ 		fr_proto_pvc		*fr_pvc;
+ 		fr_proto_pvc_info	*fr_pvc_info;
++		x25_hdlc_proto		*x25;
+ 
+ 		/* interface settings */
+ 		sync_serial_settings	*sync;
+diff --git a/include/uapi/linux/udp.h b/include/uapi/linux/udp.h
+new file mode 100644
+index 0000000000000..d0a7223a0119c
+--- /dev/null
++++ b/include/uapi/linux/udp.h
+@@ -0,0 +1,47 @@
++/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
++/*
++ * INET		An implementation of the TCP/IP protocol suite for the LINUX
++ *		operating system.  INET is implemented using the  BSD Socket
++ *		interface as the means of communication with the user level.
++ *
++ *		Definitions for the UDP protocol.
++ *
++ * Version:	@(#)udp.h	1.0.2	04/28/93
++ *
++ * Author:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
++ *
++ *		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.
++ */
++#ifndef _LINUX_UDP_H
++#define _LINUX_UDP_H
++
++#include <linux/types.h>
++
++struct udphdr {
++	__be16	source;
++	__be16	dest;
++	__be16	len;
++	__sum16	check;
++};
++
++/* UDP socket options */
++#define UDP_CORK	1	/* Never send partially complete segments */
++#define UDP_ENCAP	100	/* Set the socket to accept encapsulated packets */
++#define UDP_NO_CHECK6_TX 101	/* Disable sending checksum for UDP6X */
++#define UDP_NO_CHECK6_RX 102	/* Disable accpeting checksum for UDP6 */
++#define UDP_SEGMENT	103	/* Set GSO segmentation size */
++#define UDP_GRO		104	/* This socket can receive UDP GRO packets */
++
++/* UDP encapsulation types */
++#define UDP_ENCAP_ESPINUDP_NON_IKE	1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
++#define UDP_ENCAP_ESPINUDP	2 /* draft-ietf-ipsec-udp-encaps-06 */
++#define UDP_ENCAP_L2TPINUDP	3 /* rfc2661 */
++#define UDP_ENCAP_GTP0		4 /* GSM TS 09.60 */
++#define UDP_ENCAP_GTP1U		5 /* 3GPP TS 29.060 */
++#define UDP_ENCAP_RXRPC		6
++#define TCP_ENCAP_ESPINTCP	7 /* Yikes, this is really xfrm encap types. */
++
++#endif /* _LINUX_UDP_H */
+-- 
+2.26.2
+
diff --git a/SOURCES/0015-ip-xfrm-add-espintcp-encapsulation.patch b/SOURCES/0015-ip-xfrm-add-espintcp-encapsulation.patch
new file mode 100644
index 0000000..d19a729
--- /dev/null
+++ b/SOURCES/0015-ip-xfrm-add-espintcp-encapsulation.patch
@@ -0,0 +1,110 @@
+From b0312111114ed805f84b1e96d73f468e3a372025 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Fri, 5 Jun 2020 15:42:49 +0200
+Subject: [PATCH] ip: xfrm: add espintcp encapsulation
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1844045
+Upstream Status: iproute2.git commit 22aec42679d57
+
+commit 22aec42679d57b8e0aef864c4d45feadb727c3ce
+Author: Sabrina Dubroca <sd@queasysnail.net>
+Date:   Sun Jan 19 11:32:09 2020 +0100
+
+    ip: xfrm: add espintcp encapsulation
+
+    While at it, convert xfrm_xfrma_print and xfrm_encap_type_parse to use
+    the UAPI macros for encap_type as suggested by David Ahern, and add the
+    UAPI udp.h header (sync'd from ipsec-next to get the TCP_ENCAP_ESPINTCP
+    definition).
+
+    Co-developed-by: Herbert Xu <herbert@gondor.apana.org.au>
+    Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ ip/ipxfrm.c        | 14 ++++++++++----
+ ip/xfrm_state.c    |  2 +-
+ man/man8/ip-xfrm.8 |  4 ++--
+ 3 files changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c
+index 32f560933a477..fec206abc1f03 100644
+--- a/ip/ipxfrm.c
++++ b/ip/ipxfrm.c
+@@ -34,6 +34,7 @@
+ #include <netdb.h>
+ #include <linux/netlink.h>
+ #include <linux/rtnetlink.h>
++#include <linux/udp.h>
+ 
+ #include "utils.h"
+ #include "xfrm.h"
+@@ -753,12 +754,15 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family,
+ 
+ 		fprintf(fp, "type ");
+ 		switch (e->encap_type) {
+-		case 1:
++		case UDP_ENCAP_ESPINUDP_NON_IKE:
+ 			fprintf(fp, "espinudp-nonike ");
+ 			break;
+-		case 2:
++		case UDP_ENCAP_ESPINUDP:
+ 			fprintf(fp, "espinudp ");
+ 			break;
++		case TCP_ENCAP_ESPINTCP:
++			fprintf(fp, "espintcp ");
++			break;
+ 		default:
+ 			fprintf(fp, "%u ", e->encap_type);
+ 			break;
+@@ -1208,9 +1212,11 @@ int xfrm_encap_type_parse(__u16 *type, int *argcp, char ***argvp)
+ 	char **argv = *argvp;
+ 
+ 	if (strcmp(*argv, "espinudp-nonike") == 0)
+-		*type = 1;
++		*type = UDP_ENCAP_ESPINUDP_NON_IKE;
+ 	else if (strcmp(*argv, "espinudp") == 0)
+-		*type = 2;
++		*type = UDP_ENCAP_ESPINUDP;
++	else if (strcmp(*argv, "espintcp") == 0)
++		*type = TCP_ENCAP_ESPINTCP;
+ 	else
+ 		invarg("ENCAP-TYPE value is invalid", *argv);
+ 
+diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
+index 44f08ceed24dd..f4bf3356bb01f 100644
+--- a/ip/xfrm_state.c
++++ b/ip/xfrm_state.c
+@@ -112,7 +112,7 @@ static void usage(void)
+ 		"LIMIT-LIST := [ LIMIT-LIST ] limit LIMIT\n"
+ 		"LIMIT := { time-soft | time-hard | time-use-soft | time-use-hard } SECONDS |\n"
+ 		"         { byte-soft | byte-hard } SIZE | { packet-soft | packet-hard } COUNT\n"
+-		"ENCAP := { espinudp | espinudp-nonike } SPORT DPORT OADDR\n"
++		"ENCAP := { espinudp | espinudp-nonike | espintcp } SPORT DPORT OADDR\n"
+ 		"DIR := in | out\n");
+ 
+ 	exit(-1);
+diff --git a/man/man8/ip-xfrm.8 b/man/man8/ip-xfrm.8
+index cfce1e40b7f7d..f99f30bb448a6 100644
+--- a/man/man8/ip-xfrm.8
++++ b/man/man8/ip-xfrm.8
+@@ -207,7 +207,7 @@ ip-xfrm \- transform configuration
+ 
+ .ti -8
+ .IR ENCAP " :="
+-.RB "{ " espinudp " | " espinudp-nonike " }"
++.RB "{ " espinudp " | " espinudp-nonike " | " espintcp " }"
+ .IR SPORT " " DPORT " " OADDR
+ 
+ .ti -8
+@@ -548,7 +548,7 @@ sets limits in seconds, bytes, or numbers of packets.
+ .TP
+ .I ENCAP
+ encapsulates packets with protocol
+-.BR espinudp " or " espinudp-nonike ","
++.BR espinudp ", " espinudp-nonike ", or " espintcp ","
+ .RI "using source port " SPORT ", destination port "  DPORT
+ .RI ", and original address " OADDR "."
+ 
+-- 
+2.26.2
+
diff --git a/SOURCES/0016-Update-kernel-headers-and-import-mptcp.h.patch b/SOURCES/0016-Update-kernel-headers-and-import-mptcp.h.patch
new file mode 100644
index 0000000..2d709bd
--- /dev/null
+++ b/SOURCES/0016-Update-kernel-headers-and-import-mptcp.h.patch
@@ -0,0 +1,177 @@
+From 93f77d1e57c84093b91bc9227929cfb4a24534e9 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 19:25:47 +0200
+Subject: [PATCH] Update kernel headers and import mptcp.h
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1812207
+Upstream Status: iproute2.git commit 02ade5a8ea1c2
+Conflicts: on bpf uapi due to missing commit b5a77cf70116f ("uapi: update bpf.h")
+           and on if_bridge uapi due to several unrelated missing changes.
+
+commit 02ade5a8ea1c23201a99d8cdf7e02a6ba90d7718
+Author: David Ahern <dsahern@gmail.com>
+Date:   Wed Apr 29 16:41:39 2020 +0000
+
+    Update kernel headers and import mptcp.h
+
+    Update kernel headers to commit
+        790ab249b55d ("net: ethernet: fec: Prevent MII event after MII_SPEED write")
+
+    and import mptcp.h
+
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ include/uapi/linux/if.h        |  1 +
+ include/uapi/linux/if_bridge.h |  1 +
+ include/uapi/linux/if_ether.h  |  1 +
+ include/uapi/linux/if_link.h   |  1 +
+ include/uapi/linux/mptcp.h     | 89 ++++++++++++++++++++++++++++++++++
+ 5 files changed, 93 insertions(+)
+ create mode 100644 include/uapi/linux/mptcp.h
+
+diff --git a/include/uapi/linux/if.h b/include/uapi/linux/if.h
+index 626da393123b6..9a3bc23d0235e 100644
+--- a/include/uapi/linux/if.h
++++ b/include/uapi/linux/if.h
+@@ -175,6 +175,7 @@ enum {
+ enum {
+ 	IF_LINK_MODE_DEFAULT,
+ 	IF_LINK_MODE_DORMANT,	/* limit upward transition to dormant */
++	IF_LINK_MODE_TESTING,	/* limit upward transition to testing */
+ };
+ 
+ /*
+diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
+index 31fc51bdedb3c..53ba8385b022e 100644
+--- a/include/uapi/linux/if_bridge.h
++++ b/include/uapi/linux/if_bridge.h
+@@ -120,6 +120,7 @@ enum {
+ 	IFLA_BRIDGE_MODE,
+ 	IFLA_BRIDGE_VLAN_INFO,
+ 	IFLA_BRIDGE_VLAN_TUNNEL_INFO,
++	IFLA_BRIDGE_MRP,
+ 	__IFLA_BRIDGE_MAX,
+ };
+ #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
+diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
+index 728c42dfd59c1..1a0c7dfe8e38e 100644
+--- a/include/uapi/linux/if_ether.h
++++ b/include/uapi/linux/if_ether.h
+@@ -92,6 +92,7 @@
+ #define ETH_P_PREAUTH	0x88C7		/* 802.11 Preauthentication */
+ #define ETH_P_TIPC	0x88CA		/* TIPC 			*/
+ #define ETH_P_LLDP	0x88CC		/* Link Layer Discovery Protocol */
++#define ETH_P_MRP	0x88E3		/* Media Redundancy Protocol	*/
+ #define ETH_P_MACSEC	0x88E5		/* 802.1ae MACsec */
+ #define ETH_P_8021AH	0x88E7          /* 802.1ah Backbone Service Tag */
+ #define ETH_P_MVRP	0x88F5          /* 802.1Q MVRP                  */
+diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
+index d36919fb4024a..4da0768d7a5a3 100644
+--- a/include/uapi/linux/if_link.h
++++ b/include/uapi/linux/if_link.h
+@@ -338,6 +338,7 @@ enum {
+ 	IFLA_BRPORT_NEIGH_SUPPRESS,
+ 	IFLA_BRPORT_ISOLATED,
+ 	IFLA_BRPORT_BACKUP_PORT,
++	IFLA_BRPORT_MRP_RING_OPEN,
+ 	__IFLA_BRPORT_MAX
+ };
+ #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
+diff --git a/include/uapi/linux/mptcp.h b/include/uapi/linux/mptcp.h
+new file mode 100644
+index 0000000000000..009b8f0b0e8be
+--- /dev/null
++++ b/include/uapi/linux/mptcp.h
+@@ -0,0 +1,89 @@
++/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
++#ifndef _MPTCP_H
++#define _MPTCP_H
++
++#include <linux/const.h>
++#include <linux/types.h>
++
++#define MPTCP_SUBFLOW_FLAG_MCAP_REM		_BITUL(0)
++#define MPTCP_SUBFLOW_FLAG_MCAP_LOC		_BITUL(1)
++#define MPTCP_SUBFLOW_FLAG_JOIN_REM		_BITUL(2)
++#define MPTCP_SUBFLOW_FLAG_JOIN_LOC		_BITUL(3)
++#define MPTCP_SUBFLOW_FLAG_BKUP_REM		_BITUL(4)
++#define MPTCP_SUBFLOW_FLAG_BKUP_LOC		_BITUL(5)
++#define MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED	_BITUL(6)
++#define MPTCP_SUBFLOW_FLAG_CONNECTED		_BITUL(7)
++#define MPTCP_SUBFLOW_FLAG_MAPVALID		_BITUL(8)
++
++enum {
++	MPTCP_SUBFLOW_ATTR_UNSPEC,
++	MPTCP_SUBFLOW_ATTR_TOKEN_REM,
++	MPTCP_SUBFLOW_ATTR_TOKEN_LOC,
++	MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ,
++	MPTCP_SUBFLOW_ATTR_MAP_SEQ,
++	MPTCP_SUBFLOW_ATTR_MAP_SFSEQ,
++	MPTCP_SUBFLOW_ATTR_SSN_OFFSET,
++	MPTCP_SUBFLOW_ATTR_MAP_DATALEN,
++	MPTCP_SUBFLOW_ATTR_FLAGS,
++	MPTCP_SUBFLOW_ATTR_ID_REM,
++	MPTCP_SUBFLOW_ATTR_ID_LOC,
++	MPTCP_SUBFLOW_ATTR_PAD,
++	__MPTCP_SUBFLOW_ATTR_MAX
++};
++
++#define MPTCP_SUBFLOW_ATTR_MAX (__MPTCP_SUBFLOW_ATTR_MAX - 1)
++
++/* netlink interface */
++#define MPTCP_PM_NAME		"mptcp_pm"
++#define MPTCP_PM_CMD_GRP_NAME	"mptcp_pm_cmds"
++#define MPTCP_PM_VER		0x1
++
++/*
++ * ATTR types defined for MPTCP
++ */
++enum {
++	MPTCP_PM_ATTR_UNSPEC,
++
++	MPTCP_PM_ATTR_ADDR,				/* nested address */
++	MPTCP_PM_ATTR_RCV_ADD_ADDRS,			/* u32 */
++	MPTCP_PM_ATTR_SUBFLOWS,				/* u32 */
++
++	__MPTCP_PM_ATTR_MAX
++};
++
++#define MPTCP_PM_ATTR_MAX (__MPTCP_PM_ATTR_MAX - 1)
++
++enum {
++	MPTCP_PM_ADDR_ATTR_UNSPEC,
++
++	MPTCP_PM_ADDR_ATTR_FAMILY,			/* u16 */
++	MPTCP_PM_ADDR_ATTR_ID,				/* u8 */
++	MPTCP_PM_ADDR_ATTR_ADDR4,			/* struct in_addr */
++	MPTCP_PM_ADDR_ATTR_ADDR6,			/* struct in6_addr */
++	MPTCP_PM_ADDR_ATTR_PORT,			/* u16 */
++	MPTCP_PM_ADDR_ATTR_FLAGS,			/* u32 */
++	MPTCP_PM_ADDR_ATTR_IF_IDX,			/* s32 */
++
++	__MPTCP_PM_ADDR_ATTR_MAX
++};
++
++#define MPTCP_PM_ADDR_ATTR_MAX (__MPTCP_PM_ADDR_ATTR_MAX - 1)
++
++#define MPTCP_PM_ADDR_FLAG_SIGNAL			(1 << 0)
++#define MPTCP_PM_ADDR_FLAG_SUBFLOW			(1 << 1)
++#define MPTCP_PM_ADDR_FLAG_BACKUP			(1 << 2)
++
++enum {
++	MPTCP_PM_CMD_UNSPEC,
++
++	MPTCP_PM_CMD_ADD_ADDR,
++	MPTCP_PM_CMD_DEL_ADDR,
++	MPTCP_PM_CMD_GET_ADDR,
++	MPTCP_PM_CMD_FLUSH_ADDRS,
++	MPTCP_PM_CMD_SET_LIMITS,
++	MPTCP_PM_CMD_GET_LIMITS,
++
++	__MPTCP_PM_CMD_AFTER_LAST
++};
++
++#endif /* _MPTCP_H */
+-- 
+2.26.2
+
diff --git a/SOURCES/0017-add-support-for-mptcp-netlink-interface.patch b/SOURCES/0017-add-support-for-mptcp-netlink-interface.patch
new file mode 100644
index 0000000..47995fd
--- /dev/null
+++ b/SOURCES/0017-add-support-for-mptcp-netlink-interface.patch
@@ -0,0 +1,532 @@
+From 1f25184a76227f8a7a1e425434e6e0f0bd13457d Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 19:26:50 +0200
+Subject: [PATCH] add support for mptcp netlink interface
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1812207
+Upstream Status: unknown commit 7e0767cd862bb
+
+commit 7e0767cd862bb5dd2d41c41c5e6f55d633f953ea
+Author: Paolo Abeni <pabeni@redhat.com>
+Date:   Thu Apr 23 15:37:08 2020 +0200
+
+    add support for mptcp netlink interface
+
+    Implement basic commands to:
+    - manipulate MPTCP endpoints list
+    - manipulate MPTCP connection limits
+
+    Examples:
+    1. Allows multiple subflows per MPTCP connection
+       $ ip mptcp limits set subflows 2
+
+    2. Accept ADD_ADDR announcement from the peer (server):
+       $ ip mptcp limits set add_addr_accepted 2
+
+    3. Add a ipv4 address to be annunced for backup subflows:
+       $ ip mptcp endpoint add 10.99.1.2 signal backup
+
+    4. Add an ipv6 address used as source for additional subflows:
+       $ ip mptcp endpoint add 2001::2 subflow
+
+    Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ ip/Makefile    |   2 +-
+ ip/ip.c        |   3 +-
+ ip/ip_common.h |   1 +
+ ip/ipmptcp.c   | 436 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 440 insertions(+), 2 deletions(-)
+ create mode 100644 ip/ipmptcp.c
+
+diff --git a/ip/Makefile b/ip/Makefile
+index 5ab78d7d3b84e..8735b8e4706b3 100644
+--- a/ip/Makefile
++++ b/ip/Makefile
+@@ -11,7 +11,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
+     iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \
+     iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o \
+     ipvrf.o iplink_xstats.o ipseg6.o iplink_netdevsim.o iplink_rmnet.o \
+-    ipnexthop.o
++    ipnexthop.o ipmptcp.o
+ 
+ RTMONOBJ=rtmon.o
+ 
+diff --git a/ip/ip.c b/ip/ip.c
+index fed26f8d48279..8d62f4e312bdc 100644
+--- a/ip/ip.c
++++ b/ip/ip.c
+@@ -51,7 +51,7 @@ static void usage(void)
+ 		"where  OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |\n"
+ 		"                   tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |\n"
+ 		"                   netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |\n"
+-		"                   vrf | sr | nexthop }\n"
++		"                   vrf | sr | nexthop | mptcp }\n"
+ 		"       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
+ 		"                    -h[uman-readable] | -iec | -j[son] | -p[retty] |\n"
+ 		"                    -f[amily] { inet | inet6 | mpls | bridge | link } |\n"
+@@ -103,6 +103,7 @@ static const struct cmd {
+ 	{ "vrf",	do_ipvrf},
+ 	{ "sr",		do_seg6 },
+ 	{ "nexthop",	do_ipnh },
++	{ "mptcp",	do_mptcp },
+ 	{ "help",	do_help },
+ 	{ 0 }
+ };
+diff --git a/ip/ip_common.h b/ip/ip_common.h
+index cd916ec87c265..0dd4a53fc8333 100644
+--- a/ip/ip_common.h
++++ b/ip/ip_common.h
+@@ -82,6 +82,7 @@ void vrf_reset(void);
+ int netns_identify_pid(const char *pidstr, char *name, int len);
+ int do_seg6(int argc, char **argv);
+ int do_ipnh(int argc, char **argv);
++int do_mptcp(int argc, char **argv);
+ 
+ int iplink_get(char *name, __u32 filt_mask);
+ int iplink_ifla_xstats(int argc, char **argv);
+diff --git a/ip/ipmptcp.c b/ip/ipmptcp.c
+new file mode 100644
+index 0000000000000..bc12418bd39c6
+--- /dev/null
++++ b/ip/ipmptcp.c
+@@ -0,0 +1,436 @@
++// SPDX-License-Identifier: GPL-2.0
++
++#include <stdio.h>
++#include <string.h>
++#include <rt_names.h>
++#include <errno.h>
++
++#include <linux/genetlink.h>
++#include <linux/mptcp.h>
++
++#include "utils.h"
++#include "ip_common.h"
++#include "libgenl.h"
++#include "json_print.h"
++
++static void usage(void)
++{
++	fprintf(stderr,
++		"Usage:	ip mptcp endpoint add ADDRESS [ dev NAME ] [ id ID ]\n"
++		"				      [ FLAG-LIST ]\n"
++		"	ip mptcp endpoint delete id ID\n"
++		"	ip mptcp endpoint show [ id ID ]\n"
++		"	ip mptcp endpoint flush\n"
++		"	ip mptcp limits set [ subflows NR ] [ add_addr_accepted NR ]\n"
++		"	ip mptcp limits show\n"
++		"FLAG-LIST := [ FLAG-LIST ] FLAG\n"
++		"FLAG  := [ signal | subflow | backup ]\n");
++
++	exit(-1);
++}
++
++/* netlink socket */
++static struct rtnl_handle genl_rth = { .fd = -1 };
++static int genl_family = -1;
++
++#define MPTCP_BUFLEN	4096
++#define MPTCP_REQUEST(_req,  _cmd, _flags)	\
++	GENL_REQUEST(_req, MPTCP_BUFLEN, genl_family, 0,	\
++		     MPTCP_PM_VER, _cmd, _flags)
++
++/* Mapping from argument to address flag mask */
++static const struct {
++	const char *name;
++	unsigned long value;
++} mptcp_addr_flag_names[] = {
++	{ "signal",		MPTCP_PM_ADDR_FLAG_SIGNAL },
++	{ "subflow",		MPTCP_PM_ADDR_FLAG_SUBFLOW },
++	{ "backup",		MPTCP_PM_ADDR_FLAG_BACKUP },
++};
++
++static void print_mptcp_addr_flags(unsigned int flags)
++{
++	unsigned int i;
++
++	for (i = 0; i < ARRAY_SIZE(mptcp_addr_flag_names); i++) {
++		unsigned long mask = mptcp_addr_flag_names[i].value;
++
++		if (flags & mask) {
++			print_string(PRINT_FP, NULL, "%s ",
++				     mptcp_addr_flag_names[i].name);
++			print_bool(PRINT_JSON,
++				   mptcp_addr_flag_names[i].name, NULL, true);
++		}
++
++		flags &= ~mask;
++	}
++
++	if (flags) {
++		/* unknown flags */
++		SPRINT_BUF(b1);
++
++		snprintf(b1, sizeof(b1), "%02x", flags);
++		print_string(PRINT_ANY, "rawflags", "rawflags %s ", b1);
++	}
++}
++
++static int get_flags(const char *arg, __u32 *flags)
++{
++	unsigned int i;
++
++	for (i = 0; i < ARRAY_SIZE(mptcp_addr_flag_names); i++) {
++		if (strcmp(arg, mptcp_addr_flag_names[i].name))
++			continue;
++
++		*flags |= mptcp_addr_flag_names[i].value;
++		return 0;
++	}
++	return -1;
++}
++
++static int mptcp_parse_opt(int argc, char **argv, struct nlmsghdr *n,
++			 bool adding)
++{
++	struct rtattr *attr_addr;
++	bool addr_set = false;
++	inet_prefix address;
++	bool id_set = false;
++	__u32 index = 0;
++	__u32 flags = 0;
++	__u8 id = 0;
++
++	ll_init_map(&rth);
++	while (argc > 0) {
++		if (get_flags(*argv, &flags) == 0) {
++		} else if (matches(*argv, "id") == 0) {
++			NEXT_ARG();
++
++			if (get_u8(&id, *argv, 0))
++				invarg("invalid ID\n", *argv);
++			id_set = true;
++		} else if (matches(*argv, "dev") == 0) {
++			const char *ifname;
++
++			NEXT_ARG();
++
++			ifname = *argv;
++
++			if (check_ifname(ifname))
++				invarg("invalid interface name\n", ifname);
++
++			index = ll_name_to_index(ifname);
++
++			if (!index)
++				invarg("device does not exist\n", ifname);
++
++		} else if (get_addr(&address, *argv, AF_UNSPEC) == 0) {
++			addr_set = true;
++		} else {
++			invarg("unknown argument", *argv);
++		}
++		NEXT_ARG_FWD();
++	}
++
++	if (!addr_set && adding)
++		missarg("ADDRESS");
++
++	if (!id_set && !adding)
++		missarg("ID");
++
++	attr_addr = addattr_nest(n, MPTCP_BUFLEN,
++				 MPTCP_PM_ATTR_ADDR | NLA_F_NESTED);
++	if (id_set)
++		addattr8(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_ID, id);
++	if (flags)
++		addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_FLAGS, flags);
++	if (index)
++		addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_IF_IDX, index);
++	if (addr_set) {
++		int type;
++
++		addattr16(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_FAMILY,
++			  address.family);
++		type = address.family == AF_INET ? MPTCP_PM_ADDR_ATTR_ADDR4 :
++						   MPTCP_PM_ADDR_ATTR_ADDR6;
++		addattr_l(n, MPTCP_BUFLEN, type, &address.data,
++			  address.bytelen);
++	}
++
++	addattr_nest_end(n, attr_addr);
++	return 0;
++}
++
++static int mptcp_addr_modify(int argc, char **argv, int cmd)
++{
++	MPTCP_REQUEST(req, cmd, NLM_F_REQUEST);
++	int ret;
++
++	ret = mptcp_parse_opt(argc, argv, &req.n, cmd == MPTCP_PM_CMD_ADD_ADDR);
++	if (ret)
++		return ret;
++
++	if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
++		return -2;
++
++	return 0;
++}
++
++static int print_mptcp_addrinfo(struct rtattr *addrinfo)
++{
++	struct rtattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1];
++	__u8 family = AF_UNSPEC, addr_attr_type;
++	const char *ifname;
++	unsigned int flags;
++	int index;
++	__u16 id;
++
++	parse_rtattr_nested(tb, MPTCP_PM_ADDR_ATTR_MAX, addrinfo);
++
++	open_json_object(NULL);
++	if (tb[MPTCP_PM_ADDR_ATTR_FAMILY])
++		family = rta_getattr_u8(tb[MPTCP_PM_ADDR_ATTR_FAMILY]);
++
++	addr_attr_type = family == AF_INET ? MPTCP_PM_ADDR_ATTR_ADDR4 :
++					     MPTCP_PM_ADDR_ATTR_ADDR6;
++	if (tb[addr_attr_type]) {
++		print_string(PRINT_ANY, "address", "%s ",
++			     format_host_rta(family, tb[addr_attr_type]));
++	}
++	if (tb[MPTCP_PM_ADDR_ATTR_ID]) {
++		id = rta_getattr_u8(tb[MPTCP_PM_ADDR_ATTR_ID]);
++		print_uint(PRINT_ANY, "id", "id %u ", id);
++	}
++	if (tb[MPTCP_PM_ADDR_ATTR_FLAGS]) {
++		flags = rta_getattr_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]);
++		print_mptcp_addr_flags(flags);
++	}
++	if (tb[MPTCP_PM_ADDR_ATTR_IF_IDX]) {
++		index = rta_getattr_s32(tb[MPTCP_PM_ADDR_ATTR_IF_IDX]);
++		ifname = index ? ll_index_to_name(index) : NULL;
++
++		if (ifname)
++			print_string(PRINT_ANY, "dev", "dev %s ", ifname);
++	}
++
++	close_json_object();
++	print_string(PRINT_FP, NULL, "\n", NULL);
++	fflush(stdout);
++
++	return 0;
++}
++
++static int print_mptcp_addr(struct nlmsghdr *n, void *arg)
++{
++	struct rtattr *tb[MPTCP_PM_ATTR_MAX + 1];
++	struct genlmsghdr *ghdr;
++	struct rtattr *addrinfo;
++	int len = n->nlmsg_len;
++
++	if (n->nlmsg_type != genl_family)
++		return 0;
++
++	len -= NLMSG_LENGTH(GENL_HDRLEN);
++	if (len < 0)
++		return -1;
++
++	ghdr = NLMSG_DATA(n);
++	parse_rtattr_flags(tb, MPTCP_PM_ATTR_MAX, (void *) ghdr + GENL_HDRLEN,
++			   len, NLA_F_NESTED);
++	addrinfo = tb[MPTCP_PM_ATTR_ADDR];
++	if (!addrinfo)
++		return -1;
++
++	ll_init_map(&rth);
++	return print_mptcp_addrinfo(addrinfo);
++}
++
++static int mptcp_addr_dump(void)
++{
++	MPTCP_REQUEST(req, MPTCP_PM_CMD_GET_ADDR, NLM_F_REQUEST | NLM_F_DUMP);
++
++	if (rtnl_send(&genl_rth, &req.n, req.n.nlmsg_len) < 0) {
++		perror("Cannot send show request");
++		exit(1);
++	}
++
++	new_json_obj(json);
++
++	if (rtnl_dump_filter(&genl_rth, print_mptcp_addr, stdout) < 0) {
++		fprintf(stderr, "Dump terminated\n");
++		delete_json_obj();
++		fflush(stdout);
++		return -2;
++	}
++
++	close_json_object();
++	fflush(stdout);
++	return 0;
++}
++
++static int mptcp_addr_show(int argc, char **argv)
++{
++	MPTCP_REQUEST(req, MPTCP_PM_CMD_GET_ADDR, NLM_F_REQUEST);
++	struct nlmsghdr *answer;
++	int ret;
++
++	if (!argv)
++		return mptcp_addr_dump();
++
++	ret = mptcp_parse_opt(argc, argv, &req.n, false);
++	if (ret)
++		return ret;
++
++	if (rtnl_talk(&genl_rth, &req.n, &answer) < 0)
++		return -2;
++
++	return print_mptcp_addr(answer, stdout);
++}
++
++static int mptcp_addr_flush(int argc, char **argv)
++{
++	MPTCP_REQUEST(req, MPTCP_PM_CMD_FLUSH_ADDRS, NLM_F_REQUEST);
++
++	if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
++		return -2;
++
++	return 0;
++}
++
++static int mptcp_parse_limit(int argc, char **argv, struct nlmsghdr *n)
++{
++	bool set_rcv_add_addrs = false;
++	bool set_subflows = false;
++	__u32 rcv_add_addrs = 0;
++	__u32 subflows = 0;
++
++	while (argc > 0) {
++		if (matches(*argv, "subflows") == 0) {
++			NEXT_ARG();
++
++			if (get_u32(&subflows, *argv, 0))
++				invarg("invalid subflows\n", *argv);
++			set_subflows = true;
++		} else if (matches(*argv, "add_addr_accepted") == 0) {
++			NEXT_ARG();
++
++			if (get_u32(&rcv_add_addrs, *argv, 0))
++				invarg("invalid add_addr_accepted\n", *argv);
++			set_rcv_add_addrs = true;
++		} else {
++			invarg("unknown limit", *argv);
++		}
++		NEXT_ARG_FWD();
++	}
++
++	if (set_rcv_add_addrs)
++		addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ATTR_RCV_ADD_ADDRS,
++			  rcv_add_addrs);
++	if (set_subflows)
++		addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ATTR_SUBFLOWS, subflows);
++	return set_rcv_add_addrs || set_subflows;
++}
++
++static int print_mptcp_limit(struct nlmsghdr *n, void *arg)
++{
++	struct rtattr *tb[MPTCP_PM_ATTR_MAX + 1];
++	struct genlmsghdr *ghdr;
++	int len = n->nlmsg_len;
++	__u32 val;
++
++	if (n->nlmsg_type != genl_family)
++		return 0;
++
++	len -= NLMSG_LENGTH(GENL_HDRLEN);
++	if (len < 0)
++		return -1;
++
++	ghdr = NLMSG_DATA(n);
++	parse_rtattr(tb, MPTCP_PM_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
++
++	open_json_object(NULL);
++	if (tb[MPTCP_PM_ATTR_RCV_ADD_ADDRS]) {
++		val = rta_getattr_u32(tb[MPTCP_PM_ATTR_RCV_ADD_ADDRS]);
++
++		print_uint(PRINT_ANY, "add_addr_accepted",
++			   "add_addr_accepted %d ", val);
++	}
++
++	if (tb[MPTCP_PM_ATTR_SUBFLOWS]) {
++		val = rta_getattr_u32(tb[MPTCP_PM_ATTR_SUBFLOWS]);
++
++		print_uint(PRINT_ANY, "subflows", "subflows %d ", val);
++	}
++	print_string(PRINT_FP, NULL, "%s", "\n");
++	fflush(stdout);
++	close_json_object();
++	return 0;
++}
++
++static int mptcp_limit_get_set(int argc, char **argv, int cmd)
++{
++	bool do_get = cmd == MPTCP_PM_CMD_GET_LIMITS;
++	MPTCP_REQUEST(req, cmd, NLM_F_REQUEST);
++	struct nlmsghdr *answer;
++	int ret;
++
++	ret = mptcp_parse_limit(argc, argv, &req.n);
++	if (ret < 0)
++		return -1;
++
++	if (rtnl_talk(&genl_rth, &req.n, do_get ? &answer : NULL) < 0)
++		return -2;
++
++	if (do_get)
++		return print_mptcp_limit(answer, stdout);
++	return 0;
++}
++
++int do_mptcp(int argc, char **argv)
++{
++	if (argc == 0)
++		usage();
++
++	if (matches(*argv, "help") == 0)
++		usage();
++
++	if (genl_init_handle(&genl_rth, MPTCP_PM_NAME, &genl_family))
++		exit(1);
++
++	if (matches(*argv, "endpoint") == 0) {
++		NEXT_ARG_FWD();
++		if (argc == 0)
++			return mptcp_addr_show(0, NULL);
++
++		if (matches(*argv, "add") == 0)
++			return mptcp_addr_modify(argc-1, argv+1,
++						 MPTCP_PM_CMD_ADD_ADDR);
++		if (matches(*argv, "delete") == 0)
++			return mptcp_addr_modify(argc-1, argv+1,
++						 MPTCP_PM_CMD_DEL_ADDR);
++		if (matches(*argv, "show") == 0)
++			return mptcp_addr_show(argc-1, argv+1);
++		if (matches(*argv, "flush") == 0)
++			return mptcp_addr_flush(argc-1, argv+1);
++
++		goto unknown;
++	}
++
++	if (matches(*argv, "limits") == 0) {
++		NEXT_ARG_FWD();
++		if (argc == 0)
++			return mptcp_limit_get_set(0, NULL,
++						   MPTCP_PM_CMD_GET_LIMITS);
++
++		if (matches(*argv, "set") == 0)
++			return mptcp_limit_get_set(argc-1, argv+1,
++						   MPTCP_PM_CMD_SET_LIMITS);
++		if (matches(*argv, "show") == 0)
++			return mptcp_limit_get_set(argc-1, argv+1,
++						   MPTCP_PM_CMD_GET_LIMITS);
++	}
++
++unknown:
++	fprintf(stderr, "Command \"%s\" is unknown, try \"ip mptcp help\".\n",
++		*argv);
++	exit(-1);
++}
+-- 
+2.26.2
+
diff --git a/SOURCES/0018-Update-kernel-headers.patch b/SOURCES/0018-Update-kernel-headers.patch
new file mode 100644
index 0000000..9129be5
--- /dev/null
+++ b/SOURCES/0018-Update-kernel-headers.patch
@@ -0,0 +1,217 @@
+From 98f0c643a333ff630407828f4141131502edc6f9 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 19:26:50 +0200
+Subject: [PATCH] Update kernel headers
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1812207
+Upstream Status: unknown commit 3d72f125c300d
+
+commit 3d72f125c300dd261a5151cf1cac7cfa152376b2
+Author: David Ahern <dsahern@gmail.com>
+Date:   Sun Sep 15 10:32:58 2019 -0700
+
+    Update kernel headers
+
+    Update kernel headers to commit:
+        aa2eaa8c272a ("Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net")
+
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ include/uapi/linux/bpf.h       | 15 ++++++++++++---
+ include/uapi/linux/can.h       | 20 +++++++++++++++++++-
+ include/uapi/linux/devlink.h   | 11 +++++++++++
+ include/uapi/linux/inet_diag.h |  9 +++++++++
+ include/uapi/linux/pkt_cls.h   |  2 ++
+ include/uapi/linux/sctp.h      |  3 +++
+ 6 files changed, 56 insertions(+), 4 deletions(-)
+
+diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
+index 3e195ff43fa01..6d55239a4cc0f 100644
+--- a/include/uapi/linux/bpf.h
++++ b/include/uapi/linux/bpf.h
+@@ -106,6 +106,7 @@ enum bpf_cmd {
+ 	BPF_TASK_FD_QUERY,
+ 	BPF_MAP_LOOKUP_AND_DELETE_ELEM,
+ 	BPF_MAP_FREEZE,
++	BPF_BTF_GET_NEXT_ID,
+ };
+ 
+ enum bpf_map_type {
+@@ -284,6 +285,9 @@ enum bpf_attach_type {
+  */
+ #define BPF_F_TEST_RND_HI32	(1U << 2)
+ 
++/* The verifier internal test flag. Behavior is undefined */
++#define BPF_F_TEST_STATE_FREQ	(1U << 3)
++
+ /* When BPF ldimm64's insn[0].src_reg != 0 then this can have
+  * two extensions:
+  *
+@@ -337,6 +341,9 @@ enum bpf_attach_type {
+ #define BPF_F_RDONLY_PROG	(1U << 7)
+ #define BPF_F_WRONLY_PROG	(1U << 8)
+ 
++/* Clone map from listener for newly accepted socket */
++#define BPF_F_CLONE		(1U << 9)
++
+ /* flags for BPF_PROG_QUERY */
+ #define BPF_F_QUERY_EFFECTIVE	(1U << 0)
+ 
+@@ -577,6 +584,8 @@ union bpf_attr {
+  * 		limited to five).
+  *
+  * 		Each time the helper is called, it appends a line to the trace.
++ * 		Lines are discarded while *\/sys/kernel/debug/tracing/trace* is
++ * 		open, use *\/sys/kernel/debug/tracing/trace_pipe* to avoid this.
+  * 		The format of the trace is customizable, and the exact output
+  * 		one will get depends on the options set in
+  * 		*\/sys/kernel/debug/tracing/trace_options* (see also the
+@@ -1015,7 +1024,7 @@ union bpf_attr {
+  * 		The realm of the route for the packet associated to *skb*, or 0
+  * 		if none was found.
+  *
+- * int bpf_perf_event_output(struct pt_reg *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)
++ * int bpf_perf_event_output(struct pt_regs *ctx, struct bpf_map *map, u64 flags, void *data, u64 size)
+  * 	Description
+  * 		Write raw *data* blob into a special BPF perf event held by
+  * 		*map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf
+@@ -1077,7 +1086,7 @@ union bpf_attr {
+  * 	Return
+  * 		0 on success, or a negative error in case of failure.
+  *
+- * int bpf_get_stackid(struct pt_reg *ctx, struct bpf_map *map, u64 flags)
++ * int bpf_get_stackid(struct pt_regs *ctx, struct bpf_map *map, u64 flags)
+  * 	Description
+  * 		Walk a user or a kernel stack and return its id. To achieve
+  * 		this, the helper needs *ctx*, which is a pointer to the context
+@@ -1726,7 +1735,7 @@ union bpf_attr {
+  * 	Return
+  * 		0 on success, or a negative error in case of failure.
+  *
+- * int bpf_override_return(struct pt_reg *regs, u64 rc)
++ * int bpf_override_return(struct pt_regs *regs, u64 rc)
+  * 	Description
+  * 		Used for error injection, this helper uses kprobes to override
+  * 		the return value of the probed function, and to set it to *rc*.
+diff --git a/include/uapi/linux/can.h b/include/uapi/linux/can.h
+index 9009f0b6505cf..c61cdc7ad5cc6 100644
+--- a/include/uapi/linux/can.h
++++ b/include/uapi/linux/can.h
+@@ -157,7 +157,8 @@ struct canfd_frame {
+ #define CAN_TP20	4 /* VAG Transport Protocol v2.0 */
+ #define CAN_MCNET	5 /* Bosch MCNet */
+ #define CAN_ISOTP	6 /* ISO 15765-2 Transport Protocol */
+-#define CAN_NPROTO	7
++#define CAN_J1939	7 /* SAE J1939 */
++#define CAN_NPROTO	8
+ 
+ #define SOL_CAN_BASE 100
+ 
+@@ -174,6 +175,23 @@ struct sockaddr_can {
+ 		/* transport protocol class address information (e.g. ISOTP) */
+ 		struct { canid_t rx_id, tx_id; } tp;
+ 
++		/* J1939 address information */
++		struct {
++			/* 8 byte name when using dynamic addressing */
++			__u64 name;
++
++			/* pgn:
++			 * 8 bit: PS in PDU2 case, else 0
++			 * 8 bit: PF
++			 * 1 bit: DP
++			 * 1 bit: reserved
++			 */
++			__u32 pgn;
++
++			/* 1 byte address */
++			__u8 addr;
++		} j1939;
++
+ 		/* reserved for future CAN protocols address information */
+ 	} can_addr;
+ };
+diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
+index 3fb683bee6ba1..79e1405db67cc 100644
+--- a/include/uapi/linux/devlink.h
++++ b/include/uapi/linux/devlink.h
+@@ -202,6 +202,15 @@ enum devlink_param_cmode {
+ enum devlink_param_fw_load_policy_value {
+ 	DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER,
+ 	DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
++	DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK,
++	DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN,
++};
++
++enum devlink_param_reset_dev_on_drv_probe_value {
++	DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN,
++	DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS,
++	DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER,
++	DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK,
+ };
+ 
+ enum {
+@@ -410,6 +419,8 @@ enum devlink_attr {
+ 	DEVLINK_ATTR_TRAP_METADATA,			/* nested */
+ 	DEVLINK_ATTR_TRAP_GROUP_NAME,			/* string */
+ 
++	DEVLINK_ATTR_RELOAD_FAILED,			/* u8 0 or 1 */
++
+ 	/* add new attributes above here, update the policy in devlink.c */
+ 
+ 	__DEVLINK_ATTR_MAX,
+diff --git a/include/uapi/linux/inet_diag.h b/include/uapi/linux/inet_diag.h
+index f3bcd7ee82771..3dff6841486a4 100644
+--- a/include/uapi/linux/inet_diag.h
++++ b/include/uapi/linux/inet_diag.h
+@@ -153,11 +153,20 @@ enum {
+ 	INET_DIAG_BBRINFO,	/* request as INET_DIAG_VEGASINFO */
+ 	INET_DIAG_CLASS_ID,	/* request as INET_DIAG_TCLASS */
+ 	INET_DIAG_MD5SIG,
++	INET_DIAG_ULP_INFO,
+ 	__INET_DIAG_MAX,
+ };
+ 
+ #define INET_DIAG_MAX (__INET_DIAG_MAX - 1)
+ 
++enum {
++	INET_ULP_INFO_UNSPEC,
++	INET_ULP_INFO_NAME,
++	INET_ULP_INFO_TLS,
++	__INET_ULP_INFO_MAX,
++};
++#define INET_ULP_INFO_MAX (__INET_ULP_INFO_MAX - 1)
++
+ /* INET_DIAG_MEM */
+ 
+ struct inet_diag_meminfo {
+diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
+index 0a9ab625cba7b..c6ad22f76edee 100644
+--- a/include/uapi/linux/pkt_cls.h
++++ b/include/uapi/linux/pkt_cls.h
+@@ -165,6 +165,8 @@ enum {
+ 	TCA_POLICE_RESULT,
+ 	TCA_POLICE_TM,
+ 	TCA_POLICE_PAD,
++	TCA_POLICE_RATE64,
++	TCA_POLICE_PEAKRATE64,
+ 	__TCA_POLICE_MAX
+ #define TCA_POLICE_RESULT TCA_POLICE_RESULT
+ };
+diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
+index c4bce0a2011c1..0d4c1507a169d 100644
+--- a/include/uapi/linux/sctp.h
++++ b/include/uapi/linux/sctp.h
+@@ -134,6 +134,9 @@ typedef __s32 sctp_assoc_t;
+ #define SCTP_INTERLEAVING_SUPPORTED	125
+ #define SCTP_SENDMSG_CONNECT	126
+ #define SCTP_EVENT	127
++#define SCTP_ASCONF_SUPPORTED	128
++#define SCTP_AUTH_SUPPORTED	129
++#define SCTP_ECN_SUPPORTED	130
+ 
+ /* PR-SCTP policies */
+ #define SCTP_PR_SCTP_NONE	0x0000
+-- 
+2.26.2
+
diff --git a/SOURCES/0019-Update-kernel-headers.patch b/SOURCES/0019-Update-kernel-headers.patch
new file mode 100644
index 0000000..f6e47ee
--- /dev/null
+++ b/SOURCES/0019-Update-kernel-headers.patch
@@ -0,0 +1,150 @@
+From 4dfaa0a3e4ea077d95d7355e73a8069b1c8af97b Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 19:26:50 +0200
+Subject: [PATCH] Update kernel headers
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1812207
+Upstream Status: unknown commit ce9191ffee31d
+Conflicts: several unrelated missing changes in uapi
+
+commit ce9191ffee31d440591bf49ef530b80ee9975dfb
+Author: David Ahern <dsahern@gmail.com>
+Date:   Tue Mar 31 23:23:28 2020 +0000
+
+    Update kernel headers
+
+    Update kernel headers to commit:
+        7f80ccfe9968 ("net: ipv6: rpl_iptunnel: Fix potential memory leak in rpl_do_srh_inline")
+
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ include/uapi/linux/bpf.h       | 20 +++++++++++++++++++-
+ include/uapi/linux/devlink.h   |  6 ++++++
+ include/uapi/linux/if_link.h   |  5 ++++-
+ include/uapi/linux/inet_diag.h |  1 +
+ include/uapi/linux/lwtunnel.h  |  1 +
+ 5 files changed, 31 insertions(+), 2 deletions(-)
+
+diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
+index 6d55239a4cc0f..94aa5a1d38215 100644
+--- a/include/uapi/linux/bpf.h
++++ b/include/uapi/linux/bpf.h
+@@ -483,7 +483,7 @@ union bpf_attr {
+ 		__u32		prog_cnt;
+ 	} query;
+ 
+-	struct {
++	struct { /* anonymous struct used by BPF_RAW_TRACEPOINT_OPEN command */
+ 		__u64 name;
+ 		__u32 prog_fd;
+ 	} raw_tracepoint;
+@@ -511,6 +511,24 @@ union bpf_attr {
+ 		__u64		probe_offset;	/* output: probe_offset */
+ 		__u64		probe_addr;	/* output: probe_addr */
+ 	} task_fd_query;
++
++	struct { /* struct used by BPF_LINK_CREATE command */
++		__u32		prog_fd;	/* eBPF program to attach */
++		__u32		target_fd;	/* object to attach to */
++		__u32		attach_type;	/* attach type */
++		__u32		flags;		/* extra flags */
++	} link_create;
++
++	struct { /* struct used by BPF_LINK_UPDATE command */
++		__u32		link_fd;	/* link fd */
++		/* new program fd to update link with */
++		__u32		new_prog_fd;
++		__u32		flags;		/* extra flags */
++		/* expected link's program fd; is specified only if
++		 * BPF_F_REPLACE flag is set in flags */
++		__u32		old_prog_fd;
++	} link_update;
++
+ } __attribute__((aligned(8)));
+ 
+ /* The description below is an attempt at providing documentation to eBPF
+diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
+index 79e1405db67cc..e63aeab76bcb8 100644
+--- a/include/uapi/linux/devlink.h
++++ b/include/uapi/linux/devlink.h
+@@ -117,6 +117,11 @@ enum devlink_command {
+ 	DEVLINK_CMD_TRAP_GROUP_NEW,
+ 	DEVLINK_CMD_TRAP_GROUP_DEL,
+ 
++	DEVLINK_CMD_TRAP_POLICER_GET,	/* can dump */
++	DEVLINK_CMD_TRAP_POLICER_SET,
++	DEVLINK_CMD_TRAP_POLICER_NEW,
++	DEVLINK_CMD_TRAP_POLICER_DEL,
++
+ 	/* add new commands above here */
+ 	__DEVLINK_CMD_MAX,
+ 	DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
+@@ -216,6 +221,7 @@ enum devlink_param_reset_dev_on_drv_probe_value {
+ enum {
+ 	DEVLINK_ATTR_STATS_RX_PACKETS,		/* u64 */
+ 	DEVLINK_ATTR_STATS_RX_BYTES,		/* u64 */
++	DEVLINK_ATTR_STATS_RX_DROPPED,		/* u64 */
+ 
+ 	__DEVLINK_ATTR_STATS_MAX,
+ 	DEVLINK_ATTR_STATS_MAX = __DEVLINK_ATTR_STATS_MAX - 1
+diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
+index 4da0768d7a5a3..5d69479b8052d 100644
+--- a/include/uapi/linux/if_link.h
++++ b/include/uapi/linux/if_link.h
+@@ -459,6 +459,7 @@ enum {
+ 	IFLA_MACSEC_REPLAY_PROTECT,
+ 	IFLA_MACSEC_VALIDATION,
+ 	IFLA_MACSEC_PAD,
++	IFLA_MACSEC_OFFLOAD,
+ 	__IFLA_MACSEC_MAX,
+ };
+ 
+@@ -949,11 +950,12 @@ enum {
+ #define XDP_FLAGS_SKB_MODE		(1U << 1)
+ #define XDP_FLAGS_DRV_MODE		(1U << 2)
+ #define XDP_FLAGS_HW_MODE		(1U << 3)
++#define XDP_FLAGS_REPLACE		(1U << 4)
+ #define XDP_FLAGS_MODES			(XDP_FLAGS_SKB_MODE | \
+ 					 XDP_FLAGS_DRV_MODE | \
+ 					 XDP_FLAGS_HW_MODE)
+ #define XDP_FLAGS_MASK			(XDP_FLAGS_UPDATE_IF_NOEXIST | \
+-					 XDP_FLAGS_MODES)
++					 XDP_FLAGS_MODES | XDP_FLAGS_REPLACE)
+ 
+ /* These are stored into IFLA_XDP_ATTACHED on dump. */
+ enum {
+@@ -973,6 +975,7 @@ enum {
+ 	IFLA_XDP_DRV_PROG_ID,
+ 	IFLA_XDP_SKB_PROG_ID,
+ 	IFLA_XDP_HW_PROG_ID,
++	IFLA_XDP_EXPECTED_FD,
+ 	__IFLA_XDP_MAX,
+ };
+ 
+diff --git a/include/uapi/linux/inet_diag.h b/include/uapi/linux/inet_diag.h
+index 3dff6841486a4..db45fc664a5fd 100644
+--- a/include/uapi/linux/inet_diag.h
++++ b/include/uapi/linux/inet_diag.h
+@@ -163,6 +163,7 @@ enum {
+ 	INET_ULP_INFO_UNSPEC,
+ 	INET_ULP_INFO_NAME,
+ 	INET_ULP_INFO_TLS,
++	INET_ULP_INFO_MPTCP,
+ 	__INET_ULP_INFO_MAX,
+ };
+ #define INET_ULP_INFO_MAX (__INET_ULP_INFO_MAX - 1)
+diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h
+index 3f3fe6f30df0b..0ba94063c1809 100644
+--- a/include/uapi/linux/lwtunnel.h
++++ b/include/uapi/linux/lwtunnel.h
+@@ -13,6 +13,7 @@ enum lwtunnel_encap_types {
+ 	LWTUNNEL_ENCAP_SEG6,
+ 	LWTUNNEL_ENCAP_BPF,
+ 	LWTUNNEL_ENCAP_SEG6_LOCAL,
++	LWTUNNEL_ENCAP_RPL,
+ 	__LWTUNNEL_ENCAP_MAX,
+ };
+ 
+-- 
+2.26.2
+
diff --git a/SOURCES/0020-ss-allow-dumping-MPTCP-subflow-information.patch b/SOURCES/0020-ss-allow-dumping-MPTCP-subflow-information.patch
new file mode 100644
index 0000000..2189263
--- /dev/null
+++ b/SOURCES/0020-ss-allow-dumping-MPTCP-subflow-information.patch
@@ -0,0 +1,144 @@
+From afc9c910cc9c818180364860b04535def3c19b6e Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 19:27:41 +0200
+Subject: [PATCH] ss: allow dumping MPTCP subflow information
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1812207
+Upstream Status: unknown commit 712fdd98c0839
+Conflicts: context changes and code slightly adapted in tcp_show_info()
+           due to missing commit 14cadc707b919 ("ss: allow dumping kTLS info")
+
+commit 712fdd98c0839540a50baca0fb858c7a72d18031
+Author: Davide Caratti <dcaratti@redhat.com>
+Date:   Thu Apr 23 15:37:09 2020 +0200
+
+    ss: allow dumping MPTCP subflow information
+
+     [root@f31 packetdrill]# ss -tni
+
+     ESTAB    0        0           192.168.82.247:8080           192.0.2.1:35273
+              cubic wscale:7,8 [...] tcp-ulp-mptcp flags:Mec token:0000(id:0)/5f856c60(id:0) seq:b810457db34209a5 sfseq:1 ssnoff:0 maplen:190
+
+    Additionally extends ss manpage to describe the new entry layout.
+
+    Signed-off-by: Davide Caratti <dcaratti@redhat.com>
+    Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ man/man8/ss.8 |  5 ++++
+ misc/ss.c     | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 74 insertions(+)
+
+diff --git a/man/man8/ss.8 b/man/man8/ss.8
+index 023d771b17878..c80853f98c49a 100644
+--- a/man/man8/ss.8
++++ b/man/man8/ss.8
+@@ -261,6 +261,11 @@ the pacing rate and max pacing rate
+ .TP
+ .B rcv_space:<rcv_space>
+ a helper variable for TCP internal auto tuning socket receive buffer
++.P
++.TP
++.B tcp-ulp-mptcp flags:[MmBbJjecv] token:<rem_token(rem_id)/loc_token(loc_id)> seq:<sn> sfseq:<ssn> ssnoff:<off> maplen:<maplen>
++MPTCP subflow information
++.P
+ .RE
+ .TP
+ .B \-\-tos
+diff --git a/misc/ss.c b/misc/ss.c
+index 363b4c8d87cd3..3d565af86087c 100644
+--- a/misc/ss.c
++++ b/misc/ss.c
+@@ -51,6 +51,7 @@
+ #include <linux/tipc.h>
+ #include <linux/tipc_netlink.h>
+ #include <linux/tipc_sockets_diag.h>
++#include <linux/mptcp.h>
+ 
+ /* AF_VSOCK/PF_VSOCK is only provided since glibc 2.18 */
+ #ifndef PF_VSOCK
+@@ -2751,6 +2752,59 @@ static void print_md5sig(struct tcp_diag_md5sig *sig)
+ 	print_escape_buf(sig->tcpm_key, sig->tcpm_keylen, " ,");
+ }
+ 
++static void mptcp_subflow_info(struct rtattr *tb[])
++{
++	u_int32_t flags = 0;
++
++	if (tb[MPTCP_SUBFLOW_ATTR_FLAGS]) {
++		char caps[32 + 1] = { 0 }, *cap = &caps[0];
++
++		flags = rta_getattr_u32(tb[MPTCP_SUBFLOW_ATTR_FLAGS]);
++
++		if (flags & MPTCP_SUBFLOW_FLAG_MCAP_REM)
++			*cap++ = 'M';
++		if (flags & MPTCP_SUBFLOW_FLAG_MCAP_LOC)
++			*cap++ = 'm';
++		if (flags & MPTCP_SUBFLOW_FLAG_JOIN_REM)
++			*cap++ = 'J';
++		if (flags & MPTCP_SUBFLOW_FLAG_JOIN_LOC)
++			*cap++ = 'j';
++		if (flags & MPTCP_SUBFLOW_FLAG_BKUP_REM)
++			*cap++ = 'B';
++		if (flags & MPTCP_SUBFLOW_FLAG_BKUP_LOC)
++			*cap++ = 'b';
++		if (flags & MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED)
++			*cap++ = 'e';
++		if (flags & MPTCP_SUBFLOW_FLAG_CONNECTED)
++			*cap++ = 'c';
++		if (flags & MPTCP_SUBFLOW_FLAG_MAPVALID)
++			*cap++ = 'v';
++		if (flags)
++			out(" flags:%s", caps);
++	}
++	if (tb[MPTCP_SUBFLOW_ATTR_TOKEN_REM] &&
++	    tb[MPTCP_SUBFLOW_ATTR_TOKEN_LOC] &&
++	    tb[MPTCP_SUBFLOW_ATTR_ID_REM] &&
++	    tb[MPTCP_SUBFLOW_ATTR_ID_LOC])
++		out(" token:%04x(id:%hhu)/%04x(id:%hhu)",
++		    rta_getattr_u32(tb[MPTCP_SUBFLOW_ATTR_TOKEN_REM]),
++		    rta_getattr_u8(tb[MPTCP_SUBFLOW_ATTR_ID_REM]),
++		    rta_getattr_u32(tb[MPTCP_SUBFLOW_ATTR_TOKEN_LOC]),
++		    rta_getattr_u8(tb[MPTCP_SUBFLOW_ATTR_ID_LOC]));
++	if (tb[MPTCP_SUBFLOW_ATTR_MAP_SEQ])
++		out(" seq:%llx",
++		    rta_getattr_u64(tb[MPTCP_SUBFLOW_ATTR_MAP_SEQ]));
++	if (tb[MPTCP_SUBFLOW_ATTR_MAP_SFSEQ])
++		out(" sfseq:%x",
++		    rta_getattr_u32(tb[MPTCP_SUBFLOW_ATTR_MAP_SFSEQ]));
++	if (tb[MPTCP_SUBFLOW_ATTR_SSN_OFFSET])
++		out(" ssnoff:%x",
++		    rta_getattr_u32(tb[MPTCP_SUBFLOW_ATTR_SSN_OFFSET]));
++	if (tb[MPTCP_SUBFLOW_ATTR_MAP_DATALEN])
++		out(" maplen:%x",
++		    rta_getattr_u32(tb[MPTCP_SUBFLOW_ATTR_MAP_DATALEN]));
++}
++
+ #define TCPI_HAS_OPT(info, opt) !!(info->tcpi_options & (opt))
+ 
+ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
+@@ -2906,6 +2960,21 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
+ 			print_md5sig(sig++);
+ 		}
+ 	}
++	if (tb[INET_DIAG_ULP_INFO]) {
++		struct rtattr *ulpinfo[INET_ULP_INFO_MAX + 1] = { 0 };
++
++		parse_rtattr_nested(ulpinfo, INET_ULP_INFO_MAX,
++				    tb[INET_DIAG_ULP_INFO]);
++
++		if (ulpinfo[INET_ULP_INFO_MPTCP]) {
++			struct rtattr *sfinfo[MPTCP_SUBFLOW_ATTR_MAX + 1] =
++				{ 0 };
++
++			parse_rtattr_nested(sfinfo, MPTCP_SUBFLOW_ATTR_MAX,
++					    ulpinfo[INET_ULP_INFO_MPTCP]);
++			mptcp_subflow_info(sfinfo);
++		}
++	}
+ }
+ 
+ static const char *format_host_sa(struct sockaddr_storage *sa)
+-- 
+2.26.2
+
diff --git a/SOURCES/0021-man-mptcp-man-page.patch b/SOURCES/0021-man-mptcp-man-page.patch
new file mode 100644
index 0000000..f9aed62
--- /dev/null
+++ b/SOURCES/0021-man-mptcp-man-page.patch
@@ -0,0 +1,174 @@
+From af65892658d7c271d1fb328065a35f8017610418 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 19:28:45 +0200
+Subject: [PATCH] man: mptcp man page
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1812207
+Upstream Status: unknown commit 2d8b5fe93e9de
+
+commit 2d8b5fe93e9decb56acc243905d82fb22d6c4cfd
+Author: Paolo Abeni <pabeni@redhat.com>
+Date:   Thu Apr 23 15:37:10 2020 +0200
+
+    man: mptcp man page
+
+    describe the mptcp subcommands implemented so far.
+
+    Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ man/man8/ip-mptcp.8 | 142 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 142 insertions(+)
+ create mode 100644 man/man8/ip-mptcp.8
+
+diff --git a/man/man8/ip-mptcp.8 b/man/man8/ip-mptcp.8
+new file mode 100644
+index 0000000000000..f6457e97efbe8
+--- /dev/null
++++ b/man/man8/ip-mptcp.8
+@@ -0,0 +1,142 @@
++.TH IP\-MPTCP 8 "4 Apr 2020" "iproute2" "Linux"
++.SH "NAME"
++ip-mptcp \- MPTCP path manager configuration
++.SH "SYNOPSIS"
++.sp
++.ad l
++.in +8
++.ti -8
++.B ip
++.RI "[ " OPTIONS " ]"
++.B mptcp
++.RB "{ "
++.B endpoint
++.RB " | "
++.B limits
++.RB " | "
++.B help
++.RB " }"
++.sp
++
++.ti -8
++.BR "ip mptcp endpoint add "
++.IR IFADDR
++.RB "[ " dev
++.IR IFNAME " ]"
++.RB "[ " id
++.I ID
++.RB "] [ "
++.I FLAG-LIST
++.RB "] "
++
++.ti -8
++.BR "ip mptcp endpoint del id "
++.I ID
++
++.ti -8
++.BR "ip mptcp endpoint show "
++.RB "[ " id
++.I ID
++.RB "]"
++
++.ti -8
++.BR "ip mptcp endpoint flush"
++
++.ti -8
++.IR FLAG-LIST " := [ "  FLAG-LIST " ] " FLAG
++
++.ti -8
++.IR FLAG " := ["
++.B signal
++.RB "|"
++.B subflow
++.RB "|"
++.B backup
++.RB  "]"
++
++.ti -8
++.BR "ip mptcp limits set "
++.RB "[ "
++.B subflow
++.IR SUBFLOW_NR " ]"
++.RB "[ "
++.B add_addr_accepted
++.IR  ADD_ADDR_ACCEPTED_NR " ]"
++
++.ti -8
++.BR "ip mptcp limits show"
++
++.SH DESCRIPTION
++
++MPTCP is a transport protocol built on top of TCP that allows TCP
++connections to use multiple paths to maximize resource usage and increase
++redundancy. The ip-mptcp sub-commands allow configuring several aspects of the
++MPTCP path manager, which is in charge of subflows creation:
++
++.P
++The
++.B endpoint
++object specifies the IP addresses that will be used and/or announced for
++additional subflows:
++
++.TS
++l l.
++ip mptcp endpoint add	add new MPTCP endpoint
++ip mptcp endpoint delete	delete existing MPTCP endpoint
++ip mptcp endpoint show	get existing MPTCP endpoint
++ip mptcp endpoint flush	flush all existing MPTCP endpoints
++.TE
++
++.TP
++.IR ID
++is a unique numeric identifier for the given endpoint
++
++.TP
++.BR signal
++the endpoint will be announced/signalled to each peer via an ADD_ADDR MPTCP
++sub-option
++
++.TP
++.BR subflow
++if additional subflow creation is allowed by MPTCP limits, the endpoint will
++be used as the source address to create an additional subflow after that
++the MPTCP connection is established.
++
++.TP
++.BR backup
++the endpoint will be announced as a backup address, if this is a
++.BR signal
++endpoint, or the subflow will be created as a backup one if this is a
++.BR subflow
++endpoint
++
++.sp
++.PP
++The
++.B limits
++object specifies the constraints for subflow creations:
++
++.TS
++l l.
++ip mptcp limits show	get current MPTCP subflow creation limits
++ip mptcp limits set	change the MPTCP subflow creation limits
++.TE
++
++.TP
++.IR SUBFLOW_NR
++specifies the maximum number of additional subflows allowed for each MPTCP
++connection. Additional subflows can be created due to: incoming accepted
++ADD_ADDR option, local
++.BR subflow
++endpoints, additional subflows started by the peer.
++
++.TP
++.IR ADD_ADDR_ACCEPTED_NR
++specifies the maximum number of ADD_ADDR suboptions accepted for each MPTCP
++connection. The MPTCP path manager will try to create a new subflow for
++each accepted ADD_ADDR option, respecting the
++.IR SUBFLOW_NR
++limit.
++
++.SH AUTHOR
++Original Manpage by Paolo Abeni <pabeni@redhat.com>
+-- 
+2.26.2
+
diff --git a/SOURCES/0022-man-ip.8-add-reference-to-mptcp-man-page.patch b/SOURCES/0022-man-ip.8-add-reference-to-mptcp-man-page.patch
new file mode 100644
index 0000000..c38458f
--- /dev/null
+++ b/SOURCES/0022-man-ip.8-add-reference-to-mptcp-man-page.patch
@@ -0,0 +1,70 @@
+From c2e8f8b4c1980c773b967953b795f81942e209fb Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 19:28:45 +0200
+Subject: [PATCH] man: ip.8: add reference to mptcp man-page
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1812207
+Upstream Status: unknown commit 0c42c6b130196
+
+commit 0c42c6b130196d1d7e87acc5122f8fd325e75c5b
+Author: Paolo Abeni <pabeni@redhat.com>
+Date:   Wed Apr 29 19:17:22 2020 +0200
+
+    man: ip.8: add reference to mptcp man-page
+
+    While at it, additionally fix a mandoc warning in mptcp.8
+
+    Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ man/man8/ip-mptcp.8 | 1 -
+ man/man8/ip.8       | 7 ++++++-
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/man/man8/ip-mptcp.8 b/man/man8/ip-mptcp.8
+index f6457e97efbe8..ef8409ea4a24d 100644
+--- a/man/man8/ip-mptcp.8
++++ b/man/man8/ip-mptcp.8
+@@ -2,7 +2,6 @@
+ .SH "NAME"
+ ip-mptcp \- MPTCP path manager configuration
+ .SH "SYNOPSIS"
+-.sp
+ .ad l
+ .in +8
+ .ti -8
+diff --git a/man/man8/ip.8 b/man/man8/ip.8
+index c425aaf1d506e..f391237b4fcae 100644
+--- a/man/man8/ip.8
++++ b/man/man8/ip.8
+@@ -22,7 +22,7 @@ ip \- show / manipulate routing, network devices, interfaces and tunnels
+ .BR link " | " address " | " addrlabel " | " route " | " rule " | " neigh " | "\
+  ntable " | " tunnel " | " tuntap " | " maddress " | "  mroute " | " mrule " | "\
+  monitor " | " xfrm " | " netns " | "  l2tp " | "  tcp_metrics " | " token " | "\
+- macsec " | " vrf " }"
++ macsec " | " vrf " | " mptcp " }"
+ .sp
+ 
+ .ti -8
+@@ -268,6 +268,10 @@ readability.
+ .B monitor
+ - watch for netlink messages.
+ 
++.TP
++.B mptcp
++- manage MPTCP path manager.
++
+ .TP
+ .B mroute
+ - multicast routing cache entry.
+@@ -406,6 +410,7 @@ was written by Alexey N. Kuznetsov and added in Linux 2.2.
+ .BR ip-link (8),
+ .BR ip-maddress (8),
+ .BR ip-monitor (8),
++.BR ip-mptcp (8),
+ .BR ip-mroute (8),
+ .BR ip-neighbour (8),
+ .BR ip-netns (8),
+-- 
+2.26.2
+
diff --git a/SOURCES/0023-Update-kernel-headers.patch b/SOURCES/0023-Update-kernel-headers.patch
new file mode 100644
index 0000000..7d329c4
--- /dev/null
+++ b/SOURCES/0023-Update-kernel-headers.patch
@@ -0,0 +1,568 @@
+From f0023a7d874697821516583c1b3be95e2f110668 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 21:41:59 +0200
+Subject: [PATCH] Update kernel headers
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485
+Upstream Status: iproute2.git commit 7438afd2cc8d3
+Conflicts: on devlink uapi due to missing commit 9dcd8788fe6bc
+           ("Update kernel headers")
+
+commit 7438afd2cc8d37fd7f12e29963e1d926de53dda7
+Author: David Ahern <dsahern@gmail.com>
+Date:   Mon Nov 25 23:13:09 2019 +0000
+
+    Update kernel headers
+
+    Update kernel headers to commit:
+        c431047c4efe ("enetc: add support Credit Based Shaper(CBS) for hardware offload")
+
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ include/uapi/linux/bpf.h                    | 130 ++++++++++++++------
+ include/uapi/linux/gen_stats.h              |   5 +-
+ include/uapi/linux/lwtunnel.h               |  41 ++++++
+ include/uapi/linux/netfilter/ipset/ip_set.h |   2 +
+ include/uapi/linux/pkt_cls.h                |  29 +++++
+ include/uapi/linux/pkt_sched.h              |  22 ++--
+ include/uapi/linux/sctp.h                   |  15 +++
+ include/uapi/linux/tc_act/tc_tunnel_key.h   |  29 +++++
+ include/uapi/linux/tipc.h                   |  21 ++++
+ include/uapi/linux/tipc_netlink.h           |   4 +
+ 10 files changed, 246 insertions(+), 52 deletions(-)
+
+diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
+index 94aa5a1d38215..bf3475f915cf1 100644
+--- a/include/uapi/linux/bpf.h
++++ b/include/uapi/linux/bpf.h
+@@ -173,6 +173,7 @@ enum bpf_prog_type {
+ 	BPF_PROG_TYPE_CGROUP_SYSCTL,
+ 	BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
+ 	BPF_PROG_TYPE_CGROUP_SOCKOPT,
++	BPF_PROG_TYPE_TRACING,
+ };
+ 
+ enum bpf_attach_type {
+@@ -199,6 +200,9 @@ enum bpf_attach_type {
+ 	BPF_CGROUP_UDP6_RECVMSG,
+ 	BPF_CGROUP_GETSOCKOPT,
+ 	BPF_CGROUP_SETSOCKOPT,
++	BPF_TRACE_RAW_TP,
++	BPF_TRACE_FENTRY,
++	BPF_TRACE_FEXIT,
+ 	__MAX_BPF_ATTACH_TYPE
+ };
+ 
+@@ -344,6 +348,9 @@ enum bpf_attach_type {
+ /* Clone map from listener for newly accepted socket */
+ #define BPF_F_CLONE		(1U << 9)
+ 
++/* Enable memory-mapping BPF map */
++#define BPF_F_MMAPABLE		(1U << 10)
++
+ /* flags for BPF_PROG_QUERY */
+ #define BPF_F_QUERY_EFFECTIVE	(1U << 0)
+ 
+@@ -421,6 +428,7 @@ union bpf_attr {
+ 		__aligned_u64	line_info;	/* line info */
+ 		__u32		line_info_cnt;	/* number of bpf_line_info records */
+ 		__u32		attach_btf_id;	/* in-kernel BTF type id to attach to */
++		__u32		attach_prog_fd; /* 0 to attach to vmlinux */
+ 	};
+ 
+ 	struct { /* anonymous struct used by BPF_OBJ_* commands */
+@@ -579,10 +587,13 @@ union bpf_attr {
+  * 	Return
+  * 		0 on success, or a negative error in case of failure.
+  *
+- * int bpf_probe_read(void *dst, u32 size, const void *src)
++ * int bpf_probe_read(void *dst, u32 size, const void *unsafe_ptr)
+  * 	Description
+  * 		For tracing programs, safely attempt to read *size* bytes from
+- * 		address *src* and store the data in *dst*.
++ * 		kernel space address *unsafe_ptr* and store the data in *dst*.
++ *
++ * 		Generally, use bpf_probe_read_user() or bpf_probe_read_kernel()
++ * 		instead.
+  * 	Return
+  * 		0 on success, or a negative error in case of failure.
+  *
+@@ -1444,45 +1455,14 @@ union bpf_attr {
+  * 	Return
+  * 		0 on success, or a negative error in case of failure.
+  *
+- * int bpf_probe_read_str(void *dst, int size, const void *unsafe_ptr)
++ * int bpf_probe_read_str(void *dst, u32 size, const void *unsafe_ptr)
+  * 	Description
+- * 		Copy a NUL terminated string from an unsafe address
+- * 		*unsafe_ptr* to *dst*. The *size* should include the
+- * 		terminating NUL byte. In case the string length is smaller than
+- * 		*size*, the target is not padded with further NUL bytes. If the
+- * 		string length is larger than *size*, just *size*-1 bytes are
+- * 		copied and the last byte is set to NUL.
+- *
+- * 		On success, the length of the copied string is returned. This
+- * 		makes this helper useful in tracing programs for reading
+- * 		strings, and more importantly to get its length at runtime. See
+- * 		the following snippet:
+- *
+- * 		::
+- *
+- * 			SEC("kprobe/sys_open")
+- * 			void bpf_sys_open(struct pt_regs *ctx)
+- * 			{
+- * 			        char buf[PATHLEN]; // PATHLEN is defined to 256
+- * 			        int res = bpf_probe_read_str(buf, sizeof(buf),
+- * 				                             ctx->di);
+- *
+- * 				// Consume buf, for example push it to
+- * 				// userspace via bpf_perf_event_output(); we
+- * 				// can use res (the string length) as event
+- * 				// size, after checking its boundaries.
+- * 			}
++ * 		Copy a NUL terminated string from an unsafe kernel address
++ * 		*unsafe_ptr* to *dst*. See bpf_probe_read_kernel_str() for
++ * 		more details.
+  *
+- * 		In comparison, using **bpf_probe_read()** helper here instead
+- * 		to read the string would require to estimate the length at
+- * 		compile time, and would often result in copying more memory
+- * 		than necessary.
+- *
+- * 		Another useful use case is when parsing individual process
+- * 		arguments or individual environment variables navigating
+- * 		*current*\ **->mm->arg_start** and *current*\
+- * 		**->mm->env_start**: using this helper and the return value,
+- * 		one can quickly iterate at the right offset of the memory area.
++ * 		Generally, use bpf_probe_read_user_str() or bpf_probe_read_kernel_str()
++ * 		instead.
+  * 	Return
+  * 		On success, the strictly positive length of the string,
+  * 		including the trailing NUL character. On error, a negative
+@@ -2793,6 +2773,72 @@ union bpf_attr {
+  * 		restricted to raw_tracepoint bpf programs.
+  * 	Return
+  * 		0 on success, or a negative error in case of failure.
++ *
++ * int bpf_probe_read_user(void *dst, u32 size, const void *unsafe_ptr)
++ * 	Description
++ * 		Safely attempt to read *size* bytes from user space address
++ * 		*unsafe_ptr* and store the data in *dst*.
++ * 	Return
++ * 		0 on success, or a negative error in case of failure.
++ *
++ * int bpf_probe_read_kernel(void *dst, u32 size, const void *unsafe_ptr)
++ * 	Description
++ * 		Safely attempt to read *size* bytes from kernel space address
++ * 		*unsafe_ptr* and store the data in *dst*.
++ * 	Return
++ * 		0 on success, or a negative error in case of failure.
++ *
++ * int bpf_probe_read_user_str(void *dst, u32 size, const void *unsafe_ptr)
++ * 	Description
++ * 		Copy a NUL terminated string from an unsafe user address
++ * 		*unsafe_ptr* to *dst*. The *size* should include the
++ * 		terminating NUL byte. In case the string length is smaller than
++ * 		*size*, the target is not padded with further NUL bytes. If the
++ * 		string length is larger than *size*, just *size*-1 bytes are
++ * 		copied and the last byte is set to NUL.
++ *
++ * 		On success, the length of the copied string is returned. This
++ * 		makes this helper useful in tracing programs for reading
++ * 		strings, and more importantly to get its length at runtime. See
++ * 		the following snippet:
++ *
++ * 		::
++ *
++ * 			SEC("kprobe/sys_open")
++ * 			void bpf_sys_open(struct pt_regs *ctx)
++ * 			{
++ * 			        char buf[PATHLEN]; // PATHLEN is defined to 256
++ * 			        int res = bpf_probe_read_user_str(buf, sizeof(buf),
++ * 				                                  ctx->di);
++ *
++ * 				// Consume buf, for example push it to
++ * 				// userspace via bpf_perf_event_output(); we
++ * 				// can use res (the string length) as event
++ * 				// size, after checking its boundaries.
++ * 			}
++ *
++ * 		In comparison, using **bpf_probe_read_user()** helper here
++ * 		instead to read the string would require to estimate the length
++ * 		at compile time, and would often result in copying more memory
++ * 		than necessary.
++ *
++ * 		Another useful use case is when parsing individual process
++ * 		arguments or individual environment variables navigating
++ * 		*current*\ **->mm->arg_start** and *current*\
++ * 		**->mm->env_start**: using this helper and the return value,
++ * 		one can quickly iterate at the right offset of the memory area.
++ * 	Return
++ * 		On success, the strictly positive length of the string,
++ * 		including the trailing NUL character. On error, a negative
++ * 		value.
++ *
++ * int bpf_probe_read_kernel_str(void *dst, u32 size, const void *unsafe_ptr)
++ * 	Description
++ * 		Copy a NUL terminated string from an unsafe kernel address *unsafe_ptr*
++ * 		to *dst*. Same semantics as with bpf_probe_read_user_str() apply.
++ * 	Return
++ * 		On success, the strictly positive length of the string,	including
++ * 		the trailing NUL character. On error, a negative value.
+  */
+ #define __BPF_FUNC_MAPPER(FN)		\
+ 	FN(unspec),			\
+@@ -2906,7 +2952,11 @@ union bpf_attr {
+ 	FN(sk_storage_delete),		\
+ 	FN(send_signal),		\
+ 	FN(tcp_gen_syncookie),		\
+-	FN(skb_output),
++	FN(skb_output),			\
++	FN(probe_read_user),		\
++	FN(probe_read_kernel),		\
++	FN(probe_read_user_str),	\
++	FN(probe_read_kernel_str),
+ 
+ /* integer value in 'imm' field of BPF_CALL instruction selects which helper
+  * function eBPF program intends to call
+diff --git a/include/uapi/linux/gen_stats.h b/include/uapi/linux/gen_stats.h
+index 065408e16a807..852f234f1fd63 100644
+--- a/include/uapi/linux/gen_stats.h
++++ b/include/uapi/linux/gen_stats.h
+@@ -13,6 +13,7 @@ enum {
+ 	TCA_STATS_RATE_EST64,
+ 	TCA_STATS_PAD,
+ 	TCA_STATS_BASIC_HW,
++	TCA_STATS_PKT64,
+ 	__TCA_STATS_MAX,
+ };
+ #define TCA_STATS_MAX (__TCA_STATS_MAX - 1)
+@@ -26,10 +27,6 @@ struct gnet_stats_basic {
+ 	__u64	bytes;
+ 	__u32	packets;
+ };
+-struct gnet_stats_basic_packed {
+-	__u64	bytes;
+-	__u32	packets;
+-} __attribute__ ((packed));
+ 
+ /**
+  * struct gnet_stats_rate_est - rate estimator
+diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h
+index 0ba94063c1809..b7c0191fd1b5f 100644
+--- a/include/uapi/linux/lwtunnel.h
++++ b/include/uapi/linux/lwtunnel.h
+@@ -28,6 +28,7 @@ enum lwtunnel_ip_t {
+ 	LWTUNNEL_IP_TOS,
+ 	LWTUNNEL_IP_FLAGS,
+ 	LWTUNNEL_IP_PAD,
++	LWTUNNEL_IP_OPTS,
+ 	__LWTUNNEL_IP_MAX,
+ };
+ 
+@@ -42,11 +43,51 @@ enum lwtunnel_ip6_t {
+ 	LWTUNNEL_IP6_TC,
+ 	LWTUNNEL_IP6_FLAGS,
+ 	LWTUNNEL_IP6_PAD,
++	LWTUNNEL_IP6_OPTS,
+ 	__LWTUNNEL_IP6_MAX,
+ };
+ 
+ #define LWTUNNEL_IP6_MAX (__LWTUNNEL_IP6_MAX - 1)
+ 
++enum {
++	LWTUNNEL_IP_OPTS_UNSPEC,
++	LWTUNNEL_IP_OPTS_GENEVE,
++	LWTUNNEL_IP_OPTS_VXLAN,
++	LWTUNNEL_IP_OPTS_ERSPAN,
++	__LWTUNNEL_IP_OPTS_MAX,
++};
++
++#define LWTUNNEL_IP_OPTS_MAX (__LWTUNNEL_IP_OPTS_MAX - 1)
++
++enum {
++	LWTUNNEL_IP_OPT_GENEVE_UNSPEC,
++	LWTUNNEL_IP_OPT_GENEVE_CLASS,
++	LWTUNNEL_IP_OPT_GENEVE_TYPE,
++	LWTUNNEL_IP_OPT_GENEVE_DATA,
++	__LWTUNNEL_IP_OPT_GENEVE_MAX,
++};
++
++#define LWTUNNEL_IP_OPT_GENEVE_MAX (__LWTUNNEL_IP_OPT_GENEVE_MAX - 1)
++
++enum {
++	LWTUNNEL_IP_OPT_VXLAN_UNSPEC,
++	LWTUNNEL_IP_OPT_VXLAN_GBP,
++	__LWTUNNEL_IP_OPT_VXLAN_MAX,
++};
++
++#define LWTUNNEL_IP_OPT_VXLAN_MAX (__LWTUNNEL_IP_OPT_VXLAN_MAX - 1)
++
++enum {
++	LWTUNNEL_IP_OPT_ERSPAN_UNSPEC,
++	LWTUNNEL_IP_OPT_ERSPAN_VER,
++	LWTUNNEL_IP_OPT_ERSPAN_INDEX,
++	LWTUNNEL_IP_OPT_ERSPAN_DIR,
++	LWTUNNEL_IP_OPT_ERSPAN_HWID,
++	__LWTUNNEL_IP_OPT_ERSPAN_MAX,
++};
++
++#define LWTUNNEL_IP_OPT_ERSPAN_MAX (__LWTUNNEL_IP_OPT_ERSPAN_MAX - 1)
++
+ enum {
+ 	LWT_BPF_PROG_UNSPEC,
+ 	LWT_BPF_PROG_FD,
+diff --git a/include/uapi/linux/netfilter/ipset/ip_set.h b/include/uapi/linux/netfilter/ipset/ip_set.h
+index c512003dba6ba..4b372f46f0d04 100644
+--- a/include/uapi/linux/netfilter/ipset/ip_set.h
++++ b/include/uapi/linux/netfilter/ipset/ip_set.h
+@@ -205,6 +205,8 @@ enum ipset_cadt_flags {
+ 	IPSET_FLAG_WITH_FORCEADD = (1 << IPSET_FLAG_BIT_WITH_FORCEADD),
+ 	IPSET_FLAG_BIT_WITH_SKBINFO = 6,
+ 	IPSET_FLAG_WITH_SKBINFO = (1 << IPSET_FLAG_BIT_WITH_SKBINFO),
++	IPSET_FLAG_BIT_IFACE_WILDCARD = 7,
++	IPSET_FLAG_IFACE_WILDCARD = (1 << IPSET_FLAG_BIT_IFACE_WILDCARD),
+ 	IPSET_FLAG_CADT_MAX	= 15,
+ };
+ 
+diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
+index c6ad22f76edee..449a63971451f 100644
+--- a/include/uapi/linux/pkt_cls.h
++++ b/include/uapi/linux/pkt_cls.h
+@@ -571,6 +571,14 @@ enum {
+ 					 * TCA_FLOWER_KEY_ENC_OPT_GENEVE_
+ 					 * attributes
+ 					 */
++	TCA_FLOWER_KEY_ENC_OPTS_VXLAN,	/* Nested
++					 * TCA_FLOWER_KEY_ENC_OPT_VXLAN_
++					 * attributes
++					 */
++	TCA_FLOWER_KEY_ENC_OPTS_ERSPAN,	/* Nested
++					 * TCA_FLOWER_KEY_ENC_OPT_ERSPAN_
++					 * attributes
++					 */
+ 	__TCA_FLOWER_KEY_ENC_OPTS_MAX,
+ };
+ 
+@@ -588,6 +596,27 @@ enum {
+ #define TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX \
+ 		(__TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX - 1)
+ 
++enum {
++	TCA_FLOWER_KEY_ENC_OPT_VXLAN_UNSPEC,
++	TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP,		/* u32 */
++	__TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX,
++};
++
++#define TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX \
++		(__TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX - 1)
++
++enum {
++	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_UNSPEC,
++	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER,              /* u8 */
++	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX,            /* be32 */
++	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR,              /* u8 */
++	TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID,             /* u8 */
++	__TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX,
++};
++
++#define TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX \
++		(__TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX - 1)
++
+ enum {
+ 	TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0),
+ 	TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
+diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
+index 18f185299f472..dab60bd8f0f4a 100644
+--- a/include/uapi/linux/pkt_sched.h
++++ b/include/uapi/linux/pkt_sched.h
+@@ -950,19 +950,25 @@ enum {
+ 	TCA_PIE_BETA,
+ 	TCA_PIE_ECN,
+ 	TCA_PIE_BYTEMODE,
++	TCA_PIE_DQ_RATE_ESTIMATOR,
+ 	__TCA_PIE_MAX
+ };
+ #define TCA_PIE_MAX   (__TCA_PIE_MAX - 1)
+ 
+ struct tc_pie_xstats {
+-	__u64 prob;             /* current probability */
+-	__u32 delay;            /* current delay in ms */
+-	__u32 avg_dq_rate;      /* current average dq_rate in bits/pie_time */
+-	__u32 packets_in;       /* total number of packets enqueued */
+-	__u32 dropped;          /* packets dropped due to pie_action */
+-	__u32 overlimit;        /* dropped due to lack of space in queue */
+-	__u32 maxq;             /* maximum queue size */
+-	__u32 ecn_mark;         /* packets marked with ecn*/
++	__u64 prob;			/* current probability */
++	__u32 delay;			/* current delay in ms */
++	__u32 avg_dq_rate;		/* current average dq_rate in
++					 * bits/pie_time
++					 */
++	__u32 dq_rate_estimating;	/* is avg_dq_rate being calculated? */
++	__u32 packets_in;		/* total number of packets enqueued */
++	__u32 dropped;			/* packets dropped due to pie_action */
++	__u32 overlimit;		/* dropped due to lack of space
++					 * in queue
++					 */
++	__u32 maxq;			/* maximum queue size */
++	__u32 ecn_mark;			/* packets marked with ecn*/
+ };
+ 
+ /* CBS */
+diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
+index 0d4c1507a169d..f8f218b16c280 100644
+--- a/include/uapi/linux/sctp.h
++++ b/include/uapi/linux/sctp.h
+@@ -105,6 +105,7 @@ typedef __s32 sctp_assoc_t;
+ #define SCTP_DEFAULT_SNDINFO	34
+ #define SCTP_AUTH_DEACTIVATE_KEY	35
+ #define SCTP_REUSE_PORT		36
++#define SCTP_PEER_ADDR_THLDS_V2	37
+ 
+ /* Internal Socket Options. Some of the sctp library functions are
+  * implemented using these socket options.
+@@ -137,6 +138,8 @@ typedef __s32 sctp_assoc_t;
+ #define SCTP_ASCONF_SUPPORTED	128
+ #define SCTP_AUTH_SUPPORTED	129
+ #define SCTP_ECN_SUPPORTED	130
++#define SCTP_EXPOSE_POTENTIALLY_FAILED_STATE	131
++#define SCTP_EXPOSE_PF_STATE	SCTP_EXPOSE_POTENTIALLY_FAILED_STATE
+ 
+ /* PR-SCTP policies */
+ #define SCTP_PR_SCTP_NONE	0x0000
+@@ -410,6 +413,8 @@ enum sctp_spc_state {
+ 	SCTP_ADDR_ADDED,
+ 	SCTP_ADDR_MADE_PRIM,
+ 	SCTP_ADDR_CONFIRMED,
++	SCTP_ADDR_POTENTIALLY_FAILED,
++#define SCTP_ADDR_PF	SCTP_ADDR_POTENTIALLY_FAILED
+ };
+ 
+ 
+@@ -917,6 +922,7 @@ struct sctp_paddrinfo {
+ enum sctp_spinfo_state {
+ 	SCTP_INACTIVE,
+ 	SCTP_PF,
++#define	SCTP_POTENTIALLY_FAILED		SCTP_PF
+ 	SCTP_ACTIVE,
+ 	SCTP_UNCONFIRMED,
+ 	SCTP_UNKNOWN = 0xffff  /* Value used for transport state unknown */
+@@ -1062,6 +1068,15 @@ struct sctp_paddrthlds {
+ 	__u16 spt_pathpfthld;
+ };
+ 
++/* Use a new structure with spt_pathcpthld for back compatibility */
++struct sctp_paddrthlds_v2 {
++	sctp_assoc_t spt_assoc_id;
++	struct sockaddr_storage spt_address;
++	__u16 spt_pathmaxrxt;
++	__u16 spt_pathpfthld;
++	__u16 spt_pathcpthld;
++};
++
+ /*
+  * Socket Option for Getting the Association/Stream-Specific PR-SCTP Status
+  */
+diff --git a/include/uapi/linux/tc_act/tc_tunnel_key.h b/include/uapi/linux/tc_act/tc_tunnel_key.h
+index 41c8b462c177c..3f10dc4e7a4bb 100644
+--- a/include/uapi/linux/tc_act/tc_tunnel_key.h
++++ b/include/uapi/linux/tc_act/tc_tunnel_key.h
+@@ -50,6 +50,14 @@ enum {
+ 						 * TCA_TUNNEL_KEY_ENC_OPTS_
+ 						 * attributes
+ 						 */
++	TCA_TUNNEL_KEY_ENC_OPTS_VXLAN,		/* Nested
++						 * TCA_TUNNEL_KEY_ENC_OPTS_
++						 * attributes
++						 */
++	TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN,		/* Nested
++						 * TCA_TUNNEL_KEY_ENC_OPTS_
++						 * attributes
++						 */
+ 	__TCA_TUNNEL_KEY_ENC_OPTS_MAX,
+ };
+ 
+@@ -67,4 +75,25 @@ enum {
+ #define TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX \
+ 	(__TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX - 1)
+ 
++enum {
++	TCA_TUNNEL_KEY_ENC_OPT_VXLAN_UNSPEC,
++	TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP,		/* u32 */
++	__TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX,
++};
++
++#define TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX \
++	(__TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX - 1)
++
++enum {
++	TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_UNSPEC,
++	TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER,		/* u8 */
++	TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX,		/* be32 */
++	TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR,		/* u8 */
++	TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID,		/* u8 */
++	__TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX,
++};
++
++#define TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX \
++	(__TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX - 1)
++
+ #endif
+diff --git a/include/uapi/linux/tipc.h b/include/uapi/linux/tipc.h
+index 0f6f28b2e3010..de5bcd2a09fae 100644
+--- a/include/uapi/linux/tipc.h
++++ b/include/uapi/linux/tipc.h
+@@ -233,6 +233,27 @@ struct tipc_sioc_nodeid_req {
+ 	char node_id[TIPC_NODEID_LEN];
+ };
+ 
++/*
++ * TIPC Crypto, AEAD
++ */
++#define TIPC_AEAD_ALG_NAME		(32)
++
++struct tipc_aead_key {
++	char alg_name[TIPC_AEAD_ALG_NAME];
++	unsigned int keylen;	/* in bytes */
++	char key[];
++};
++
++#define TIPC_AEAD_KEYLEN_MIN		(16 + 4)
++#define TIPC_AEAD_KEYLEN_MAX		(32 + 4)
++#define TIPC_AEAD_KEY_SIZE_MAX		(sizeof(struct tipc_aead_key) + \
++							TIPC_AEAD_KEYLEN_MAX)
++
++static __inline__ int tipc_aead_key_size(struct tipc_aead_key *key)
++{
++	return sizeof(*key) + key->keylen;
++}
++
+ /* The macros and functions below are deprecated:
+  */
+ 
+diff --git a/include/uapi/linux/tipc_netlink.h b/include/uapi/linux/tipc_netlink.h
+index efb958fd167d0..6c2194ab745bd 100644
+--- a/include/uapi/linux/tipc_netlink.h
++++ b/include/uapi/linux/tipc_netlink.h
+@@ -63,6 +63,8 @@ enum {
+ 	TIPC_NL_PEER_REMOVE,
+ 	TIPC_NL_BEARER_ADD,
+ 	TIPC_NL_UDP_GET_REMOTEIP,
++	TIPC_NL_KEY_SET,
++	TIPC_NL_KEY_FLUSH,
+ 
+ 	__TIPC_NL_CMD_MAX,
+ 	TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1
+@@ -160,6 +162,8 @@ enum {
+ 	TIPC_NLA_NODE_UNSPEC,
+ 	TIPC_NLA_NODE_ADDR,		/* u32 */
+ 	TIPC_NLA_NODE_UP,		/* flag */
++	TIPC_NLA_NODE_ID,		/* data */
++	TIPC_NLA_NODE_KEY,		/* data */
+ 
+ 	__TIPC_NLA_NODE_MAX,
+ 	TIPC_NLA_NODE_MAX = __TIPC_NLA_NODE_MAX - 1
+-- 
+2.26.2
+
diff --git a/SOURCES/0024-iproute_lwtunnel-add-options-support-for-geneve-meta.patch b/SOURCES/0024-iproute_lwtunnel-add-options-support-for-geneve-meta.patch
new file mode 100644
index 0000000..e093682
--- /dev/null
+++ b/SOURCES/0024-iproute_lwtunnel-add-options-support-for-geneve-meta.patch
@@ -0,0 +1,297 @@
+From c6f909bd0f40c58f39f857e1c57638cb41241fa2 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 21:43:01 +0200
+Subject: [PATCH] iproute_lwtunnel: add options support for geneve metadata
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485
+Upstream Status: unknown commit ca7614d4c6f45
+
+commit ca7614d4c6f456187d831a8202bb4a8559a72f8b
+Author: Xin Long <lucien.xin@gmail.com>
+Date:   Mon Apr 27 18:27:45 2020 +0800
+
+    iproute_lwtunnel: add options support for geneve metadata
+
+    This patch is to add LWTUNNEL_IP(6)_OPTS and LWTUNNEL_IP_OPTS_GENEVE's
+    parse and print to implement geneve options support in iproute_lwtunnel.
+
+    Options are expressed as class:type:data and multiple options may be
+    listed using a comma delimiter, class and type are numbers and data
+    is a hex string.
+
+    With this patch, users can add and dump geneve options like:
+
+      # ip netns add a
+      # ip netns add b
+      # ip -n a link add eth0 type veth peer name eth0 netns b
+      # ip -n a link set eth0 up; ip -n b link set eth0 up
+      # ip -n a addr add 10.1.0.1/24 dev eth0
+      # ip -n b addr add 10.1.0.2/24 dev eth0
+      # ip -n b link add geneve1 type geneve id 1 remote 10.1.0.1 ttl 64
+      # ip -n b addr add 1.1.1.1/24 dev geneve1
+      # ip -n b link set geneve1 up
+      # ip -n b route add 2.1.1.0/24 dev geneve1
+      # ip -n a link add geneve1 type geneve external
+      # ip -n a addr add 2.1.1.1/24 dev geneve1
+      # ip -n a link set geneve1 up
+      # ip -n a route add 1.1.1.0/24 encap ip id 1 geneve_opts \
+        1:1:1212121234567890,1:1:1212121234567890,1:1:1212121234567890 \
+        dst 10.1.0.2 dev geneve1
+      # ip -n a route show
+      # ip netns exec a ping 1.1.1.1 -c 1
+
+       1.1.1.0/24  encap ip id 1 src 0.0.0.0 dst 10.1.0.2 ttl 0 tos 0
+         geneve_opts 1:1:1212121234567890,1:1:1212121234567890 ...
+
+       PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
+       64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=0.079 ms
+
+    v1->v2:
+      - improve the changelog.
+      - use PRINT_ANY to support dumping with json format.
+    v2->v3:
+      - implement proper JSON array for opts instead of just bunch of strings.
+    v3->v4:
+      - keep the same format between input and output, json and non json.
+      - print class and type as uint and print data as hex string.
+
+    Signed-off-by: Xin Long <lucien.xin@gmail.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ ip/iproute_lwtunnel.c | 174 +++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 172 insertions(+), 2 deletions(-)
+
+diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
+index 60f34a32a6e5b..76d906c47c44f 100644
+--- a/ip/iproute_lwtunnel.c
++++ b/ip/iproute_lwtunnel.c
+@@ -291,6 +291,54 @@ static void print_encap_mpls(FILE *fp, struct rtattr *encap)
+ 			rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
+ }
+ 
++static void lwtunnel_print_geneve_opts(struct rtattr *attr)
++{
++	struct rtattr *tb[LWTUNNEL_IP_OPT_GENEVE_MAX + 1];
++	struct rtattr *i = RTA_DATA(attr);
++	int rem = RTA_PAYLOAD(attr);
++	char *name = "geneve_opts";
++	int data_len, offset = 0;
++	char data[rem * 2 + 1];
++	__u16 class;
++	__u8 type;
++
++	print_nl();
++	print_string(PRINT_FP, name, "\t%s ", name);
++	open_json_array(PRINT_JSON, name);
++
++	while (rem) {
++		parse_rtattr(tb, LWTUNNEL_IP_OPT_GENEVE_MAX, i, rem);
++		class = rta_getattr_be16(tb[LWTUNNEL_IP_OPT_GENEVE_CLASS]);
++		type = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_GENEVE_TYPE]);
++		data_len = RTA_PAYLOAD(tb[LWTUNNEL_IP_OPT_GENEVE_DATA]);
++		hexstring_n2a(RTA_DATA(tb[LWTUNNEL_IP_OPT_GENEVE_DATA]),
++			      data_len, data, sizeof(data));
++		offset += data_len + 20;
++		rem -= data_len + 20;
++		i = RTA_DATA(attr) + offset;
++
++		open_json_object(NULL);
++		print_uint(PRINT_ANY, "class", "%u", class);
++		print_uint(PRINT_ANY, "type", ":%u", type);
++		if (rem)
++			print_string(PRINT_ANY, "data", ":%s,", data);
++		else
++			print_string(PRINT_ANY, "data", ":%s ", data);
++		close_json_object();
++	}
++
++	close_json_array(PRINT_JSON, name);
++}
++
++static void lwtunnel_print_opts(struct rtattr *attr)
++{
++	struct rtattr *tb_opt[LWTUNNEL_IP_OPTS_MAX + 1];
++
++	parse_rtattr_nested(tb_opt, LWTUNNEL_IP_OPTS_MAX, attr);
++	if (tb_opt[LWTUNNEL_IP_OPTS_GENEVE])
++		lwtunnel_print_geneve_opts(tb_opt[LWTUNNEL_IP_OPTS_GENEVE]);
++}
++
+ static void print_encap_ip(FILE *fp, struct rtattr *encap)
+ {
+ 	struct rtattr *tb[LWTUNNEL_IP_MAX+1];
+@@ -329,6 +377,9 @@ static void print_encap_ip(FILE *fp, struct rtattr *encap)
+ 		if (flags & TUNNEL_SEQ)
+ 			print_bool(PRINT_ANY, "seq", "seq ", true);
+ 	}
++
++	if (tb[LWTUNNEL_IP_OPTS])
++		lwtunnel_print_opts(tb[LWTUNNEL_IP_OPTS]);
+ }
+ 
+ static void print_encap_ila(FILE *fp, struct rtattr *encap)
+@@ -401,6 +452,9 @@ static void print_encap_ip6(FILE *fp, struct rtattr *encap)
+ 		if (flags & TUNNEL_SEQ)
+ 			print_bool(PRINT_ANY, "seq", "seq ", true);
+ 	}
++
++	if (tb[LWTUNNEL_IP6_OPTS])
++		lwtunnel_print_opts(tb[LWTUNNEL_IP6_OPTS]);
+ }
+ 
+ static void print_encap_bpf(FILE *fp, struct rtattr *encap)
+@@ -795,11 +849,97 @@ static int parse_encap_mpls(struct rtattr *rta, size_t len,
+ 	return 0;
+ }
+ 
++static int lwtunnel_parse_geneve_opt(char *str, size_t len, struct rtattr *rta)
++{
++	struct rtattr *nest;
++	char *token;
++	int i, err;
++
++	nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_GENEVE | NLA_F_NESTED);
++	i = 1;
++	token = strsep(&str, ":");
++	while (token) {
++		switch (i) {
++		case LWTUNNEL_IP_OPT_GENEVE_CLASS:
++		{
++			__be16 opt_class;
++
++			if (!strlen(token))
++				break;
++			err = get_be16(&opt_class, token, 0);
++			if (err)
++				return err;
++
++			rta_addattr16(rta, len, i, opt_class);
++			break;
++		}
++		case LWTUNNEL_IP_OPT_GENEVE_TYPE:
++		{
++			__u8 opt_type;
++
++			if (!strlen(token))
++				break;
++			err = get_u8(&opt_type, token, 0);
++			if (err)
++				return err;
++
++			rta_addattr8(rta, len, i, opt_type);
++			break;
++		}
++		case LWTUNNEL_IP_OPT_GENEVE_DATA:
++		{
++			size_t token_len = strlen(token);
++			__u8 *opts;
++
++			if (!token_len)
++				break;
++			opts = malloc(token_len / 2);
++			if (!opts)
++				return -1;
++			if (hex2mem(token, opts, token_len / 2) < 0) {
++				free(opts);
++				return -1;
++			}
++			rta_addattr_l(rta, len, i, opts, token_len / 2);
++			free(opts);
++
++			break;
++		}
++		default:
++			fprintf(stderr, "Unknown \"geneve_opts\" type\n");
++			return -1;
++		}
++
++		token = strsep(&str, ":");
++		i++;
++	}
++	rta_nest_end(rta, nest);
++
++	return 0;
++}
++
++static int lwtunnel_parse_geneve_opts(char *str, size_t len, struct rtattr *rta)
++{
++	char *token;
++	int err;
++
++	token = strsep(&str, ",");
++	while (token) {
++		err = lwtunnel_parse_geneve_opt(token, len, rta);
++		if (err)
++			return err;
++
++		token = strsep(&str, ",");
++	}
++
++	return 0;
++}
++
+ static int parse_encap_ip(struct rtattr *rta, size_t len,
+ 			  int *argcp, char ***argvp)
+ {
+ 	int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
+-	int key_ok = 0, csum_ok = 0, seq_ok = 0;
++	int key_ok = 0, csum_ok = 0, seq_ok = 0, opts_ok = 0;
+ 	char **argv = *argvp;
+ 	int argc = *argcp;
+ 	int ret = 0;
+@@ -851,6 +991,21 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
+ 			if (get_u8(&ttl, *argv, 0))
+ 				invarg("\"ttl\" value is invalid\n", *argv);
+ 			ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
++		} else if (strcmp(*argv, "geneve_opts") == 0) {
++			struct rtattr *nest;
++
++			if (opts_ok++)
++				duparg2("opts", *argv);
++
++			NEXT_ARG();
++
++			nest = rta_nest(rta, len,
++					LWTUNNEL_IP_OPTS | NLA_F_NESTED);
++			ret = lwtunnel_parse_geneve_opts(*argv, len, rta);
++			if (ret)
++				invarg("\"geneve_opts\" value is invalid\n",
++				       *argv);
++			rta_nest_end(rta, nest);
+ 		} else if (strcmp(*argv, "key") == 0) {
+ 			if (key_ok++)
+ 				duparg2("key", *argv);
+@@ -966,7 +1121,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
+ 			   int *argcp, char ***argvp)
+ {
+ 	int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
+-	int key_ok = 0, csum_ok = 0, seq_ok = 0;
++	int key_ok = 0, csum_ok = 0, seq_ok = 0, opts_ok = 0;
+ 	char **argv = *argvp;
+ 	int argc = *argcp;
+ 	int ret = 0;
+@@ -1020,6 +1175,21 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
+ 				       *argv);
+ 			ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT,
+ 					   hoplimit);
++		} else if (strcmp(*argv, "geneve_opts") == 0) {
++			struct rtattr *nest;
++
++			if (opts_ok++)
++				duparg2("opts", *argv);
++
++			NEXT_ARG();
++
++			nest = rta_nest(rta, len,
++					LWTUNNEL_IP_OPTS | NLA_F_NESTED);
++			ret = lwtunnel_parse_geneve_opts(*argv, len, rta);
++			if (ret)
++				invarg("\"geneve_opts\" value is invalid\n",
++				       *argv);
++			rta_nest_end(rta, nest);
+ 		} else if (strcmp(*argv, "key") == 0) {
+ 			if (key_ok++)
+ 				duparg2("key", *argv);
+-- 
+2.26.2
+
diff --git a/SOURCES/0025-iproute_lwtunnel-add-options-support-for-vxlan-metad.patch b/SOURCES/0025-iproute_lwtunnel-add-options-support-for-vxlan-metad.patch
new file mode 100644
index 0000000..cc25df9
--- /dev/null
+++ b/SOURCES/0025-iproute_lwtunnel-add-options-support-for-vxlan-metad.patch
@@ -0,0 +1,175 @@
+From 873511fb86756c40631f80963356179627d69d49 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 21:43:01 +0200
+Subject: [PATCH] iproute_lwtunnel: add options support for vxlan metadata
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485
+Upstream Status: unknown commit b1bc0f3892222
+
+commit b1bc0f38922220b379ed39552a5e2a7cf9dccd92
+Author: Xin Long <lucien.xin@gmail.com>
+Date:   Mon Apr 27 18:27:46 2020 +0800
+
+    iproute_lwtunnel: add options support for vxlan metadata
+
+    This patch is to add LWTUNNEL_IP_OPTS_VXLAN's parse and print to implement
+    vxlan options support in iproute_lwtunnel.
+
+    Option is expressed a number for gbp only, and vxlan doesn't support
+    multiple options.
+
+    With this patch, users can add and dump vxlan options like:
+
+      # ip netns add a
+      # ip netns add b
+      # ip -n a link add eth0 type veth peer name eth0 netns b
+      # ip -n a link set eth0 up
+      # ip -n b link set eth0 up
+      # ip -n a addr add 10.1.0.1/24 dev eth0
+      # ip -n b addr add 10.1.0.2/24 dev eth0
+      # ip -n b link add vxlan1 type vxlan id 1 local 10.1.0.2 \
+        remote 10.1.0.1 dev eth0 ttl 64 gbp
+      # ip -n b addr add 1.1.1.1/24 dev vxlan1
+      # ip -n b link set vxlan1 up
+      # ip -n b route add 2.1.1.0/24 dev vxlan1
+      # ip -n a link add vxlan1 type vxlan local 10.1.0.1 dev eth0 ttl 64 \
+        gbp external
+      # ip -n a addr add 2.1.1.1/24 dev vxlan1
+      # ip -n a link set vxlan1 up
+      # ip -n a route add 1.1.1.0/24 encap ip id 1 \
+        vxlan_opts 1110 dst 10.1.0.2 dev vxlan1
+      # ip -n a route show
+      # ip netns exec a ping 1.1.1.1 -c 1
+
+       1.1.1.0/24  encap ip id 1 src 0.0.0.0 dst 10.1.0.2 ttl 0 tos 0
+         vxlan_opts 1110 dev vxlan1 scope link
+
+       PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
+       64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=0.111 ms
+
+    v1->v2:
+      - improve the changelog.
+      - get_u32 with base = 0 for gbp.
+      - use PRINT_ANY to support dumping with json format.
+    v2->v3:
+      - implement proper JSON array for opts.
+    v3->v4:
+      - keep the same format between input and output, json and non json.
+      - print gbp as uint.
+
+    Signed-off-by: Xin Long <lucien.xin@gmail.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ ip/iproute_lwtunnel.c | 68 +++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 68 insertions(+)
+
+diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
+index 76d906c47c44f..17514dcad9219 100644
+--- a/ip/iproute_lwtunnel.c
++++ b/ip/iproute_lwtunnel.c
+@@ -330,6 +330,26 @@ static void lwtunnel_print_geneve_opts(struct rtattr *attr)
+ 	close_json_array(PRINT_JSON, name);
+ }
+ 
++static void lwtunnel_print_vxlan_opts(struct rtattr *attr)
++{
++	struct rtattr *tb[LWTUNNEL_IP_OPT_VXLAN_MAX + 1];
++	struct rtattr *i = RTA_DATA(attr);
++	int rem = RTA_PAYLOAD(attr);
++	char *name = "vxlan_opts";
++	__u32 gbp;
++
++	parse_rtattr(tb, LWTUNNEL_IP_OPT_VXLAN_MAX, i, rem);
++	gbp = rta_getattr_u32(tb[LWTUNNEL_IP_OPT_VXLAN_GBP]);
++
++	print_nl();
++	print_string(PRINT_FP, name, "\t%s ", name);
++	open_json_array(PRINT_JSON, name);
++	open_json_object(NULL);
++	print_uint(PRINT_ANY, "gbp", "%u ", gbp);
++	close_json_object();
++	close_json_array(PRINT_JSON, name);
++}
++
+ static void lwtunnel_print_opts(struct rtattr *attr)
+ {
+ 	struct rtattr *tb_opt[LWTUNNEL_IP_OPTS_MAX + 1];
+@@ -337,6 +357,8 @@ static void lwtunnel_print_opts(struct rtattr *attr)
+ 	parse_rtattr_nested(tb_opt, LWTUNNEL_IP_OPTS_MAX, attr);
+ 	if (tb_opt[LWTUNNEL_IP_OPTS_GENEVE])
+ 		lwtunnel_print_geneve_opts(tb_opt[LWTUNNEL_IP_OPTS_GENEVE]);
++	else if (tb_opt[LWTUNNEL_IP_OPTS_VXLAN])
++		lwtunnel_print_vxlan_opts(tb_opt[LWTUNNEL_IP_OPTS_VXLAN]);
+ }
+ 
+ static void print_encap_ip(FILE *fp, struct rtattr *encap)
+@@ -935,6 +957,22 @@ static int lwtunnel_parse_geneve_opts(char *str, size_t len, struct rtattr *rta)
+ 	return 0;
+ }
+ 
++static int lwtunnel_parse_vxlan_opts(char *str, size_t len, struct rtattr *rta)
++{
++	struct rtattr *nest;
++	__u32 gbp;
++	int err;
++
++	nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_VXLAN | NLA_F_NESTED);
++	err = get_u32(&gbp, str, 0);
++	if (err)
++		return err;
++	rta_addattr32(rta, len, LWTUNNEL_IP_OPT_VXLAN_GBP, gbp);
++
++	rta_nest_end(rta, nest);
++	return 0;
++}
++
+ static int parse_encap_ip(struct rtattr *rta, size_t len,
+ 			  int *argcp, char ***argvp)
+ {
+@@ -1006,6 +1044,21 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
+ 				invarg("\"geneve_opts\" value is invalid\n",
+ 				       *argv);
+ 			rta_nest_end(rta, nest);
++		} else if (strcmp(*argv, "vxlan_opts") == 0) {
++			struct rtattr *nest;
++
++			if (opts_ok++)
++				duparg2("opts", *argv);
++
++			NEXT_ARG();
++
++			nest = rta_nest(rta, len,
++					LWTUNNEL_IP_OPTS | NLA_F_NESTED);
++			ret = lwtunnel_parse_vxlan_opts(*argv, len, rta);
++			if (ret)
++				invarg("\"vxlan_opts\" value is invalid\n",
++				       *argv);
++			rta_nest_end(rta, nest);
+ 		} else if (strcmp(*argv, "key") == 0) {
+ 			if (key_ok++)
+ 				duparg2("key", *argv);
+@@ -1190,6 +1243,21 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
+ 				invarg("\"geneve_opts\" value is invalid\n",
+ 				       *argv);
+ 			rta_nest_end(rta, nest);
++		} else if (strcmp(*argv, "vxlan_opts") == 0) {
++			struct rtattr *nest;
++
++			if (opts_ok++)
++				duparg2("opts", *argv);
++
++			NEXT_ARG();
++
++			nest = rta_nest(rta, len,
++					LWTUNNEL_IP_OPTS | NLA_F_NESTED);
++			ret = lwtunnel_parse_vxlan_opts(*argv, len, rta);
++			if (ret)
++				invarg("\"vxlan_opts\" value is invalid\n",
++				       *argv);
++			rta_nest_end(rta, nest);
+ 		} else if (strcmp(*argv, "key") == 0) {
+ 			if (key_ok++)
+ 				duparg2("key", *argv);
+-- 
+2.26.2
+
diff --git a/SOURCES/0026-iproute_lwtunnel-add-options-support-for-erspan-meta.patch b/SOURCES/0026-iproute_lwtunnel-add-options-support-for-erspan-meta.patch
new file mode 100644
index 0000000..d9f0bb6
--- /dev/null
+++ b/SOURCES/0026-iproute_lwtunnel-add-options-support-for-erspan-meta.patch
@@ -0,0 +1,246 @@
+From 3628115b53f7b693f623638fb5ec71bc292a3a00 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 21:43:01 +0200
+Subject: [PATCH] iproute_lwtunnel: add options support for erspan metadata
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485
+Upstream Status: unknown commit 39fa047938fbe
+
+commit 39fa047938fbef6cd08687b0daa4d86afbfdc61c
+Author: Xin Long <lucien.xin@gmail.com>
+Date:   Mon Apr 27 18:27:47 2020 +0800
+
+    iproute_lwtunnel: add options support for erspan metadata
+
+    This patch is to add LWTUNNEL_IP_OPTS_ERSPAN's parse and print to implement
+    erspan options support in iproute_lwtunnel.
+
+    Option is expressed as version:index:dir:hwid, dir and hwid will be parsed
+    when version is 2, while index will be parsed when version is 1. All of
+    these are numbers. erspan doesn't support multiple options.
+
+    With this patch, users can add and dump erspan options like:
+
+      # ip netns add a
+      # ip netns add b
+      # ip -n a link add eth0 type veth peer name eth0 netns b
+      # ip -n a link set eth0 up
+      # ip -n b link set eth0 up
+      # ip -n a addr add 10.1.0.1/24 dev eth0
+      # ip -n b addr add 10.1.0.2/24 dev eth0
+      # ip -n b link add erspan1 type erspan key 1 seq erspan 123 \
+        local 10.1.0.2 remote 10.1.0.1
+      # ip -n b addr add 1.1.1.1/24 dev erspan1
+      # ip -n b link set erspan1 up
+      # ip -n b route add 2.1.1.0/24 dev erspan1
+      # ip -n a link add erspan1 type erspan key 1 seq local 10.1.0.1 external
+      # ip -n a addr add 2.1.1.1/24 dev erspan1
+      # ip -n a link set erspan1 up
+      # ip -n a route add 1.1.1.0/24 encap ip id 1 \
+        erspan_opts 2:123:1:2 dst 10.1.0.2 dev erspan1
+      # ip -n a route show
+      # ip netns exec a ping 1.1.1.1 -c 1
+
+       1.1.1.0/24  encap ip id 1 src 0.0.0.0 dst 10.1.0.2 ttl 0 tos 0
+         erspan_opts 2:0:1:2 dev erspan1 scope link
+
+       PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
+       64 bytes from 1.1.1.1: icmp_seq=1 ttl=64 time=0.124 ms
+
+    v1->v2:
+      - improve the changelog.
+      - use PRINT_ANY to support dumping with json format.
+    v2->v3:
+      - implement proper JSON object for opts instead of just bunch of strings.
+    v3->v4:
+      - keep the same format between input and output, json and non json.
+      - print version, index, dir and hwid as uint.
+
+    Signed-off-by: Xin Long <lucien.xin@gmail.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ ip/iproute_lwtunnel.c | 140 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 140 insertions(+)
+
+diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
+index 17514dcad9219..7e145768c111f 100644
+--- a/ip/iproute_lwtunnel.c
++++ b/ip/iproute_lwtunnel.c
+@@ -350,6 +350,38 @@ static void lwtunnel_print_vxlan_opts(struct rtattr *attr)
+ 	close_json_array(PRINT_JSON, name);
+ }
+ 
++static void lwtunnel_print_erspan_opts(struct rtattr *attr)
++{
++	struct rtattr *tb[LWTUNNEL_IP_OPT_ERSPAN_MAX + 1];
++	struct rtattr *i = RTA_DATA(attr);
++	char *name = "erspan_opts";
++	__u8 ver, hwid, dir;
++	__u32 idx;
++
++	parse_rtattr(tb, LWTUNNEL_IP_OPT_ERSPAN_MAX, i, RTA_PAYLOAD(attr));
++	ver = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_VER]);
++	if (ver == 1) {
++		idx = rta_getattr_be32(tb[LWTUNNEL_IP_OPT_ERSPAN_INDEX]);
++		dir = 0;
++		hwid = 0;
++	} else {
++		idx = 0;
++		dir = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_DIR]);
++		hwid = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_HWID]);
++	}
++
++	print_nl();
++	print_string(PRINT_FP, name, "\t%s ", name);
++	open_json_array(PRINT_JSON, name);
++	open_json_object(NULL);
++	print_uint(PRINT_ANY, "ver", "%u", ver);
++	print_uint(PRINT_ANY, "index", ":%u", idx);
++	print_uint(PRINT_ANY, "dir", ":%u", dir);
++	print_uint(PRINT_ANY, "hwid", ":%u ", hwid);
++	close_json_object();
++	close_json_array(PRINT_JSON, name);
++}
++
+ static void lwtunnel_print_opts(struct rtattr *attr)
+ {
+ 	struct rtattr *tb_opt[LWTUNNEL_IP_OPTS_MAX + 1];
+@@ -359,6 +391,8 @@ static void lwtunnel_print_opts(struct rtattr *attr)
+ 		lwtunnel_print_geneve_opts(tb_opt[LWTUNNEL_IP_OPTS_GENEVE]);
+ 	else if (tb_opt[LWTUNNEL_IP_OPTS_VXLAN])
+ 		lwtunnel_print_vxlan_opts(tb_opt[LWTUNNEL_IP_OPTS_VXLAN]);
++	else if (tb_opt[LWTUNNEL_IP_OPTS_ERSPAN])
++		lwtunnel_print_erspan_opts(tb_opt[LWTUNNEL_IP_OPTS_ERSPAN]);
+ }
+ 
+ static void print_encap_ip(FILE *fp, struct rtattr *encap)
+@@ -973,6 +1007,82 @@ static int lwtunnel_parse_vxlan_opts(char *str, size_t len, struct rtattr *rta)
+ 	return 0;
+ }
+ 
++static int lwtunnel_parse_erspan_opts(char *str, size_t len, struct rtattr *rta)
++{
++	struct rtattr *nest;
++	char *token;
++	int i, err;
++
++	nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_ERSPAN | NLA_F_NESTED);
++	i = 1;
++	token = strsep(&str, ":");
++	while (token) {
++		switch (i) {
++		case LWTUNNEL_IP_OPT_ERSPAN_VER:
++		{
++			__u8 opt_type;
++
++			if (!strlen(token))
++				break;
++			err = get_u8(&opt_type, token, 0);
++			if (err)
++				return err;
++
++			rta_addattr8(rta, len, i, opt_type);
++			break;
++		}
++		case LWTUNNEL_IP_OPT_ERSPAN_INDEX:
++		{
++			__be32 opt_class;
++
++			if (!strlen(token))
++				break;
++			err = get_be32(&opt_class, token, 0);
++			if (err)
++				return err;
++
++			rta_addattr32(rta, len, i, opt_class);
++			break;
++		}
++		case LWTUNNEL_IP_OPT_ERSPAN_DIR:
++		{
++			__u8 opt_type;
++
++			if (!strlen(token))
++				break;
++			err = get_u8(&opt_type, token, 0);
++			if (err)
++				return err;
++
++			rta_addattr8(rta, len, i, opt_type);
++			break;
++		}
++		case LWTUNNEL_IP_OPT_ERSPAN_HWID:
++		{
++			__u8 opt_type;
++
++			if (!strlen(token))
++				break;
++			err = get_u8(&opt_type, token, 0);
++			if (err)
++				return err;
++
++			rta_addattr8(rta, len, i, opt_type);
++			break;
++		}
++		default:
++			fprintf(stderr, "Unknown \"geneve_opts\" type\n");
++			return -1;
++		}
++
++		token = strsep(&str, ":");
++		i++;
++	}
++
++	rta_nest_end(rta, nest);
++	return 0;
++}
++
+ static int parse_encap_ip(struct rtattr *rta, size_t len,
+ 			  int *argcp, char ***argvp)
+ {
+@@ -1059,6 +1169,21 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
+ 				invarg("\"vxlan_opts\" value is invalid\n",
+ 				       *argv);
+ 			rta_nest_end(rta, nest);
++		} else if (strcmp(*argv, "erspan_opts") == 0) {
++			struct rtattr *nest;
++
++			if (opts_ok++)
++				duparg2("opts", *argv);
++
++			NEXT_ARG();
++
++			nest = rta_nest(rta, len,
++					LWTUNNEL_IP_OPTS | NLA_F_NESTED);
++			ret = lwtunnel_parse_erspan_opts(*argv, len, rta);
++			if (ret)
++				invarg("\"erspan_opts\" value is invalid\n",
++				       *argv);
++			rta_nest_end(rta, nest);
+ 		} else if (strcmp(*argv, "key") == 0) {
+ 			if (key_ok++)
+ 				duparg2("key", *argv);
+@@ -1258,6 +1383,21 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
+ 				invarg("\"vxlan_opts\" value is invalid\n",
+ 				       *argv);
+ 			rta_nest_end(rta, nest);
++		} else if (strcmp(*argv, "erspan_opts") == 0) {
++			struct rtattr *nest;
++
++			if (opts_ok++)
++				duparg2("opts", *argv);
++
++			NEXT_ARG();
++
++			nest = rta_nest(rta, len,
++					LWTUNNEL_IP_OPTS | NLA_F_NESTED);
++			ret = lwtunnel_parse_erspan_opts(*argv, len, rta);
++			if (ret)
++				invarg("\"erspan_opts\" value is invalid\n",
++				       *argv);
++			rta_nest_end(rta, nest);
+ 		} else if (strcmp(*argv, "key") == 0) {
+ 			if (key_ok++)
+ 				duparg2("key", *argv);
+-- 
+2.26.2
+
diff --git a/SOURCES/0027-tc-m_tunnel_key-add-options-support-for-vxlan.patch b/SOURCES/0027-tc-m_tunnel_key-add-options-support-for-vxlan.patch
new file mode 100644
index 0000000..b86d0b3
--- /dev/null
+++ b/SOURCES/0027-tc-m_tunnel_key-add-options-support-for-vxlan.patch
@@ -0,0 +1,258 @@
+From f970b592af7421ce932a788a6a14161c351d75e0 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 21:43:01 +0200
+Subject: [PATCH] tc: m_tunnel_key: add options support for vxlan
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485
+Upstream Status: unknown commit f72c3ad00f3b7
+Conflicts: context change due to missing commit 7b0d424abef16
+           ("tc: do not output newline in oneline mode")
+
+commit f72c3ad00f3b7869e90840d0098a83cb88224892
+Author: Xin Long <lucien.xin@gmail.com>
+Date:   Mon Apr 27 18:27:48 2020 +0800
+
+    tc: m_tunnel_key: add options support for vxlan
+
+    This patch is to add TCA_TUNNEL_KEY_ENC_OPTS_VXLAN's parse and
+    print to implement vxlan options support in m_tunnel_key, like
+    Commit 6217917a3826 ("tc: m_tunnel_key: Add tunnel option support
+    to act_tunnel_key") for geneve options support.
+
+    Option is expressed a 32bit number for gbp only, and vxlan
+    doesn't support multiple options.
+
+    With this patch, users can add and dump vxlan options like:
+
+      # ip link add name vxlan1 type vxlan dstport 0 external
+      # tc qdisc add dev eth0 ingress
+      # tc filter add dev eth0 protocol ip parent ffff: \
+          flower indev eth0 \
+            ip_proto udp \
+            action tunnel_key \
+              set src_ip 10.0.99.192 \
+              dst_ip 10.0.99.193 \
+              dst_port 6081 \
+              id 11 \
+              vxlan_opts 65793 \
+          action mirred egress redirect dev vxlan1
+      # tc -s filter show dev eth0 parent ffff:
+
+         filter protocol ip pref 49152 flower chain 0 handle 0x1
+           indev eth0
+           eth_type ipv4
+           ip_proto udp
+           not_in_hw
+             action order 1: tunnel_key  set
+             src_ip 10.0.99.192
+             dst_ip 10.0.99.193
+             key_id 11
+             dst_port 6081
+             vxlan_opts 65793
+             ...
+
+    v1->v2:
+      - get_u32 with base = 0 for gbp.
+      - use to print_unint("0x%x") to print gbp.
+    v2->v3:
+      - implement proper JSON array for opts.
+    v3->v4:
+      - keep the same format between input and output, json and non json.
+      - print gbp as uint.
+
+    Signed-off-by: Xin Long <lucien.xin@gmail.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ man/man8/tc-tunnel_key.8 | 10 ++++-
+ tc/m_tunnel_key.c        | 85 +++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 85 insertions(+), 10 deletions(-)
+
+diff --git a/man/man8/tc-tunnel_key.8 b/man/man8/tc-tunnel_key.8
+index 2145eb62e70e2..c208e2c82a181 100644
+--- a/man/man8/tc-tunnel_key.8
++++ b/man/man8/tc-tunnel_key.8
+@@ -66,8 +66,10 @@ options.
+ .B id
+ ,
+ .B dst_port
+-and
++,
+ .B geneve_opts
++and
++.B vxlan_opts
+ are optional.
+ .RS
+ .TP
+@@ -91,6 +93,12 @@ is specified in the form CLASS:TYPE:DATA, where CLASS is represented as a
+ variable length hexadecimal value. Additionally multiple options may be
+ listed using a comma delimiter.
+ .TP
++.B vxlan_opts
++Vxlan metatdata options.
++.B vxlan_opts
++is specified in the form GBP, as a 32bit number. Multiple options is not
++supported.
++.TP
+ .B tos
+ Outer header TOS
+ .TP
+diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c
+index 4e65e444776a2..76391d6c85fb2 100644
+--- a/tc/m_tunnel_key.c
++++ b/tc/m_tunnel_key.c
+@@ -29,7 +29,7 @@ static void explain(void)
+ 		"src_ip <IP> (mandatory)\n"
+ 		"dst_ip <IP> (mandatory)\n"
+ 		"dst_port <UDP_PORT>\n"
+-		"geneve_opts <OPTIONS>\n"
++		"geneve_opts | vxlan_opts <OPTIONS>\n"
+ 		"csum | nocsum (default is \"csum\")\n");
+ }
+ 
+@@ -112,6 +112,21 @@ static int tunnel_key_parse_u8(char *str, int base, int type,
+ 	return 0;
+ }
+ 
++static int tunnel_key_parse_u32(char *str, int base, int type,
++				struct nlmsghdr *n)
++{
++	__u32 value;
++	int ret;
++
++	ret = get_u32(&value, str, base);
++	if (ret)
++		return ret;
++
++	addattr32(n, MAX_MSG, type, value);
++
++	return 0;
++}
++
+ static int tunnel_key_parse_geneve_opt(char *str, struct nlmsghdr *n)
+ {
+ 	char *token, *saveptr = NULL;
+@@ -190,6 +205,27 @@ static int tunnel_key_parse_geneve_opts(char *str, struct nlmsghdr *n)
+ 	return 0;
+ }
+ 
++static int tunnel_key_parse_vxlan_opt(char *str, struct nlmsghdr *n)
++{
++	struct rtattr *encap, *nest;
++	int ret;
++
++	encap = addattr_nest(n, MAX_MSG,
++			     TCA_TUNNEL_KEY_ENC_OPTS | NLA_F_NESTED);
++	nest = addattr_nest(n, MAX_MSG,
++			    TCA_TUNNEL_KEY_ENC_OPTS_VXLAN | NLA_F_NESTED);
++
++	ret = tunnel_key_parse_u32(str, 0,
++				   TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, n);
++	if (ret)
++		return ret;
++
++	addattr_nest_end(n, nest);
++	addattr_nest_end(n, encap);
++
++	return 0;
++}
++
+ static int tunnel_key_parse_tos_ttl(char *str, int type, struct nlmsghdr *n)
+ {
+ 	int ret;
+@@ -287,6 +323,13 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
+ 				fprintf(stderr, "Illegal \"geneve_opts\"\n");
+ 				return -1;
+ 			}
++		} else if (matches(*argv, "vxlan_opts") == 0) {
++			NEXT_ARG();
++
++			if (tunnel_key_parse_vxlan_opt(*argv, n)) {
++				fprintf(stderr, "Illegal \"vxlan_opts\"\n");
++				return -1;
++			}
+ 		} else if (matches(*argv, "tos") == 0) {
+ 			NEXT_ARG();
+ 			ret = tunnel_key_parse_tos_ttl(*argv,
+@@ -406,13 +449,13 @@ static void tunnel_key_print_flag(FILE *f, const char *name_on,
+ 		     rta_getattr_u8(attr) ? name_on : name_off);
+ }
+ 
+-static void tunnel_key_print_geneve_options(const char *name,
+-					    struct rtattr *attr)
++static void tunnel_key_print_geneve_options(struct rtattr *attr)
+ {
+ 	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1];
+ 	struct rtattr *i = RTA_DATA(attr);
+ 	int ii, data_len = 0, offset = 0;
+ 	int rem = RTA_PAYLOAD(attr);
++	char *name = "geneve_opts";
+ 	char strbuf[rem * 2 + 1];
+ 	char data[rem * 2 + 1];
+ 	uint8_t data_r[rem];
+@@ -420,7 +463,8 @@ static void tunnel_key_print_geneve_options(const char *name,
+ 	uint8_t type;
+ 
+ 	open_json_array(PRINT_JSON, name);
+-	print_string(PRINT_FP, name, "\n\t%s ", "geneve_opt");
++	print_nl();
++	print_string(PRINT_FP, name, "\t%s ", name);
+ 
+ 	while (rem) {
+ 		parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, i, rem);
+@@ -453,7 +497,27 @@ static void tunnel_key_print_geneve_options(const char *name,
+ 	close_json_array(PRINT_JSON, name);
+ }
+ 
+-static void tunnel_key_print_key_opt(const char *name, struct rtattr *attr)
++static void tunnel_key_print_vxlan_options(struct rtattr *attr)
++{
++	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1];
++	struct rtattr *i = RTA_DATA(attr);
++	int rem = RTA_PAYLOAD(attr);
++	char *name = "vxlan_opts";
++	__u32 gbp;
++
++	parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX, i, rem);
++	gbp = rta_getattr_u32(tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]);
++
++	print_nl();
++	print_string(PRINT_FP, name, "\t%s ", name);
++	open_json_array(PRINT_JSON, name);
++	open_json_object(NULL);
++	print_uint(PRINT_ANY, "gbp", "%u", gbp);
++	close_json_object();
++	close_json_array(PRINT_JSON, name);
++}
++
++static void tunnel_key_print_key_opt(struct rtattr *attr)
+ {
+ 	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1];
+ 
+@@ -461,8 +525,12 @@ static void tunnel_key_print_key_opt(const char *name, struct rtattr *attr)
+ 		return;
+ 
+ 	parse_rtattr_nested(tb, TCA_TUNNEL_KEY_ENC_OPTS_MAX, attr);
+-	tunnel_key_print_geneve_options(name,
+-					tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]);
++	if (tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE])
++		tunnel_key_print_geneve_options(
++			tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]);
++	else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN])
++		tunnel_key_print_vxlan_options(
++			tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]);
+ }
+ 
+ static void tunnel_key_print_tos_ttl(FILE *f, char *name,
+@@ -518,8 +586,7 @@ static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
+ 					tb[TCA_TUNNEL_KEY_ENC_KEY_ID]);
+ 		tunnel_key_print_dst_port(f, "dst_port",
+ 					  tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);
+-		tunnel_key_print_key_opt("geneve_opts",
+-					 tb[TCA_TUNNEL_KEY_ENC_OPTS]);
++		tunnel_key_print_key_opt(tb[TCA_TUNNEL_KEY_ENC_OPTS]);
+ 		tunnel_key_print_flag(f, "nocsum", "csum",
+ 				      tb[TCA_TUNNEL_KEY_NO_CSUM]);
+ 		tunnel_key_print_tos_ttl(f, "tos",
+-- 
+2.26.2
+
diff --git a/SOURCES/0028-tc-m_tunnel_key-add-options-support-for-erpsan.patch b/SOURCES/0028-tc-m_tunnel_key-add-options-support-for-erpsan.patch
new file mode 100644
index 0000000..5dfebf0
--- /dev/null
+++ b/SOURCES/0028-tc-m_tunnel_key-add-options-support-for-erpsan.patch
@@ -0,0 +1,265 @@
+From 2fb8c115a8031d893fff588181cc42764391e4d5 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 21:43:50 +0200
+Subject: [PATCH] tc: m_tunnel_key: add options support for erpsan
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485
+Upstream Status: unknown commit 668fd9b25d9ec
+
+commit 668fd9b25d9eca3067040273239f7825db95442b
+Author: Xin Long <lucien.xin@gmail.com>
+Date:   Mon Apr 27 18:27:49 2020 +0800
+
+    tc: m_tunnel_key: add options support for erpsan
+
+    This patch is to add TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN's parse and
+    print to implement erspan options support in m_tunnel_key, like
+    Commit 6217917a3826 ("tc: m_tunnel_key: Add tunnel option support
+    to act_tunnel_key") for geneve options support.
+
+    Option is expressed as version:index:dir:hwid, dir and hwid will
+    be parsed when version is 2, while index will be parsed when
+    version is 1. erspan doesn't support multiple options.
+
+    With this patch, users can add and dump erspan options like:
+
+      # ip link add name erspan1 type erspan external
+      # tc qdisc add dev eth0 ingress
+      # tc filter add dev eth0 protocol ip parent ffff: \
+          flower indev eth0 \
+            ip_proto udp \
+            action tunnel_key \
+              set src_ip 10.0.99.192 \
+              dst_ip 10.0.99.193 \
+              dst_port 6081 \
+              id 11 \
+              erspan_opts 1:2:0:0 \
+          action mirred egress redirect dev erspan1
+      # tc -s filter show dev eth0 parent ffff:
+
+         filter protocol ip pref 49151 flower chain 0 handle 0x1
+           indev eth0
+           eth_type ipv4
+           ip_proto udp
+           not_in_hw
+             action order 1: tunnel_key  set
+             src_ip 10.0.99.192
+             dst_ip 10.0.99.193
+             key_id 11
+             dst_port 6081
+             erspan_opts 1:2:0:0
+             csum pipe
+               index 2 ref 1 bind 1
+             ...
+    v1->v2:
+      - no change.
+    v2->v3:
+      - no change.
+    v3->v4:
+      - keep the same format between input and output, json and non json.
+      - print version, index, dir and hwid as uint.
+
+    Signed-off-by: Xin Long <lucien.xin@gmail.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ man/man8/tc-tunnel_key.8 |  12 +++-
+ tc/m_tunnel_key.c        | 117 ++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 127 insertions(+), 2 deletions(-)
+
+diff --git a/man/man8/tc-tunnel_key.8 b/man/man8/tc-tunnel_key.8
+index c208e2c82a181..ad9972402c0e5 100644
+--- a/man/man8/tc-tunnel_key.8
++++ b/man/man8/tc-tunnel_key.8
+@@ -68,8 +68,10 @@ options.
+ .B dst_port
+ ,
+ .B geneve_opts
+-and
++,
+ .B vxlan_opts
++and
++.B erspan_opts
+ are optional.
+ .RS
+ .TP
+@@ -99,6 +101,14 @@ Vxlan metatdata options.
+ is specified in the form GBP, as a 32bit number. Multiple options is not
+ supported.
+ .TP
++.B erspan_opts
++Erspan metatdata options.
++.B erspan_opts
++is specified in the form VERSION:INDEX:DIR:HWID, where VERSION is represented
++as a 8bit number, INDEX as an 32bit number, DIR and HWID as a 8bit number.
++Multiple options is not supported. Note INDEX is used when VERSION is 1,
++and DIR and HWID are used when VERSION is 2.
++.TP
+ .B tos
+ Outer header TOS
+ .TP
+diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c
+index 76391d6c85fb2..a56fe24413fa0 100644
+--- a/tc/m_tunnel_key.c
++++ b/tc/m_tunnel_key.c
+@@ -29,7 +29,7 @@ static void explain(void)
+ 		"src_ip <IP> (mandatory)\n"
+ 		"dst_ip <IP> (mandatory)\n"
+ 		"dst_port <UDP_PORT>\n"
+-		"geneve_opts | vxlan_opts <OPTIONS>\n"
++		"geneve_opts | vxlan_opts | erspan_opts <OPTIONS>\n"
+ 		"csum | nocsum (default is \"csum\")\n");
+ }
+ 
+@@ -97,6 +97,21 @@ static int tunnel_key_parse_be16(char *str, int base, int type,
+ 	return 0;
+ }
+ 
++static int tunnel_key_parse_be32(char *str, int base, int type,
++				 struct nlmsghdr *n)
++{
++	__be32 value;
++	int ret;
++
++	ret = get_be32(&value, str, base);
++	if (ret)
++		return ret;
++
++	addattr32(n, MAX_MSG, type, value);
++
++	return 0;
++}
++
+ static int tunnel_key_parse_u8(char *str, int base, int type,
+ 			       struct nlmsghdr *n)
+ {
+@@ -226,6 +241,63 @@ static int tunnel_key_parse_vxlan_opt(char *str, struct nlmsghdr *n)
+ 	return 0;
+ }
+ 
++static int tunnel_key_parse_erspan_opt(char *str, struct nlmsghdr *n)
++{
++	char *token, *saveptr = NULL;
++	struct rtattr *encap, *nest;
++	int i, ret;
++
++	encap = addattr_nest(n, MAX_MSG,
++			     TCA_TUNNEL_KEY_ENC_OPTS | NLA_F_NESTED);
++	nest = addattr_nest(n, MAX_MSG,
++			    TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN | NLA_F_NESTED);
++
++	token = strtok_r(str, ":", &saveptr);
++	i = 1;
++	while (token) {
++		switch (i) {
++		case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER:
++		{
++			ret = tunnel_key_parse_u8(token, 0, i, n);
++			if (ret)
++				return ret;
++			break;
++		}
++		case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX:
++		{
++			ret = tunnel_key_parse_be32(token, 0, i, n);
++			if (ret)
++				return ret;
++			break;
++		}
++		case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR:
++		{
++			ret = tunnel_key_parse_u8(token, 0, i, n);
++			if (ret)
++				return ret;
++			break;
++		}
++		case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID:
++		{
++			ret = tunnel_key_parse_u8(token, 0, i, n);
++			if (ret)
++				return ret;
++			break;
++		}
++		default:
++			return -1;
++		}
++
++		token = strtok_r(NULL, ":", &saveptr);
++		i++;
++	}
++
++	addattr_nest_end(n, nest);
++	addattr_nest_end(n, encap);
++
++	return 0;
++}
++
+ static int tunnel_key_parse_tos_ttl(char *str, int type, struct nlmsghdr *n)
+ {
+ 	int ret;
+@@ -330,6 +402,13 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
+ 				fprintf(stderr, "Illegal \"vxlan_opts\"\n");
+ 				return -1;
+ 			}
++		} else if (matches(*argv, "erspan_opts") == 0) {
++			NEXT_ARG();
++
++			if (tunnel_key_parse_erspan_opt(*argv, n)) {
++				fprintf(stderr, "Illegal \"erspan_opts\"\n");
++				return -1;
++			}
+ 		} else if (matches(*argv, "tos") == 0) {
+ 			NEXT_ARG();
+ 			ret = tunnel_key_parse_tos_ttl(*argv,
+@@ -517,6 +596,39 @@ static void tunnel_key_print_vxlan_options(struct rtattr *attr)
+ 	close_json_array(PRINT_JSON, name);
+ }
+ 
++static void tunnel_key_print_erspan_options(struct rtattr *attr)
++{
++	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1];
++	struct rtattr *i = RTA_DATA(attr);
++	int rem = RTA_PAYLOAD(attr);
++	char *name = "erspan_opts";
++	__u8 ver, hwid, dir;
++	__u32 idx;
++
++	parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX, i, rem);
++	ver = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]);
++	if (ver == 1) {
++		idx = rta_getattr_be32(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]);
++		dir = 0;
++		hwid = 0;
++	} else {
++		idx = 0;
++		dir = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR]);
++		hwid = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]);
++	}
++
++	print_nl();
++	print_string(PRINT_FP, name, "\t%s ", name);
++	open_json_array(PRINT_JSON, name);
++	open_json_object(NULL);
++	print_uint(PRINT_ANY, "ver", "%u", ver);
++	print_uint(PRINT_ANY, "index", ":%u", idx);
++	print_uint(PRINT_ANY, "dir", ":%u", dir);
++	print_uint(PRINT_ANY, "hwid", ":%u", hwid);
++	close_json_object();
++	close_json_array(PRINT_JSON, name);
++}
++
+ static void tunnel_key_print_key_opt(struct rtattr *attr)
+ {
+ 	struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1];
+@@ -531,6 +643,9 @@ static void tunnel_key_print_key_opt(struct rtattr *attr)
+ 	else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN])
+ 		tunnel_key_print_vxlan_options(
+ 			tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]);
++	else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN])
++		tunnel_key_print_erspan_options(
++			tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN]);
+ }
+ 
+ static void tunnel_key_print_tos_ttl(FILE *f, char *name,
+-- 
+2.26.2
+
diff --git a/SOURCES/0029-tc-f_flower-add-options-support-for-vxlan.patch b/SOURCES/0029-tc-f_flower-add-options-support-for-vxlan.patch
new file mode 100644
index 0000000..0de0f70
--- /dev/null
+++ b/SOURCES/0029-tc-f_flower-add-options-support-for-vxlan.patch
@@ -0,0 +1,316 @@
+From 4bd1eb80a195ce1a64e33f5fc9d5c58bf9f30c8d Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 21:43:50 +0200
+Subject: [PATCH] tc: f_flower: add options support for vxlan
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485
+Upstream Status: unknown commit 93c8d5f72f8ce
+Conflicts: on a removed line due to missing commit 93c8d5f72f8ce
+           ("tc: f_flower: add options support for vxlan")
+
+commit 93c8d5f72f8ce4b98c68508e85457f83933302c0
+Author: Xin Long <lucien.xin@gmail.com>
+Date:   Mon Apr 27 18:27:50 2020 +0800
+
+    tc: f_flower: add options support for vxlan
+
+    This patch is to add TCA_FLOWER_KEY_ENC_OPTS_VXLAN's parse and
+    print to implement vxlan options support in m_tunnel_key, like
+    Commit 56155d4df86d ("tc: f_flower: add geneve option match
+    support to flower") for geneve options support.
+
+    Option is expressed a 32bit number for gbp only, and vxlan
+    doesn't support multiple options.
+
+    With this patch, users can add and dump vxlan options like:
+
+      # ip link add name vxlan1 type vxlan dstport 0 external
+      # tc qdisc add dev vxlan1 ingress
+      # tc filter add dev vxlan1 protocol ip parent ffff: \
+          flower \
+            enc_src_ip 10.0.99.192 \
+            enc_dst_ip 10.0.99.193 \
+            enc_key_id 11 \
+            vxlan_opts 65793/4008635966 \
+            ip_proto udp \
+            action mirred egress redirect dev eth1
+      # tc -s filter show dev vxlan1 parent ffff:
+
+         filter protocol ip pref 49152 flower chain 0 handle 0x1
+           eth_type ipv4
+           ip_proto udp
+           enc_dst_ip 10.0.99.193
+           enc_src_ip 10.0.99.192
+           enc_key_id 11
+           vxlan_opts 65793/4008635966
+           not_in_hw
+             action order 1: mirred (Egress Redirect to device eth1) stolen
+             index 3 ref 1 bind 1
+             Action statistics:
+             Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
+             backlog 0b 0p requeues 0
+
+    v1->v2:
+      - get_u32 with base = 0 for gbp.
+    v2->v3:
+      - implement proper JSON array for opts.
+    v3->v4:
+      - keep the same format between input and output, json and non json.
+      - print gbp as uint.
+
+    Signed-off-by: Xin Long <lucien.xin@gmail.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ man/man8/tc-flower.8 |  12 ++++
+ tc/f_flower.c        | 130 +++++++++++++++++++++++++++++++++++++------
+ 2 files changed, 126 insertions(+), 16 deletions(-)
+
+diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
+index adff41e39b006..0efacbfdf9a95 100644
+--- a/man/man8/tc-flower.8
++++ b/man/man8/tc-flower.8
+@@ -81,7 +81,11 @@ flower \- flow based traffic control filter
+ .IR TOS " | "
+ .B enc_ttl
+ .IR TTL " | "
++{
+ .B geneve_opts
++|
++.B vxlan_opts
++}
+ .IR OPTIONS " | "
+ .BR ip_flags
+ .IR IP_FLAGS
+@@ -290,6 +294,8 @@ bits is assumed.
+ .BI enc_ttl " NUMBER"
+ .TQ
+ .BI geneve_opts " OPTIONS"
++.TQ
++.BI vxlan_opts " OPTIONS"
+ Match on IP tunnel metadata. Key id
+ .I NUMBER
+ is a 32 bit tunnel key id (e.g. VNI for VXLAN tunnel).
+@@ -310,6 +316,12 @@ the masks is missing, \fBtc\fR assumes a full-length match. The options can
+ be described in the form CLASS:TYPE:DATA/CLASS_MASK:TYPE_MASK:DATA_MASK,
+ where CLASS is represented as a 16bit hexadecimal value, TYPE as an 8bit
+ hexadecimal value and DATA as a variable length hexadecimal value.
++vxlan_opts
++.I OPTIONS
++doesn't support multiple options, and it consists of a key followed by a slash
++and corresponding mask. If the mask is missing, \fBtc\fR assumes a full-length
++match. The option can be described in the form GBP/GBP_MASK, where GBP is
++represented as a 32bit number.
+ .TP
+ .BI ip_flags " IP_FLAGS"
+ .I IP_FLAGS
+diff --git a/tc/f_flower.c b/tc/f_flower.c
+index 70d40d3b2f2bf..09079cd2c2280 100644
+--- a/tc/f_flower.c
++++ b/tc/f_flower.c
+@@ -81,6 +81,7 @@ static void explain(void)
+ 		"			enc_tos MASKED-IP_TOS |\n"
+ 		"			enc_ttl MASKED-IP_TTL |\n"
+ 		"			geneve_opts MASKED-OPTIONS |\n"
++		"			vxlan_opts MASKED-OPTIONS |\n"
+ 		"			ip_flags IP-FLAGS | \n"
+ 		"			enc_dst_port [ port_number ] }\n"
+ 		"	FILTERID := X:Y:Z\n"
+@@ -648,7 +649,7 @@ static int flower_parse_enc_port(char *str, int type, struct nlmsghdr *n)
+ 	return 0;
+ }
+ 
+-static int flower_parse_geneve_opts(char *str, struct nlmsghdr *n)
++static int flower_parse_geneve_opt(char *str, struct nlmsghdr *n)
+ {
+ 	struct rtattr *nest;
+ 	char *token;
+@@ -718,14 +719,33 @@ static int flower_parse_geneve_opts(char *str, struct nlmsghdr *n)
+ 	return 0;
+ }
+ 
+-static int flower_parse_enc_opt_part(char *str, struct nlmsghdr *n)
++static int flower_parse_vxlan_opt(char *str, struct nlmsghdr *n)
++{
++	struct rtattr *nest;
++	__u32 gbp;
++	int err;
++
++	nest = addattr_nest(n, MAX_MSG,
++			    TCA_FLOWER_KEY_ENC_OPTS_VXLAN | NLA_F_NESTED);
++
++	err = get_u32(&gbp, str, 0);
++	if (err)
++		return err;
++	addattr32(n, MAX_MSG, TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP, gbp);
++
++	addattr_nest_end(n, nest);
++
++	return 0;
++}
++
++static int flower_parse_geneve_opts(char *str, struct nlmsghdr *n)
+ {
+ 	char *token;
+ 	int err;
+ 
+ 	token = strsep(&str, ",");
+ 	while (token) {
+-		err = flower_parse_geneve_opts(token, n);
++		err = flower_parse_geneve_opt(token, n);
+ 		if (err)
+ 			return err;
+ 
+@@ -755,7 +775,7 @@ static int flower_check_enc_opt_key(char *key)
+ 	return 0;
+ }
+ 
+-static int flower_parse_enc_opts(char *str, struct nlmsghdr *n)
++static int flower_parse_enc_opts_geneve(char *str, struct nlmsghdr *n)
+ {
+ 	char key[XATTR_SIZE_MAX], mask[XATTR_SIZE_MAX];
+ 	int data_len, key_len, mask_len, err;
+@@ -807,13 +827,50 @@ static int flower_parse_enc_opts(char *str, struct nlmsghdr *n)
+ 	mask[mask_len - 1] = '\0';
+ 
+ 	nest = addattr_nest(n, MAX_MSG, TCA_FLOWER_KEY_ENC_OPTS);
+-	err = flower_parse_enc_opt_part(key, n);
++	err = flower_parse_geneve_opts(key, n);
+ 	if (err)
+ 		return err;
+ 	addattr_nest_end(n, nest);
+ 
+ 	nest = addattr_nest(n, MAX_MSG, TCA_FLOWER_KEY_ENC_OPTS_MASK);
+-	err = flower_parse_enc_opt_part(mask, n);
++	err = flower_parse_geneve_opts(mask, n);
++	if (err)
++		return err;
++	addattr_nest_end(n, nest);
++
++	return 0;
++}
++
++static int flower_parse_enc_opts_vxlan(char *str, struct nlmsghdr *n)
++{
++	char key[XATTR_SIZE_MAX], mask[XATTR_SIZE_MAX];
++	struct rtattr *nest;
++	char *slash;
++	int err;
++
++	slash = strchr(str, '/');
++	if (slash) {
++		*slash++ = '\0';
++		if (strlen(slash) > XATTR_SIZE_MAX)
++			return -1;
++		strcpy(mask, slash);
++	} else {
++		strcpy(mask, "0xffffffff");
++	}
++
++	if (strlen(str) > XATTR_SIZE_MAX)
++		return -1;
++	strcpy(key, str);
++
++	nest = addattr_nest(n, MAX_MSG, TCA_FLOWER_KEY_ENC_OPTS | NLA_F_NESTED);
++	err = flower_parse_vxlan_opt(str, n);
++	if (err)
++		return err;
++	addattr_nest_end(n, nest);
++
++	nest = addattr_nest(n, MAX_MSG,
++			    TCA_FLOWER_KEY_ENC_OPTS_MASK | NLA_F_NESTED);
++	err = flower_parse_vxlan_opt(mask, n);
+ 	if (err)
+ 		return err;
+ 	addattr_nest_end(n, nest);
+@@ -1275,11 +1332,18 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
+ 			}
+ 		} else if (matches(*argv, "geneve_opts") == 0) {
+ 			NEXT_ARG();
+-			ret = flower_parse_enc_opts(*argv, n);
++			ret = flower_parse_enc_opts_geneve(*argv, n);
+ 			if (ret < 0) {
+ 				fprintf(stderr, "Illegal \"geneve_opts\"\n");
+ 				return -1;
+ 			}
++		} else if (matches(*argv, "vxlan_opts") == 0) {
++			NEXT_ARG();
++			ret = flower_parse_enc_opts_vxlan(*argv, n);
++			if (ret < 0) {
++				fprintf(stderr, "Illegal \"vxlan_opts\"\n");
++				return -1;
++			}
+ 		} else if (matches(*argv, "action") == 0) {
+ 			NEXT_ARG();
+ 			ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n);
+@@ -1643,10 +1707,29 @@ static void flower_print_geneve_opts(const char *name, struct rtattr *attr,
+ 	close_json_array(PRINT_JSON, name);
+ }
+ 
+-static void flower_print_geneve_parts(const char *name, struct rtattr *attr,
+-				      char *key, char *mask)
++static void flower_print_vxlan_opts(const char *name, struct rtattr *attr,
++				    char *strbuf)
++{
++	struct rtattr *tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX + 1];
++	struct rtattr *i = RTA_DATA(attr);
++	int rem = RTA_PAYLOAD(attr);
++	__u32 gbp;
++
++	parse_rtattr(tb, TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX, i, rem);
++	gbp = rta_getattr_u32(tb[TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP]);
++
++	open_json_array(PRINT_JSON, name);
++	open_json_object(NULL);
++	print_uint(PRINT_JSON, "gbp", NULL, gbp);
++	close_json_object();
++	close_json_array(PRINT_JSON, name);
++
++	sprintf(strbuf, "%u", gbp);
++}
++
++static void flower_print_enc_parts(const char *name, const char *namefrm,
++				   struct rtattr *attr, char *key, char *mask)
+ {
+-	char *namefrm = "\n  geneve_opt %s";
+ 	char *key_token, *mask_token, *out;
+ 	int len;
+ 
+@@ -1687,14 +1770,29 @@ static void flower_print_enc_opts(const char *name, struct rtattr *attr,
+ 		goto err_key_free;
+ 
+ 	parse_rtattr_nested(key_tb, TCA_FLOWER_KEY_ENC_OPTS_MAX, attr);
+-	flower_print_geneve_opts("geneve_opt_key",
+-				 key_tb[TCA_FLOWER_KEY_ENC_OPTS_GENEVE], key);
+-
+ 	parse_rtattr_nested(msk_tb, TCA_FLOWER_KEY_ENC_OPTS_MAX, mask_attr);
+-	flower_print_geneve_opts("geneve_opt_mask",
+-				 msk_tb[TCA_FLOWER_KEY_ENC_OPTS_GENEVE], msk);
+ 
+-	flower_print_geneve_parts(name, attr, key, msk);
++	if (key_tb[TCA_FLOWER_KEY_ENC_OPTS_GENEVE]) {
++		flower_print_geneve_opts("geneve_opt_key",
++				key_tb[TCA_FLOWER_KEY_ENC_OPTS_GENEVE], key);
++
++		if (msk_tb[TCA_FLOWER_KEY_ENC_OPTS_GENEVE])
++			flower_print_geneve_opts("geneve_opt_mask",
++				msk_tb[TCA_FLOWER_KEY_ENC_OPTS_GENEVE], msk);
++
++		flower_print_enc_parts(name, "  geneve_opts %s", attr, key,
++				       msk);
++	} else if (key_tb[TCA_FLOWER_KEY_ENC_OPTS_VXLAN]) {
++		flower_print_vxlan_opts("vxlan_opt_key",
++				key_tb[TCA_FLOWER_KEY_ENC_OPTS_VXLAN], key);
++
++		if (msk_tb[TCA_FLOWER_KEY_ENC_OPTS_VXLAN])
++			flower_print_vxlan_opts("vxlan_opt_mask",
++				msk_tb[TCA_FLOWER_KEY_ENC_OPTS_VXLAN], msk);
++
++		flower_print_enc_parts(name, "  vxlan_opts %s", attr, key,
++				       msk);
++	}
+ 
+ 	free(msk);
+ err_key_free:
+-- 
+2.26.2
+
diff --git a/SOURCES/0030-tc-f_flower-add-options-support-for-erspan.patch b/SOURCES/0030-tc-f_flower-add-options-support-for-erspan.patch
new file mode 100644
index 0000000..6c1469b
--- /dev/null
+++ b/SOURCES/0030-tc-f_flower-add-options-support-for-erspan.patch
@@ -0,0 +1,324 @@
+From 6784a916b142c3bd5cf7c20a30b23e362bd4908a Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Thu, 4 Jun 2020 21:44:22 +0200
+Subject: [PATCH] tc: f_flower: add options support for erspan
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485
+Upstream Status: unknown commit 4e578c78fedfe
+
+commit 4e578c78fedfe6ffa5fa5fde56778b264485829b
+Author: Xin Long <lucien.xin@gmail.com>
+Date:   Mon Apr 27 18:27:51 2020 +0800
+
+    tc: f_flower: add options support for erspan
+
+    This patch is to add TCA_FLOWER_KEY_ENC_OPTS_ERSPAN's parse and
+    print to implement erspan options support in m_tunnel_key, like
+    Commit 56155d4df86d ("tc: f_flower: add geneve option match
+    support to flower") for geneve options support.
+
+    Option is expressed as version:index:dir:hwid, dir and hwid will
+    be parsed when version is 2, while index will be parsed when
+    version is 1. erspan doesn't support multiple options.
+
+    With this patch, users can add and dump erspan options like:
+
+      # ip link add name erspan1 type erspan external
+      # tc qdisc add dev erspan1 ingress
+      # tc filter add dev erspan1 protocol ip parent ffff: \
+          flower \
+            enc_src_ip 10.0.99.192 \
+            enc_dst_ip 10.0.99.193 \
+            enc_key_id 11 \
+            erspan_opts 1:2:0:0/1:255:0:0 \
+            ip_proto udp \
+            action mirred egress redirect dev eth1
+      # tc -s filter show dev erspan1 parent ffff:
+
+         filter protocol ip pref 49152 flower chain 0 handle 0x1
+           eth_type ipv4
+           ip_proto udp
+           enc_dst_ip 10.0.99.193
+           enc_src_ip 10.0.99.192
+           enc_key_id 11
+           erspan_opts 1:2:0:0/1:255:0:0
+           not_in_hw
+             action order 1: mirred (Egress Redirect to device eth1) stolen
+             index 1 ref 1 bind 1
+             Action statistics:
+             Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
+             backlog 0b 0p requeues 0
+
+    v1->v2:
+      - no change.
+    v2->v3:
+      - no change.
+    v3->v4:
+      - keep the same format between input and output, json and non json.
+      - print version, index, dir and hwid as uint.
+
+    Signed-off-by: Xin Long <lucien.xin@gmail.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ man/man8/tc-flower.8 |  13 ++++
+ tc/f_flower.c        | 171 +++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 184 insertions(+)
+
+diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
+index 0efacbfdf9a95..f41b0f7f1ef13 100644
+--- a/man/man8/tc-flower.8
++++ b/man/man8/tc-flower.8
+@@ -85,6 +85,8 @@ flower \- flow based traffic control filter
+ .B geneve_opts
+ |
+ .B vxlan_opts
++|
++.B erspan_opts
+ }
+ .IR OPTIONS " | "
+ .BR ip_flags
+@@ -296,6 +298,8 @@ bits is assumed.
+ .BI geneve_opts " OPTIONS"
+ .TQ
+ .BI vxlan_opts " OPTIONS"
++.TQ
++.BI erspan_opts " OPTIONS"
+ Match on IP tunnel metadata. Key id
+ .I NUMBER
+ is a 32 bit tunnel key id (e.g. VNI for VXLAN tunnel).
+@@ -322,6 +326,15 @@ doesn't support multiple options, and it consists of a key followed by a slash
+ and corresponding mask. If the mask is missing, \fBtc\fR assumes a full-length
+ match. The option can be described in the form GBP/GBP_MASK, where GBP is
+ represented as a 32bit number.
++erspan_opts
++.I OPTIONS
++doesn't support multiple options, and it consists of a key followed by a slash
++and corresponding mask. If the mask is missing, \fBtc\fR assumes a full-length
++match. The option can be described in the form
++VERSION:INDEX:DIR:HWID/VERSION:INDEX_MASK:DIR_MASK:HWID_MASK, where VERSION is
++represented as a 8bit number, INDEX as an 32bit number, DIR and HWID as a 8bit
++number. Multiple options is not supported. Note INDEX/INDEX_MASK is used when
++VERSION is 1, and DIR/DIR_MASK and HWID/HWID_MASK are used when VERSION is 2.
+ .TP
+ .BI ip_flags " IP_FLAGS"
+ .I IP_FLAGS
+diff --git a/tc/f_flower.c b/tc/f_flower.c
+index 09079cd2c2280..691541ec59d4c 100644
+--- a/tc/f_flower.c
++++ b/tc/f_flower.c
+@@ -82,6 +82,7 @@ static void explain(void)
+ 		"			enc_ttl MASKED-IP_TTL |\n"
+ 		"			geneve_opts MASKED-OPTIONS |\n"
+ 		"			vxlan_opts MASKED-OPTIONS |\n"
++		"                       erspan_opts MASKED-OPTIONS |\n"
+ 		"			ip_flags IP-FLAGS | \n"
+ 		"			enc_dst_port [ port_number ] }\n"
+ 		"	FILTERID := X:Y:Z\n"
+@@ -738,6 +739,84 @@ static int flower_parse_vxlan_opt(char *str, struct nlmsghdr *n)
+ 	return 0;
+ }
+ 
++static int flower_parse_erspan_opt(char *str, struct nlmsghdr *n)
++{
++	struct rtattr *nest;
++	char *token;
++	int i, err;
++
++	nest = addattr_nest(n, MAX_MSG,
++			    TCA_FLOWER_KEY_ENC_OPTS_ERSPAN | NLA_F_NESTED);
++
++	i = 1;
++	token = strsep(&str, ":");
++	while (token) {
++		switch (i) {
++		case TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER:
++		{
++			__u8 opt_type;
++
++			if (!strlen(token))
++				break;
++			err = get_u8(&opt_type, token, 0);
++			if (err)
++				return err;
++
++			addattr8(n, MAX_MSG, i, opt_type);
++			break;
++		}
++		case TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX:
++		{
++			__be32 opt_index;
++
++			if (!strlen(token))
++				break;
++			err = get_be32(&opt_index, token, 0);
++			if (err)
++				return err;
++
++			addattr32(n, MAX_MSG, i, opt_index);
++			break;
++		}
++		case TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR:
++		{
++			__u8 opt_type;
++
++			if (!strlen(token))
++				break;
++			err = get_u8(&opt_type, token, 0);
++			if (err)
++				return err;
++
++			addattr8(n, MAX_MSG, i, opt_type);
++			break;
++		}
++		case TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID:
++		{
++			__u8 opt_type;
++
++			if (!strlen(token))
++				break;
++			err = get_u8(&opt_type, token, 0);
++			if (err)
++				return err;
++
++			addattr8(n, MAX_MSG, i, opt_type);
++			break;
++		}
++		default:
++			fprintf(stderr, "Unknown \"geneve_opts\" type\n");
++			return -1;
++		}
++
++		token = strsep(&str, ":");
++		i++;
++	}
++	addattr_nest_end(n, nest);
++
++	return 0;
++}
++
+ static int flower_parse_geneve_opts(char *str, struct nlmsghdr *n)
+ {
+ 	char *token;
+@@ -878,6 +957,49 @@ static int flower_parse_enc_opts_vxlan(char *str, struct nlmsghdr *n)
+ 	return 0;
+ }
+ 
++static int flower_parse_enc_opts_erspan(char *str, struct nlmsghdr *n)
++{
++	char key[XATTR_SIZE_MAX], mask[XATTR_SIZE_MAX];
++	struct rtattr *nest;
++	char *slash;
++	int err;
++
++
++	slash = strchr(str, '/');
++	if (slash) {
++		*slash++ = '\0';
++		if (strlen(slash) > XATTR_SIZE_MAX)
++			return -1;
++		strcpy(mask, slash);
++	} else {
++		int index;
++
++		slash = strchr(str, ':');
++		index = (int)(slash - str);
++		memcpy(mask, str, index);
++		strcpy(mask + index, ":0xffffffff:0xff:0xff");
++	}
++
++	if (strlen(str) > XATTR_SIZE_MAX)
++		return -1;
++	strcpy(key, str);
++
++	nest = addattr_nest(n, MAX_MSG, TCA_FLOWER_KEY_ENC_OPTS | NLA_F_NESTED);
++	err = flower_parse_erspan_opt(key, n);
++	if (err)
++		return err;
++	addattr_nest_end(n, nest);
++
++	nest = addattr_nest(n, MAX_MSG,
++			    TCA_FLOWER_KEY_ENC_OPTS_MASK | NLA_F_NESTED);
++	err = flower_parse_erspan_opt(mask, n);
++	if (err)
++		return err;
++	addattr_nest_end(n, nest);
++
++	return 0;
++}
++
+ static int flower_parse_opt(struct filter_util *qu, char *handle,
+ 			    int argc, char **argv, struct nlmsghdr *n)
+ {
+@@ -1344,6 +1466,13 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
+ 				fprintf(stderr, "Illegal \"vxlan_opts\"\n");
+ 				return -1;
+ 			}
++		} else if (matches(*argv, "erspan_opts") == 0) {
++			NEXT_ARG();
++			ret = flower_parse_enc_opts_erspan(*argv, n);
++			if (ret < 0) {
++				fprintf(stderr, "Illegal \"erspan_opts\"\n");
++				return -1;
++			}
+ 		} else if (matches(*argv, "action") == 0) {
+ 			NEXT_ARG();
+ 			ret = parse_action(&argc, &argv, TCA_FLOWER_ACT, n);
+@@ -1727,6 +1856,38 @@ static void flower_print_vxlan_opts(const char *name, struct rtattr *attr,
+ 	sprintf(strbuf, "%u", gbp);
+ }
+ 
++static void flower_print_erspan_opts(const char *name, struct rtattr *attr,
++				     char *strbuf)
++{
++	struct rtattr *tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX + 1];
++	__u8 ver, hwid, dir;
++	__u32 idx;
++
++	parse_rtattr(tb, TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX, RTA_DATA(attr),
++		     RTA_PAYLOAD(attr));
++	ver = rta_getattr_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER]);
++	if (ver == 1) {
++		idx = rta_getattr_be32(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX]);
++		hwid = 0;
++		dir = 0;
++	} else {
++		idx = 0;
++		hwid = rta_getattr_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID]);
++		dir = rta_getattr_u8(tb[TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR]);
++	}
++
++	open_json_array(PRINT_JSON, name);
++	open_json_object(NULL);
++	print_uint(PRINT_JSON, "ver", NULL, ver);
++	print_uint(PRINT_JSON, "index", NULL, idx);
++	print_uint(PRINT_JSON, "dir", NULL, dir);
++	print_uint(PRINT_JSON, "hwid", NULL, hwid);
++	close_json_object();
++	close_json_array(PRINT_JSON, name);
++
++	sprintf(strbuf, "%u:%u:%u:%u", ver, idx, dir, hwid);
++}
++
+ static void flower_print_enc_parts(const char *name, const char *namefrm,
+ 				   struct rtattr *attr, char *key, char *mask)
+ {
+@@ -1792,6 +1953,16 @@ static void flower_print_enc_opts(const char *name, struct rtattr *attr,
+ 
+ 		flower_print_enc_parts(name, "  vxlan_opts %s", attr, key,
+ 				       msk);
++	} else if (key_tb[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN]) {
++		flower_print_erspan_opts("erspan_opt_key",
++				key_tb[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN], key);
++
++		if (msk_tb[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN])
++			flower_print_erspan_opts("erspan_opt_mask",
++				msk_tb[TCA_FLOWER_KEY_ENC_OPTS_ERSPAN], msk);
++
++		flower_print_enc_parts(name, "  erspan_opts %s", attr, key,
++				       msk);
+ 	}
+ 
+ 	free(msk);
+-- 
+2.26.2
+
diff --git a/SOURCES/0031-devlink-Add-health-error-recovery-status-monitoring.patch b/SOURCES/0031-devlink-Add-health-error-recovery-status-monitoring.patch
new file mode 100644
index 0000000..813691b
--- /dev/null
+++ b/SOURCES/0031-devlink-Add-health-error-recovery-status-monitoring.patch
@@ -0,0 +1,116 @@
+From 81a035c029c2ef108da0f854c5a670aa3f06bb94 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Wed, 17 Jun 2020 12:10:11 +0200
+Subject: [PATCH] devlink: Add health error recovery status monitoring
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1821039
+Upstream Status: iproute2.git commit 5023df6a21c73
+Conflicts: context change due to missing commit
+  - ef12d6dafaeb9 ("devlink: Add devlink trap set and show commands")
+  - 4ede9e9d56206 ("devlink: Add devlink trap group set and show commands")
+  - a66af5569337b ("devlink: Add devlink trap policer set and show commands")
+
+commit 5023df6a21c73560b514d7fde5381d140373afe9
+Author: Moshe Shemesh <moshe@mellanox.com>
+Date:   Tue Feb 4 23:37:02 2020 +0200
+
+    devlink: Add health error recovery status monitoring
+
+    Add support for devlink health error recovery status monitoring.
+    Update devlink-monitor man page accordingly.
+
+    Signed-off-by: Moshe Shemesh <moshe@mellanox.com>
+    Acked-by: Jiri Pirko <jiri@mellanox.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ devlink/devlink.c          | 17 +++++++++++++++--
+ man/man8/devlink-monitor.8 |  3 ++-
+ 2 files changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/devlink/devlink.c b/devlink/devlink.c
+index 0293373928f50..f7e859c266394 100644
+--- a/devlink/devlink.c
++++ b/devlink/devlink.c
+@@ -3764,6 +3764,7 @@ static const char *cmd_name(uint8_t cmd)
+ 	case DEVLINK_CMD_REGION_SET: return "set";
+ 	case DEVLINK_CMD_REGION_NEW: return "new";
+ 	case DEVLINK_CMD_REGION_DEL: return "del";
++	case DEVLINK_CMD_HEALTH_REPORTER_RECOVER: return "status";
+ 	default: return "<unknown cmd>";
+ 	}
+ }
+@@ -3792,6 +3793,8 @@ static const char *cmd_obj(uint8_t cmd)
+ 	case DEVLINK_CMD_REGION_NEW:
+ 	case DEVLINK_CMD_REGION_DEL:
+ 		return "region";
++	case DEVLINK_CMD_HEALTH_REPORTER_RECOVER:
++		return "health";
+ 	default: return "<unknown obj>";
+ 	}
+ }
+@@ -3817,6 +3820,7 @@ static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
+ }
+ 
+ static void pr_out_region(struct dl *dl, struct nlattr **tb);
++static void pr_out_health(struct dl *dl, struct nlattr **tb_health);
+ 
+ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
+ {
+@@ -3872,6 +3876,14 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
+ 		pr_out_mon_header(genl->cmd);
+ 		pr_out_region(dl, tb);
+ 		break;
++	case DEVLINK_CMD_HEALTH_REPORTER_RECOVER:
++		mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
++		if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
++		    !tb[DEVLINK_ATTR_HEALTH_REPORTER])
++			return MNL_CB_ERROR;
++		pr_out_mon_header(genl->cmd);
++		pr_out_health(dl, tb);
++		break;
+ 	}
+ 	return MNL_CB_OK;
+ }
+@@ -3885,7 +3897,8 @@ static int cmd_mon_show(struct dl *dl)
+ 	while ((cur_obj = dl_argv_index(dl, index++))) {
+ 		if (strcmp(cur_obj, "all") != 0 &&
+ 		    strcmp(cur_obj, "dev") != 0 &&
+-		    strcmp(cur_obj, "port") != 0) {
++		    strcmp(cur_obj, "port") != 0 &&
++		    strcmp(cur_obj, "health") != 0) {
+ 			pr_err("Unknown object \"%s\"\n", cur_obj);
+ 			return -EINVAL;
+ 		}
+@@ -3902,7 +3915,7 @@ static int cmd_mon_show(struct dl *dl)
+ static void cmd_mon_help(void)
+ {
+ 	pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
+-	       "where  OBJECT-LIST := { dev | port }\n");
++	       "where  OBJECT-LIST := { dev | port | health }\n");
+ }
+ 
+ static int cmd_mon(struct dl *dl)
+diff --git a/man/man8/devlink-monitor.8 b/man/man8/devlink-monitor.8
+index 13fe641dc8f54..9bc579673ebf4 100644
+--- a/man/man8/devlink-monitor.8
++++ b/man/man8/devlink-monitor.8
+@@ -21,7 +21,7 @@ command is the first in the command line and then the object list.
+ .I OBJECT-LIST
+ is the list of object types that we want to monitor.
+ It may contain
+-.BR dev ", " port ".
++.BR dev ", " port ", " health ".
+ 
+ .B devlink
+ opens Devlink Netlink socket, listens on it and dumps state changes.
+@@ -31,6 +31,7 @@ opens Devlink Netlink socket, listens on it and dumps state changes.
+ .BR devlink-dev (8),
+ .BR devlink-sb (8),
+ .BR devlink-port (8),
++.BR devlink-health (8),
+ .br
+ 
+ .SH AUTHOR
+-- 
+2.26.2
+
diff --git a/SOURCES/0032-ss-allow-dumping-kTLS-info.patch b/SOURCES/0032-ss-allow-dumping-kTLS-info.patch
new file mode 100644
index 0000000..9fe02ae
--- /dev/null
+++ b/SOURCES/0032-ss-allow-dumping-kTLS-info.patch
@@ -0,0 +1,139 @@
+From 06bd12bd8e48182f7f3293bbec187b4e90da796f Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Mon, 29 Jun 2020 14:36:51 +0200
+Subject: [PATCH] ss: allow dumping kTLS info
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1812207
+Upstream Status: iproute2.git commit 14cadc707b919
+Conflicts: due to out-of-order cherry-pick of commit
+           712fdd98c0839 ("ss: allow dumping MPTCP subflow information")
+
+commit 14cadc707b919914e9a2d5dffad9232c3ae97c5f
+Author: Davide Caratti <dcaratti@redhat.com>
+Date:   Mon Oct 7 12:16:44 2019 +0200
+
+    ss: allow dumping kTLS info
+
+    now that INET_DIAG_INFO requests can dump TCP ULP information, extend 'ss'
+    to allow diagnosing kTLS when it is attached to a TCP socket. While at it,
+    import kTLS uAPI definitions from the latest net-next tree.
+
+    CC: Andrea Claudi <aclaudi@redhat.com>
+    Co-developed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
+    Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
+    Signed-off-by: Davide Caratti <dcaratti@redhat.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ misc/ss.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 82 insertions(+)
+
+diff --git a/misc/ss.c b/misc/ss.c
+index 3d565af86087c..8285382bd6c4a 100644
+--- a/misc/ss.c
++++ b/misc/ss.c
+@@ -51,6 +51,7 @@
+ #include <linux/tipc.h>
+ #include <linux/tipc_netlink.h>
+ #include <linux/tipc_sockets_diag.h>
++#include <linux/tls.h>
+ #include <linux/mptcp.h>
+ 
+ /* AF_VSOCK/PF_VSOCK is only provided since glibc 2.18 */
+@@ -2752,6 +2753,72 @@ static void print_md5sig(struct tcp_diag_md5sig *sig)
+ 	print_escape_buf(sig->tcpm_key, sig->tcpm_keylen, " ,");
+ }
+ 
++static void tcp_tls_version(struct rtattr *attr)
++{
++	u_int16_t val;
++
++	if (!attr)
++		return;
++	val = rta_getattr_u16(attr);
++
++	switch (val) {
++	case TLS_1_2_VERSION:
++		out(" version: 1.2");
++		break;
++	case TLS_1_3_VERSION:
++		out(" version: 1.3");
++		break;
++	default:
++		out(" version: unknown(%hu)", val);
++		break;
++	}
++}
++
++static void tcp_tls_cipher(struct rtattr *attr)
++{
++	u_int16_t val;
++
++	if (!attr)
++		return;
++	val = rta_getattr_u16(attr);
++
++	switch (val) {
++	case TLS_CIPHER_AES_GCM_128:
++		out(" cipher: aes-gcm-128");
++		break;
++	case TLS_CIPHER_AES_GCM_256:
++		out(" cipher: aes-gcm-256");
++		break;
++	}
++}
++
++static void tcp_tls_conf(const char *name, struct rtattr *attr)
++{
++	u_int16_t val;
++
++	if (!attr)
++		return;
++	val = rta_getattr_u16(attr);
++
++	switch (val) {
++	case TLS_CONF_BASE:
++		out(" %s: none", name);
++		break;
++	case TLS_CONF_SW:
++		out(" %s: sw", name);
++		break;
++	case TLS_CONF_HW:
++		out(" %s: hw", name);
++		break;
++	case TLS_CONF_HW_RECORD:
++		out(" %s: hw-record", name);
++		break;
++	default:
++		out(" %s: unknown(%hu)", name, val);
++		break;
++	}
++}
++
+ static void mptcp_subflow_info(struct rtattr *tb[])
+ {
+ 	u_int32_t flags = 0;
+@@ -2966,6 +3033,21 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
+ 		parse_rtattr_nested(ulpinfo, INET_ULP_INFO_MAX,
+ 				    tb[INET_DIAG_ULP_INFO]);
+ 
++		if (ulpinfo[INET_ULP_INFO_NAME])
++			out(" tcp-ulp-%s",
++			    rta_getattr_str(ulpinfo[INET_ULP_INFO_NAME]));
++
++		if (ulpinfo[INET_ULP_INFO_TLS]) {
++			struct rtattr *tlsinfo[TLS_INFO_MAX + 1] = { 0 };
++
++			parse_rtattr_nested(tlsinfo, TLS_INFO_MAX,
++					    ulpinfo[INET_ULP_INFO_TLS]);
++
++			tcp_tls_version(tlsinfo[TLS_INFO_VERSION]);
++			tcp_tls_cipher(tlsinfo[TLS_INFO_CIPHER]);
++			tcp_tls_conf("rxconf", tlsinfo[TLS_INFO_RXCONF]);
++			tcp_tls_conf("txconf", tlsinfo[TLS_INFO_TXCONF]);
++		}
+ 		if (ulpinfo[INET_ULP_INFO_MPTCP]) {
+ 			struct rtattr *sfinfo[MPTCP_SUBFLOW_ATTR_MAX + 1] =
+ 				{ 0 };
+-- 
+2.26.2
+
diff --git a/SOURCES/0033-Import-tc_act-tc_ct.h-uapi-file.patch b/SOURCES/0033-Import-tc_act-tc_ct.h-uapi-file.patch
new file mode 100644
index 0000000..f3c473d
--- /dev/null
+++ b/SOURCES/0033-Import-tc_act-tc_ct.h-uapi-file.patch
@@ -0,0 +1,73 @@
+From 4c330f41bce887a4a06d6c84c62a3a8c1b0b5160 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Tue, 9 Jun 2020 15:45:55 +0200
+Subject: [PATCH] Import tc_act/tc_ct.h uapi file
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1844637
+Upstream Status: iproute2.git commit f47081befffc5
+
+commit f47081befffc50a5eef734d0a6654b59047e7808
+Author: David Ahern <dsahern@gmail.com>
+Date:   Thu Jul 18 15:40:07 2019 -0700
+
+    Import tc_act/tc_ct.h uapi file
+
+    Import include/uapi/linux/tc_act/tc_ct.h header from commit of last
+    kernel headers sync.
+
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ include/uapi/linux/tc_act/tc_ct.h | 41 +++++++++++++++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+ create mode 100644 include/uapi/linux/tc_act/tc_ct.h
+
+diff --git a/include/uapi/linux/tc_act/tc_ct.h b/include/uapi/linux/tc_act/tc_ct.h
+new file mode 100644
+index 0000000000000..5fb1d7ac10272
+--- /dev/null
++++ b/include/uapi/linux/tc_act/tc_ct.h
+@@ -0,0 +1,41 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
++#ifndef __UAPI_TC_CT_H
++#define __UAPI_TC_CT_H
++
++#include <linux/types.h>
++#include <linux/pkt_cls.h>
++
++enum {
++	TCA_CT_UNSPEC,
++	TCA_CT_PARMS,
++	TCA_CT_TM,
++	TCA_CT_ACTION,		/* u16 */
++	TCA_CT_ZONE,		/* u16 */
++	TCA_CT_MARK,		/* u32 */
++	TCA_CT_MARK_MASK,	/* u32 */
++	TCA_CT_LABELS,		/* u128 */
++	TCA_CT_LABELS_MASK,	/* u128 */
++	TCA_CT_NAT_IPV4_MIN,	/* be32 */
++	TCA_CT_NAT_IPV4_MAX,	/* be32 */
++	TCA_CT_NAT_IPV6_MIN,	/* struct in6_addr */
++	TCA_CT_NAT_IPV6_MAX,	/* struct in6_addr */
++	TCA_CT_NAT_PORT_MIN,	/* be16 */
++	TCA_CT_NAT_PORT_MAX,	/* be16 */
++	TCA_CT_PAD,
++	__TCA_CT_MAX
++};
++
++#define TCA_CT_MAX (__TCA_CT_MAX - 1)
++
++#define TCA_CT_ACT_COMMIT	(1 << 0)
++#define TCA_CT_ACT_FORCE	(1 << 1)
++#define TCA_CT_ACT_CLEAR	(1 << 2)
++#define TCA_CT_ACT_NAT		(1 << 3)
++#define TCA_CT_ACT_NAT_SRC	(1 << 4)
++#define TCA_CT_ACT_NAT_DST	(1 << 5)
++
++struct tc_ct {
++	tc_gen;
++};
++
++#endif /* __UAPI_TC_CT_H */
+-- 
+2.26.2
+
diff --git a/SOURCES/0034-tc-add-NLA_F_NESTED-flag-to-all-actions-options-nest.patch b/SOURCES/0034-tc-add-NLA_F_NESTED-flag-to-all-actions-options-nest.patch
new file mode 100644
index 0000000..5832ac4
--- /dev/null
+++ b/SOURCES/0034-tc-add-NLA_F_NESTED-flag-to-all-actions-options-nest.patch
@@ -0,0 +1,40 @@
+From bf795d2418ee298ddc73171829d6dc4914c22a46 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Tue, 9 Jun 2020 15:45:56 +0200
+Subject: [PATCH] tc: add NLA_F_NESTED flag to all actions options nested block
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1844637
+Upstream Status: iproute2.git commit 18aa9f5583e94
+
+commit 18aa9f5583e94abc7204b2376b819ede1180da97
+Author: Paul Blakey <paulb@mellanox.com>
+Date:   Thu Jul 11 11:14:25 2019 +0300
+
+    tc: add NLA_F_NESTED flag to all actions options nested block
+
+    Strict netlink validation now requires this flag on all nested
+    attributes, add it for action options.
+
+    Signed-off-by: Paul Blakey <paulb@mellanox.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ tc/m_action.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/tc/m_action.c b/tc/m_action.c
+index c46aeaafa8ebf..4da810c8c0aa7 100644
+--- a/tc/m_action.c
++++ b/tc/m_action.c
+@@ -214,7 +214,8 @@ done0:
+ 			tail = addattr_nest(n, MAX_MSG, ++prio);
+ 			addattr_l(n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
+ 
+-			ret = a->parse_aopt(a, &argc, &argv, TCA_ACT_OPTIONS,
++			ret = a->parse_aopt(a, &argc, &argv,
++					    TCA_ACT_OPTIONS | NLA_F_NESTED,
+ 					    n);
+ 
+ 			if (ret < 0) {
+-- 
+2.26.2
+
diff --git a/SOURCES/0035-tc-Introduce-tc-ct-action.patch b/SOURCES/0035-tc-Introduce-tc-ct-action.patch
new file mode 100644
index 0000000..3971adf
--- /dev/null
+++ b/SOURCES/0035-tc-Introduce-tc-ct-action.patch
@@ -0,0 +1,621 @@
+From ef66b6a546f3f1fd517cfa306cc347ad096bd932 Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Tue, 9 Jun 2020 15:45:56 +0200
+Subject: [PATCH] tc: Introduce tc ct action
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1844637
+Upstream Status: iproute2.git commit c8a494314c400
+
+commit c8a494314c400eb023d7555933ba8ab40345519b
+Author: Paul Blakey <paulb@mellanox.com>
+Date:   Thu Jul 11 11:14:26 2019 +0300
+
+    tc: Introduce tc ct action
+
+    New tc action to send packets to conntrack module, commit
+    them, and set a zone, labels, mark, and nat on the connection.
+
+    It can also clear the packet's conntrack state by using clear.
+
+    Usage:
+       ct clear
+       ct commit [force] [zone] [mark] [label] [nat]
+       ct [nat] [zone]
+
+    Signed-off-by: Paul Blakey <paulb@mellanox.com>
+    Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+    Signed-off-by: Yossi Kuperman <yossiku@mellanox.com>
+    Acked-by: Jiri Pirko <jiri@mellanox.com>
+    Acked-by: Roi Dayan <roid@mellanox.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ tc/Makefile  |   1 +
+ tc/m_ct.c    | 497 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ tc/tc_util.c |  44 +++++
+ tc/tc_util.h |   4 +
+ 4 files changed, 546 insertions(+)
+ create mode 100644 tc/m_ct.c
+
+diff --git a/tc/Makefile b/tc/Makefile
+index 09ff3692b1663..14171a28cba5d 100644
+--- a/tc/Makefile
++++ b/tc/Makefile
+@@ -53,6 +53,7 @@ TCMODULES += m_ctinfo.o
+ TCMODULES += m_bpf.o
+ TCMODULES += m_tunnel_key.o
+ TCMODULES += m_sample.o
++TCMODULES += m_ct.o
+ TCMODULES += p_ip.o
+ TCMODULES += p_ip6.o
+ TCMODULES += p_icmp.o
+diff --git a/tc/m_ct.c b/tc/m_ct.c
+new file mode 100644
+index 0000000000000..8589cb9a3c515
+--- /dev/null
++++ b/tc/m_ct.c
+@@ -0,0 +1,497 @@
++// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
++/* -
++ * m_ct.c     Connection tracking action
++ *
++ * Authors:   Paul Blakey <paulb@mellanox.com>
++ *            Yossi Kuperman <yossiku@mellanox.com>
++ *            Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include "utils.h"
++#include "tc_util.h"
++#include <linux/tc_act/tc_ct.h>
++
++static void
++usage(void)
++{
++	fprintf(stderr,
++		"Usage: ct clear\n"
++		"	ct commit [force] [zone ZONE] [mark MASKED_MARK] [label MASKED_LABEL] [nat NAT_SPEC]\n"
++		"	ct [nat] [zone ZONE]\n"
++		"Where: ZONE is the conntrack zone table number\n"
++		"	NAT_SPEC is {src|dst} addr addr1[-addr2] [port port1[-port2]]\n"
++		"\n");
++	exit(-1);
++}
++
++static int ct_parse_nat_addr_range(const char *str, struct nlmsghdr *n)
++{
++	inet_prefix addr = { .family = AF_UNSPEC, };
++	char *addr1, *addr2 = 0;
++	SPRINT_BUF(buffer);
++	int attr;
++	int ret;
++
++	strncpy(buffer, str, sizeof(buffer) - 1);
++
++	addr1 = buffer;
++	addr2 = strchr(addr1, '-');
++	if (addr2) {
++		*addr2 = '\0';
++		addr2++;
++	}
++
++	ret = get_addr(&addr, addr1, AF_UNSPEC);
++	if (ret)
++		return ret;
++	attr = addr.family == AF_INET ? TCA_CT_NAT_IPV4_MIN :
++					TCA_CT_NAT_IPV6_MIN;
++	addattr_l(n, MAX_MSG, attr, addr.data, addr.bytelen);
++
++	if (addr2) {
++		ret = get_addr(&addr, addr2, addr.family);
++		if (ret)
++			return ret;
++	}
++	attr = addr.family == AF_INET ? TCA_CT_NAT_IPV4_MAX :
++					TCA_CT_NAT_IPV6_MAX;
++	addattr_l(n, MAX_MSG, attr, addr.data, addr.bytelen);
++
++	return 0;
++}
++
++static int ct_parse_nat_port_range(const char *str, struct nlmsghdr *n)
++{
++	char *port1, *port2 = 0;
++	SPRINT_BUF(buffer);
++	__be16 port;
++	int ret;
++
++	strncpy(buffer, str, sizeof(buffer) - 1);
++
++	port1 = buffer;
++	port2 = strchr(port1, '-');
++	if (port2) {
++		*port2 = '\0';
++		port2++;
++	}
++
++	ret = get_be16(&port, port1, 10);
++	if (ret)
++		return -1;
++	addattr16(n, MAX_MSG, TCA_CT_NAT_PORT_MIN, port);
++
++	if (port2) {
++		ret = get_be16(&port, port2, 10);
++		if (ret)
++			return -1;
++	}
++	addattr16(n, MAX_MSG, TCA_CT_NAT_PORT_MAX, port);
++
++	return 0;
++}
++
++
++static int ct_parse_u16(char *str, int value_type, int mask_type,
++			struct nlmsghdr *n)
++{
++	__u16 value, mask;
++	char *slash = 0;
++
++	if (mask_type != TCA_CT_UNSPEC) {
++		slash = strchr(str, '/');
++		if (slash)
++			*slash = '\0';
++	}
++
++	if (get_u16(&value, str, 0))
++		return -1;
++
++	if (slash) {
++		if (get_u16(&mask, slash + 1, 0))
++			return -1;
++	} else {
++		mask = UINT16_MAX;
++	}
++
++	addattr16(n, MAX_MSG, value_type, value);
++	if (mask_type != TCA_CT_UNSPEC)
++		addattr16(n, MAX_MSG, mask_type, mask);
++
++	return 0;
++}
++
++static int ct_parse_u32(char *str, int value_type, int mask_type,
++			struct nlmsghdr *n)
++{
++	__u32 value, mask;
++	char *slash;
++
++	slash = strchr(str, '/');
++	if (slash)
++		*slash = '\0';
++
++	if (get_u32(&value, str, 0))
++		return -1;
++
++	if (slash) {
++		if (get_u32(&mask, slash + 1, 0))
++			return -1;
++	} else {
++		mask = UINT32_MAX;
++	}
++
++	addattr32(n, MAX_MSG, value_type, value);
++	addattr32(n, MAX_MSG, mask_type, mask);
++
++	return 0;
++}
++
++static int ct_parse_mark(char *str, struct nlmsghdr *n)
++{
++	return ct_parse_u32(str, TCA_CT_MARK, TCA_CT_MARK_MASK, n);
++}
++
++static int ct_parse_labels(char *str, struct nlmsghdr *n)
++{
++#define LABELS_SIZE	16
++	uint8_t labels[LABELS_SIZE], lmask[LABELS_SIZE];
++	char *slash, *mask = NULL;
++	size_t slen, slen_mask = 0;
++
++	slash = index(str, '/');
++	if (slash) {
++		*slash = 0;
++		mask = slash+1;
++		slen_mask = strlen(mask);
++	}
++
++	slen = strlen(str);
++	if (slen > LABELS_SIZE*2 || slen_mask > LABELS_SIZE*2) {
++		char errmsg[128];
++
++		snprintf(errmsg, sizeof(errmsg),
++				"%zd Max allowed size %d",
++				slen, LABELS_SIZE*2);
++		invarg(errmsg, str);
++	}
++
++	if (hex2mem(str, labels, slen/2) < 0)
++		invarg("ct: labels must be a hex string\n", str);
++	addattr_l(n, MAX_MSG, TCA_CT_LABELS, labels, slen/2);
++
++	if (mask) {
++		if (hex2mem(mask, lmask, slen_mask/2) < 0)
++			invarg("ct: labels mask must be a hex string\n", mask);
++	} else {
++		memset(lmask, 0xff, sizeof(lmask));
++		slen_mask = sizeof(lmask)*2;
++	}
++	addattr_l(n, MAX_MSG, TCA_CT_LABELS_MASK, lmask, slen_mask/2);
++
++	return 0;
++}
++
++static int
++parse_ct(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
++		struct nlmsghdr *n)
++{
++	struct tc_ct sel = {};
++	char **argv = *argv_p;
++	struct rtattr *tail;
++	int argc = *argc_p;
++	int ct_action = 0;
++	int ret;
++
++	tail = addattr_nest(n, MAX_MSG, tca_id);
++
++	if (argc && matches(*argv, "ct") == 0)
++		NEXT_ARG_FWD();
++
++	while (argc > 0) {
++		if (matches(*argv, "zone") == 0) {
++			NEXT_ARG();
++
++			if (ct_parse_u16(*argv,
++					 TCA_CT_ZONE, TCA_CT_UNSPEC, n)) {
++				fprintf(stderr, "ct: Illegal \"zone\"\n");
++				return -1;
++			}
++		} else if (matches(*argv, "nat") == 0) {
++			ct_action |= TCA_CT_ACT_NAT;
++
++			NEXT_ARG();
++			if (matches(*argv, "src") == 0)
++				ct_action |= TCA_CT_ACT_NAT_SRC;
++			else if (matches(*argv, "dst") == 0)
++				ct_action |= TCA_CT_ACT_NAT_DST;
++			else
++				continue;
++
++			NEXT_ARG();
++			if (matches(*argv, "addr") != 0)
++				usage();
++
++			NEXT_ARG();
++			ret = ct_parse_nat_addr_range(*argv, n);
++			if (ret) {
++				fprintf(stderr, "ct: Illegal nat address range\n");
++				return -1;
++			}
++
++			NEXT_ARG_FWD();
++			if (matches(*argv, "port") != 0)
++				continue;
++
++			NEXT_ARG();
++			ret = ct_parse_nat_port_range(*argv, n);
++			if (ret) {
++				fprintf(stderr, "ct: Illegal nat port range\n");
++				return -1;
++			}
++		} else if (matches(*argv, "clear") == 0) {
++			ct_action |= TCA_CT_ACT_CLEAR;
++		} else if (matches(*argv, "commit") == 0) {
++			ct_action |= TCA_CT_ACT_COMMIT;
++		} else if (matches(*argv, "force") == 0) {
++			ct_action |= TCA_CT_ACT_FORCE;
++		} else if (matches(*argv, "index") == 0) {
++			NEXT_ARG();
++			if (get_u32(&sel.index, *argv, 10)) {
++				fprintf(stderr, "ct: Illegal \"index\"\n");
++				return -1;
++			}
++		} else if (matches(*argv, "mark") == 0) {
++			NEXT_ARG();
++
++			ret = ct_parse_mark(*argv, n);
++			if (ret) {
++				fprintf(stderr, "ct: Illegal \"mark\"\n");
++				return -1;
++			}
++		} else if (matches(*argv, "label") == 0) {
++			NEXT_ARG();
++
++			ret = ct_parse_labels(*argv, n);
++			if (ret) {
++				fprintf(stderr, "ct: Illegal \"label\"\n");
++				return -1;
++			}
++		} else if (matches(*argv, "help") == 0) {
++			usage();
++		} else {
++			break;
++		}
++		NEXT_ARG_FWD();
++	}
++
++	if (ct_action & TCA_CT_ACT_CLEAR &&
++	    ct_action & ~TCA_CT_ACT_CLEAR) {
++		fprintf(stderr, "ct: clear can only be used alone\n");
++		return -1;
++	}
++
++	if (ct_action & TCA_CT_ACT_NAT_SRC &&
++	    ct_action & TCA_CT_ACT_NAT_DST) {
++		fprintf(stderr, "ct: src and dst nat can't be used together\n");
++		return -1;
++	}
++
++	if ((ct_action & TCA_CT_ACT_COMMIT) &&
++	    (ct_action & TCA_CT_ACT_NAT) &&
++	    !(ct_action & (TCA_CT_ACT_NAT_SRC | TCA_CT_ACT_NAT_DST))) {
++		fprintf(stderr, "ct: commit and nat must set src or dst\n");
++		return -1;
++	}
++
++	if (!(ct_action & TCA_CT_ACT_COMMIT) &&
++	    (ct_action & (TCA_CT_ACT_NAT_SRC | TCA_CT_ACT_NAT_DST))) {
++		fprintf(stderr, "ct: src or dst is only valid if commit is set\n");
++		return -1;
++	}
++
++	parse_action_control_dflt(&argc, &argv, &sel.action, false,
++				  TC_ACT_PIPE);
++	NEXT_ARG_FWD();
++
++	addattr16(n, MAX_MSG, TCA_CT_ACTION, ct_action);
++	addattr_l(n, MAX_MSG, TCA_CT_PARMS, &sel, sizeof(sel));
++	addattr_nest_end(n, tail);
++
++	*argc_p = argc;
++	*argv_p = argv;
++	return 0;
++}
++
++static int ct_sprint_port(char *buf, const char *prefix, struct rtattr *attr)
++{
++	if (!attr)
++		return 0;
++
++	return sprintf(buf, "%s%d", prefix, rta_getattr_be16(attr));
++}
++
++static int ct_sprint_ip_addr(char *buf, const char *prefix,
++			     struct rtattr *attr)
++{
++	int family;
++	size_t len;
++
++	if (!attr)
++		return 0;
++
++	len = RTA_PAYLOAD(attr);
++
++	if (len == 4)
++		family = AF_INET;
++	else if (len == 16)
++		family = AF_INET6;
++	else
++		return 0;
++
++	return sprintf(buf, "%s%s", prefix, rt_addr_n2a_rta(family, attr));
++}
++
++static void ct_print_nat(int ct_action, struct rtattr **tb)
++{
++	size_t done = 0;
++	char out[256] = "";
++	bool nat;
++
++	if (!(ct_action & TCA_CT_ACT_NAT))
++		return;
++
++	if (ct_action & TCA_CT_ACT_NAT_SRC) {
++		nat = true;
++		done += sprintf(out + done, "src");
++	} else if (ct_action & TCA_CT_ACT_NAT_DST) {
++		nat = true;
++		done += sprintf(out + done, "dst");
++	}
++
++	if (nat) {
++		done += ct_sprint_ip_addr(out + done, " addr ",
++					  tb[TCA_CT_NAT_IPV4_MIN]);
++		done += ct_sprint_ip_addr(out + done, " addr ",
++					  tb[TCA_CT_NAT_IPV6_MIN]);
++		if (tb[TCA_CT_NAT_IPV4_MAX] &&
++		    memcmp(RTA_DATA(tb[TCA_CT_NAT_IPV4_MIN]),
++			   RTA_DATA(tb[TCA_CT_NAT_IPV4_MAX]), 4))
++			done += ct_sprint_ip_addr(out + done, "-",
++						  tb[TCA_CT_NAT_IPV4_MAX]);
++		else if (tb[TCA_CT_NAT_IPV6_MAX] &&
++			    memcmp(RTA_DATA(tb[TCA_CT_NAT_IPV6_MIN]),
++				   RTA_DATA(tb[TCA_CT_NAT_IPV6_MAX]), 16))
++			done += ct_sprint_ip_addr(out + done, "-",
++						  tb[TCA_CT_NAT_IPV6_MAX]);
++		done += ct_sprint_port(out + done, " port ",
++				       tb[TCA_CT_NAT_PORT_MIN]);
++		if (tb[TCA_CT_NAT_PORT_MAX] &&
++		    memcmp(RTA_DATA(tb[TCA_CT_NAT_PORT_MIN]),
++			   RTA_DATA(tb[TCA_CT_NAT_PORT_MAX]), 2))
++			done += ct_sprint_port(out + done, "-",
++					       tb[TCA_CT_NAT_PORT_MAX]);
++	}
++
++	if (done)
++		print_string(PRINT_ANY, "nat", " nat %s", out);
++	else
++		print_string(PRINT_ANY, "nat", " nat", "");
++}
++
++static void ct_print_labels(struct rtattr *attr,
++			    struct rtattr *mask_attr)
++{
++	const unsigned char *str;
++	bool print_mask = false;
++	char out[256], *p;
++	int data_len, i;
++
++	if (!attr)
++		return;
++
++	data_len = RTA_PAYLOAD(attr);
++	hexstring_n2a(RTA_DATA(attr), data_len, out, sizeof(out));
++	p = out + data_len*2;
++
++	data_len = RTA_PAYLOAD(attr);
++	str = RTA_DATA(mask_attr);
++	if (data_len != 16)
++		print_mask = true;
++	for (i = 0; !print_mask && i < data_len; i++) {
++		if (str[i] != 0xff)
++			print_mask = true;
++	}
++	if (print_mask) {
++		*p++ = '/';
++		hexstring_n2a(RTA_DATA(mask_attr), data_len, p,
++			      sizeof(out)-(p-out));
++		p += data_len*2;
++	}
++	*p = '\0';
++
++	print_string(PRINT_ANY, "label", " label %s", out);
++}
++
++static int print_ct(struct action_util *au, FILE *f, struct rtattr *arg)
++{
++	struct rtattr *tb[TCA_CT_MAX + 1];
++	const char *commit;
++	struct tc_ct *p;
++	int ct_action = 0;
++
++	if (arg == NULL)
++		return -1;
++
++	parse_rtattr_nested(tb, TCA_CT_MAX, arg);
++	if (tb[TCA_CT_PARMS] == NULL) {
++		print_string(PRINT_FP, NULL, "%s", "[NULL ct parameters]");
++		return -1;
++	}
++
++	p = RTA_DATA(tb[TCA_CT_PARMS]);
++
++	print_string(PRINT_ANY, "kind", "%s", "ct");
++
++	if (tb[TCA_CT_ACTION])
++		ct_action = rta_getattr_u16(tb[TCA_CT_ACTION]);
++	if (ct_action & TCA_CT_ACT_COMMIT) {
++		commit = ct_action & TCA_CT_ACT_FORCE ?
++			 "commit force" : "commit";
++		print_string(PRINT_ANY, "action", " %s", commit);
++	} else if (ct_action & TCA_CT_ACT_CLEAR) {
++		print_string(PRINT_ANY, "action", " %s", "clear");
++	}
++
++	print_masked_u32("mark", tb[TCA_CT_MARK], tb[TCA_CT_MARK_MASK]);
++	print_masked_u16("zone", tb[TCA_CT_ZONE], NULL);
++	ct_print_labels(tb[TCA_CT_LABELS], tb[TCA_CT_LABELS_MASK]);
++	ct_print_nat(ct_action, tb);
++
++	print_action_control(f, " ", p->action, "");
++
++	print_uint(PRINT_ANY, "index", "\n\t index %u", p->index);
++	print_int(PRINT_ANY, "ref", " ref %d", p->refcnt);
++	print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt);
++
++	if (show_stats) {
++		if (tb[TCA_CT_TM]) {
++			struct tcf_t *tm = RTA_DATA(tb[TCA_CT_TM]);
++
++			print_tm(f, tm);
++		}
++	}
++	print_string(PRINT_FP, NULL, "%s", "\n ");
++
++	return 0;
++}
++
++struct action_util ct_action_util = {
++	.id = "ct",
++	.parse_aopt = parse_ct,
++	.print_aopt = print_ct,
++};
+diff --git a/tc/tc_util.c b/tc/tc_util.c
+index b90d256c33a4a..0eb530408d056 100644
+--- a/tc/tc_util.c
++++ b/tc/tc_util.c
+@@ -914,3 +914,47 @@ compat_xstats:
+ 	if (tb[TCA_XSTATS] && xstats)
+ 		*xstats = tb[TCA_XSTATS];
+ }
++
++void print_masked_u32(const char *name, struct rtattr *attr,
++		      struct rtattr *mask_attr)
++{
++	__u32 value, mask;
++	SPRINT_BUF(namefrm);
++	SPRINT_BUF(out);
++	size_t done;
++
++	if (!attr)
++		return;
++
++	value = rta_getattr_u32(attr);
++	mask = mask_attr ? rta_getattr_u32(mask_attr) : UINT32_MAX;
++
++	done = sprintf(out, "%u", value);
++	if (mask != UINT32_MAX)
++		sprintf(out + done, "/0x%x", mask);
++
++	sprintf(namefrm, " %s %%s", name);
++	print_string(PRINT_ANY, name, namefrm, out);
++}
++
++void print_masked_u16(const char *name, struct rtattr *attr,
++		      struct rtattr *mask_attr)
++{
++	__u16 value, mask;
++	SPRINT_BUF(namefrm);
++	SPRINT_BUF(out);
++	size_t done;
++
++	if (!attr)
++		return;
++
++	value = rta_getattr_u16(attr);
++	mask = mask_attr ? rta_getattr_u16(mask_attr) : UINT16_MAX;
++
++	done = sprintf(out, "%u", value);
++	if (mask != UINT16_MAX)
++		sprintf(out + done, "/0x%x", mask);
++
++	sprintf(namefrm, " %s %%s", name);
++	print_string(PRINT_ANY, name, namefrm, out);
++}
+diff --git a/tc/tc_util.h b/tc/tc_util.h
+index eb4b60db3fdd7..0c3425abc62fa 100644
+--- a/tc/tc_util.h
++++ b/tc/tc_util.h
+@@ -127,4 +127,8 @@ int action_a2n(char *arg, int *result, bool allow_num);
+ 
+ bool tc_qdisc_block_exists(__u32 block_index);
+ 
++void print_masked_u32(const char *name, struct rtattr *attr,
++		      struct rtattr *mask_attr);
++void print_masked_u16(const char *name, struct rtattr *attr,
++		      struct rtattr *mask_attr);
+ #endif
+-- 
+2.26.2
+
diff --git a/SOURCES/0036-tc-flower-Add-matching-on-conntrack-info.patch b/SOURCES/0036-tc-flower-Add-matching-on-conntrack-info.patch
new file mode 100644
index 0000000..9de9989
--- /dev/null
+++ b/SOURCES/0036-tc-flower-Add-matching-on-conntrack-info.patch
@@ -0,0 +1,393 @@
+From b60d960c65c6aa5695ecf1c71b18790ca0cb475c Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Tue, 9 Jun 2020 15:45:56 +0200
+Subject: [PATCH] tc: flower: Add matching on conntrack info
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1844637
+Upstream Status: iproute2.git commit 2fffb1c03056e
+
+commit 2fffb1c03056e71d49d623f7ca460883fa6110a6
+Author: Paul Blakey <paulb@mellanox.com>
+Date:   Thu Jul 11 11:14:27 2019 +0300
+
+    tc: flower: Add matching on conntrack info
+
+    Matches on conntrack state, zone, mark, and label.
+
+    Signed-off-by: Paul Blakey <paulb@mellanox.com>
+    Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
+    Signed-off-by: Yossi Kuperman <yossiku@mellanox.com>
+    Acked-by: Jiri Pirko <jiri@mellanox.com>
+    Acked-by: Roi Dayan <roid@mellanox.com>
+    Signed-off-by: David Ahern <dsahern@gmail.com>
+---
+ man/man8/tc-flower.8 |  35 ++++++
+ tc/f_flower.c        | 276 ++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 310 insertions(+), 1 deletion(-)
+
+diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
+index f41b0f7f1ef13..0f95f303f23b7 100644
+--- a/man/man8/tc-flower.8
++++ b/man/man8/tc-flower.8
+@@ -295,6 +295,41 @@ bits is assumed.
+ .TQ
+ .BI enc_ttl " NUMBER"
+ .TQ
++.BR
++.TP
++.BI ct_state " CT_STATE"
++.TQ
++.BI ct_zone " CT_MASKED_ZONE"
++.TQ
++.BI ct_mark " CT_MASKED_MARK"
++.TQ
++.BI ct_label " CT_MASKED_LABEL"
++Matches on connection tracking info
++.RS
++.TP
++.I CT_STATE
++Match the connection state, and can ne combination of [{+|-}flag] flags, where flag can be one of
++.RS
++.TP
++trk - Tracked connection.
++.TP
++new - New connection.
++.TP
++est - Established connection.
++.TP
++Example: +trk+est
++.RE
++.TP
++.I CT_MASKED_ZONE
++Match the connection zone, and can be masked.
++.TP
++.I CT_MASKED_MARK
++32bit match on the connection mark, and can be masked.
++.TP
++.I CT_MASKED_LABEL
++128bit match on the connection label, and can be masked.
++.RE
++.TP
+ .BI geneve_opts " OPTIONS"
+ .TQ
+ .BI vxlan_opts " OPTIONS"
+diff --git a/tc/f_flower.c b/tc/f_flower.c
+index 691541ec59d4c..0a6eaa0df94ce 100644
+--- a/tc/f_flower.c
++++ b/tc/f_flower.c
+@@ -84,9 +84,14 @@ static void explain(void)
+ 		"			vxlan_opts MASKED-OPTIONS |\n"
+ 		"                       erspan_opts MASKED-OPTIONS |\n"
+ 		"			ip_flags IP-FLAGS | \n"
+-		"			enc_dst_port [ port_number ] }\n"
++		"			enc_dst_port [ port_number ] |\n"
++		"			ct_state MASKED_CT_STATE |\n"
++		"			ct_label MASKED_CT_LABEL |\n"
++		"			ct_mark MASKED_CT_MARK |\n"
++		"			ct_zone MASKED_CT_ZONE }\n"
+ 		"	FILTERID := X:Y:Z\n"
+ 		"	MASKED_LLADDR := { LLADDR | LLADDR/MASK | LLADDR/BITS }\n"
++		"	MASKED_CT_STATE := combination of {+|-} and flags trk,est,new\n"
+ 		"	ACTION-SPEC := ... look at individual actions\n"
+ 		"\n"
+ 		"NOTE:	CLASSID, IP-PROTO are parsed as hexadecimal input.\n"
+@@ -216,6 +221,159 @@ static int flower_parse_matching_flags(char *str,
+ 	return 0;
+ }
+ 
++static int flower_parse_u16(char *str, int value_type, int mask_type,
++			    struct nlmsghdr *n)
++{
++	__u16 value, mask;
++	char *slash;
++
++	slash = strchr(str, '/');
++	if (slash)
++		*slash = '\0';
++
++	if (get_u16(&value, str, 0))
++		return -1;
++
++	if (slash) {
++		if (get_u16(&mask, slash + 1, 0))
++			return -1;
++	} else {
++		mask = UINT16_MAX;
++	}
++
++	addattr16(n, MAX_MSG, value_type, value);
++	addattr16(n, MAX_MSG, mask_type, mask);
++
++	return 0;
++}
++
++static int flower_parse_u32(char *str, int value_type, int mask_type,
++			    struct nlmsghdr *n)
++{
++	__u32 value, mask;
++	char *slash;
++
++	slash = strchr(str, '/');
++	if (slash)
++		*slash = '\0';
++
++	if (get_u32(&value, str, 0))
++		return -1;
++
++	if (slash) {
++		if (get_u32(&mask, slash + 1, 0))
++			return -1;
++	} else {
++		mask = UINT32_MAX;
++	}
++
++	addattr32(n, MAX_MSG, value_type, value);
++	addattr32(n, MAX_MSG, mask_type, mask);
++
++	return 0;
++}
++
++static int flower_parse_ct_mark(char *str, struct nlmsghdr *n)
++{
++	return flower_parse_u32(str,
++				TCA_FLOWER_KEY_CT_MARK,
++				TCA_FLOWER_KEY_CT_MARK_MASK,
++				n);
++}
++
++static int flower_parse_ct_zone(char *str, struct nlmsghdr *n)
++{
++	return flower_parse_u16(str,
++				TCA_FLOWER_KEY_CT_ZONE,
++				TCA_FLOWER_KEY_CT_ZONE_MASK,
++				n);
++}
++
++static int flower_parse_ct_labels(char *str, struct nlmsghdr *n)
++{
++#define LABELS_SIZE	16
++	uint8_t labels[LABELS_SIZE], lmask[LABELS_SIZE];
++	char *slash, *mask = NULL;
++	size_t slen, slen_mask = 0;
++
++	slash = index(str, '/');
++	if (slash) {
++		*slash = 0;
++		mask = slash + 1;
++		slen_mask = strlen(mask);
++	}
++
++	slen = strlen(str);
++	if (slen > LABELS_SIZE * 2 || slen_mask > LABELS_SIZE * 2) {
++		char errmsg[128];
++
++		snprintf(errmsg, sizeof(errmsg),
++				"%zd Max allowed size %d",
++				slen, LABELS_SIZE*2);
++		invarg(errmsg, str);
++	}
++
++	if (hex2mem(str, labels, slen / 2) < 0)
++		invarg("labels must be a hex string\n", str);
++	addattr_l(n, MAX_MSG, TCA_FLOWER_KEY_CT_LABELS, labels, slen / 2);
++
++	if (mask) {
++		if (hex2mem(mask, lmask, slen_mask / 2) < 0)
++			invarg("labels mask must be a hex string\n", mask);
++	} else {
++		memset(lmask, 0xff, sizeof(lmask));
++		slen_mask = sizeof(lmask) * 2;
++	}
++	addattr_l(n, MAX_MSG, TCA_FLOWER_KEY_CT_LABELS_MASK, lmask,
++		  slen_mask / 2);
++
++	return 0;
++}
++
++static struct flower_ct_states {
++	char *str;
++	int flag;
++} flower_ct_states[] = {
++	{ "trk", TCA_FLOWER_KEY_CT_FLAGS_TRACKED },
++	{ "new", TCA_FLOWER_KEY_CT_FLAGS_NEW },
++	{ "est", TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED },
++};
++
++static int flower_parse_ct_state(char *str, struct nlmsghdr *n)
++{
++	int flags = 0, mask = 0,  len, i;
++	bool p;
++
++	while (*str != '\0') {
++		if (*str == '+')
++			p = true;
++		else if (*str == '-')
++			p = false;
++		else
++			return -1;
++
++		for (i = 0; i < ARRAY_SIZE(flower_ct_states); i++) {
++			len = strlen(flower_ct_states[i].str);
++			if (strncmp(str + 1, flower_ct_states[i].str, len))
++				continue;
++
++			if (p)
++				flags |= flower_ct_states[i].flag;
++			mask |= flower_ct_states[i].flag;
++			break;
++		}
++
++		if (i == ARRAY_SIZE(flower_ct_states))
++			return -1;
++
++		str += len + 1;
++	}
++
++	addattr16(n, MAX_MSG, TCA_FLOWER_KEY_CT_STATE, flags);
++	addattr16(n, MAX_MSG, TCA_FLOWER_KEY_CT_STATE_MASK, mask);
++	return 0;
++}
++
+ static int flower_parse_ip_proto(char *str, __be16 eth_type, int type,
+ 				 __u8 *p_ip_proto, struct nlmsghdr *n)
+ {
+@@ -1077,6 +1235,34 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
+ 			flags |= TCA_CLS_FLAGS_SKIP_HW;
+ 		} else if (matches(*argv, "skip_sw") == 0) {
+ 			flags |= TCA_CLS_FLAGS_SKIP_SW;
++		} else if (matches(*argv, "ct_state") == 0) {
++			NEXT_ARG();
++			ret = flower_parse_ct_state(*argv, n);
++			if (ret < 0) {
++				fprintf(stderr, "Illegal \"ct_state\"\n");
++				return -1;
++			}
++		} else if (matches(*argv, "ct_zone") == 0) {
++			NEXT_ARG();
++			ret = flower_parse_ct_zone(*argv, n);
++			if (ret < 0) {
++				fprintf(stderr, "Illegal \"ct_zone\"\n");
++				return -1;
++			}
++		} else if (matches(*argv, "ct_mark") == 0) {
++			NEXT_ARG();
++			ret = flower_parse_ct_mark(*argv, n);
++			if (ret < 0) {
++				fprintf(stderr, "Illegal \"ct_mark\"\n");
++				return -1;
++			}
++		} else if (matches(*argv, "ct_label") == 0) {
++			NEXT_ARG();
++			ret = flower_parse_ct_labels(*argv, n);
++			if (ret < 0) {
++				fprintf(stderr, "Illegal \"ct_label\"\n");
++				return -1;
++			}
+ 		} else if (matches(*argv, "indev") == 0) {
+ 			NEXT_ARG();
+ 			if (check_ifname(*argv))
+@@ -1783,6 +1969,85 @@ static void flower_print_tcp_flags(const char *name, struct rtattr *flags_attr,
+ 	print_string(PRINT_ANY, name, namefrm, out);
+ }
+ 
++static void flower_print_ct_state(struct rtattr *flags_attr,
++				  struct rtattr *mask_attr)
++{
++	SPRINT_BUF(out);
++	uint16_t state;
++	uint16_t state_mask;
++	size_t done = 0;
++	int i;
++
++	if (!flags_attr)
++		return;
++
++	state = rta_getattr_u16(flags_attr);
++	if (mask_attr)
++		state_mask = rta_getattr_u16(mask_attr);
++	else
++		state_mask = UINT16_MAX;
++
++	for (i = 0; i < ARRAY_SIZE(flower_ct_states); i++) {
++		if (!(state_mask & flower_ct_states[i].flag))
++			continue;
++
++		if (state & flower_ct_states[i].flag)
++			done += sprintf(out + done, "+%s",
++					flower_ct_states[i].str);
++		else
++			done += sprintf(out + done, "-%s",
++					flower_ct_states[i].str);
++	}
++
++	print_string(PRINT_ANY, "ct_state", "\n  ct_state %s", out);
++}
++
++static void flower_print_ct_label(struct rtattr *attr,
++				  struct rtattr *mask_attr)
++{
++	const unsigned char *str;
++	bool print_mask = false;
++	int data_len, i;
++	SPRINT_BUF(out);
++	char *p;
++
++	if (!attr)
++		return;
++
++	data_len = RTA_PAYLOAD(attr);
++	hexstring_n2a(RTA_DATA(attr), data_len, out, sizeof(out));
++	p = out + data_len*2;
++
++	data_len = RTA_PAYLOAD(attr);
++	str = RTA_DATA(mask_attr);
++	if (data_len != 16)
++		print_mask = true;
++	for (i = 0; !print_mask && i < data_len; i++) {
++		if (str[i] != 0xff)
++			print_mask = true;
++	}
++	if (print_mask) {
++		*p++ = '/';
++		hexstring_n2a(RTA_DATA(mask_attr), data_len, p,
++			      sizeof(out)-(p-out));
++		p += data_len*2;
++	}
++	*p = '\0';
++
++	print_string(PRINT_ANY, "ct_label", "\n  ct_label %s", out);
++}
++
++static void flower_print_ct_zone(struct rtattr *attr,
++				 struct rtattr *mask_attr)
++{
++	print_masked_u16("ct_zone", attr, mask_attr);
++}
++
++static void flower_print_ct_mark(struct rtattr *attr,
++				 struct rtattr *mask_attr)
++{
++	print_masked_u32("ct_mark", attr, mask_attr);
++}
+ 
+ static void flower_print_key_id(const char *name, struct rtattr *attr)
+ {
+@@ -2218,6 +2483,15 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
+ 				    tb[TCA_FLOWER_KEY_FLAGS],
+ 				    tb[TCA_FLOWER_KEY_FLAGS_MASK]);
+ 
++	flower_print_ct_state(tb[TCA_FLOWER_KEY_CT_STATE],
++			      tb[TCA_FLOWER_KEY_CT_STATE_MASK]);
++	flower_print_ct_zone(tb[TCA_FLOWER_KEY_CT_ZONE],
++			     tb[TCA_FLOWER_KEY_CT_ZONE_MASK]);
++	flower_print_ct_mark(tb[TCA_FLOWER_KEY_CT_MARK],
++			     tb[TCA_FLOWER_KEY_CT_MARK_MASK]);
++	flower_print_ct_label(tb[TCA_FLOWER_KEY_CT_LABELS],
++			      tb[TCA_FLOWER_KEY_CT_LABELS_MASK]);
++
+ 	close_json_object();
+ 
+ 	if (tb[TCA_FLOWER_FLAGS]) {
+-- 
+2.26.2
+
diff --git a/SOURCES/0037-man-tc-ct.8-Add-manual-page-for-ct-tc-action.patch b/SOURCES/0037-man-tc-ct.8-Add-manual-page-for-ct-tc-action.patch
new file mode 100644
index 0000000..5888574
--- /dev/null
+++ b/SOURCES/0037-man-tc-ct.8-Add-manual-page-for-ct-tc-action.patch
@@ -0,0 +1,154 @@
+From 7c371119412595ad2d063b91fdea616dcacb4eed Mon Sep 17 00:00:00 2001
+From: Andrea Claudi <aclaudi@redhat.com>
+Date: Tue, 9 Jun 2020 15:45:56 +0200
+Subject: [PATCH] man: tc-ct.8: Add manual page for ct tc action
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1844637
+Upstream Status: iproute2.git commit 924c43778a845
+
+commit 924c43778a8453e2cd0fd1440b9224bed9c87c0d
+Author: Paul Blakey <paulb@mellanox.com>
+Date:   Thu May 14 17:10:20 2020 +0300
+
+    man: tc-ct.8: Add manual page for ct tc action
+
+    Signed-off-by: Paul Blakey <paulb@mellanox.com>
+    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
+---
+ man/man8/tc-ct.8     | 107 +++++++++++++++++++++++++++++++++++++++++++
+ man/man8/tc-flower.8 |   6 +++
+ 2 files changed, 113 insertions(+)
+ create mode 100644 man/man8/tc-ct.8
+
+diff --git a/man/man8/tc-ct.8 b/man/man8/tc-ct.8
+new file mode 100644
+index 0000000000000..45d29320f1d01
+--- /dev/null
++++ b/man/man8/tc-ct.8
+@@ -0,0 +1,107 @@
++.TH "ct action in tc" 8 "14 May 2020" "iproute2" "Linux"
++.SH NAME
++ct \- tc connection tracking action
++.SH SYNOPSIS
++.in +8
++.ti -8
++.BR "tc ... action ct commit [ force ] [ zone "
++.IR ZONE
++.BR "] [ mark "
++.IR MASKED_MARK
++.BR "] [ label "
++.IR MASKED_LABEL
++.BR "] [ nat "
++.IR NAT_SPEC
++.BR "]"
++
++.ti -8
++.BR "tc ... action ct [ nat ] [ zone "
++.IR ZONE
++.BR "]"
++
++.ti -8
++.BR "tc ... action ct clear"
++
++.SH DESCRIPTION
++The ct action is a tc action for sending packets and interacting with the netfilter conntrack module.
++
++It can (as shown in the synopsis, in order):
++
++Send the packet to conntrack, and commit the connection, while configuring
++a 32bit mark, 128bit label, and src/dst nat.
++
++Send the packet to conntrack, which will mark the packet with the connection's state and
++configured metadata (mark/label), and execute previous configured nat.
++
++Clear the packet's of previous connection tracking state.
++
++.SH OPTIONS
++.TP
++.BI zone " ZONE"
++Specify a conntrack zone number on which to send the packet to conntrack.
++.TP
++.BI mark " MASKED_MARK"
++Specify a masked 32bit mark to set for the connection (only valid with commit).
++.TP
++.BI label " MASKED_LABEL"
++Specify a masked 128bit label to set for the connection (only valid with commit).
++.TP
++.BI nat " NAT_SPEC"
++.BI Where " NAT_SPEC " ":= {src|dst} addr" " addr1" "[-" "addr2" "] [port " "port1" "[-" "port2" "]]"
++
++Specify src/dst and range of nat to configure for the connection (only valid with commit).
++.RS
++.TP
++src/dst - configure src or dst nat
++.TP
++.BI  "" "addr1" "/" "addr2" " - IPv4/IPv6 addresses"
++.TP
++.BI  "" "port1" "/" "port2" " - Port numbers"
++.RE
++.TP
++.BI nat
++Restore any previous configured nat.
++.TP
++.BI clear
++Remove any conntrack state and metadata (mark/label) from the packet (must only option specified).
++.TP
++.BI force
++Forces conntrack direction for a previously commited connections, so that current direction will become the original direction (only valid with commit).
++
++.SH EXAMPLES
++Example showing natted firewall in conntrack zone 2, and conntrack mark usage:
++.EX
++
++#Add ingress qdisc on eth0 and eth1 interfaces
++.nf
++$ tc qdisc add dev eth0 handle ingress
++$ tc qdisc add dev eth1 handle ingress
++
++#Setup filters on eth0, allowing opening new connections in zone 2, and doing src nat + mark for each new connection
++$ tc filter add dev eth0 ingress prio 1 chain 0 proto ip flower ip_proto tcp ct_state -trk \\
++action ct zone 2 pipe action goto chain 2
++$ tc filter add dev eth0 ingress prio 1 chain 2 proto ip flower ct_state +trk+new \\
++action ct zone 2 commit mark 0xbb nat src addr 5.5.5.7 pipe action mirred egress redirect dev eth1
++$ tc filter add dev eth0 ingress prio 1 chain 2 proto ip flower ct_zone 2 ct_mark 0xbb ct_state +trk+est \\
++action ct nat pipe action mirred egress redirect dev eth1
++
++#Setup filters on eth1, allowing only established connections of zone 2 through, and reverse nat (dst nat in this case)
++$ tc filter add dev eth1 ingress prio 1 chain 0 proto ip flower ip_proto tcp ct_state -trk \\
++action ct zone 2 pipe action goto chain 1
++$ tc filter add dev eth1 ingress prio 1 chain 1 proto ip flower ct_zone 2 ct_mark 0xbb ct_state +trk+est \\
++action ct nat pipe action mirred egress redirect dev eth0
++.fi
++
++.EE
++
++.RE
++.SH SEE ALSO
++.BR tc (8),
++.BR tc-flower (8)
++.BR tc-mirred (8)
++.SH AUTHORS
++Paul Blakey <paulb@mellanox.com>
++
++Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
++
++Yossi Kuperman <yossiku@mellanox.com>
+diff --git a/man/man8/tc-flower.8 b/man/man8/tc-flower.8
+index 0f95f303f23b7..02a7256f36ebb 100644
+--- a/man/man8/tc-flower.8
++++ b/man/man8/tc-flower.8
+@@ -1,5 +1,11 @@
+ .TH "Flower filter in tc" 8 "22 Oct 2015" "iproute2" "Linux"
+ 
++	"Usage: ct clear\n"
++		"	ct commit [force] [zone ZONE] [mark MASKED_MARK] [label MASKED_LABEL] [nat NAT_SPEC] [OFFLOAD_POLICY]\n"
++		"	ct [nat] [zone ZONE] [OFFLOAD_POLICY]\n"
++		"Where: ZONE is the conntrack zone table number\n"
++		"	NAT_SPEC is {src|dst} addr addr1[-addr2] [port port1[-port2]]\n"
++		"	OFFLOAD_POLICY is [policy_pkts PACKETS] [policy_timeout TIMEOUT]\n"
+ .SH NAME
+ flower \- flow based traffic control filter
+ .SH SYNOPSIS
+-- 
+2.26.2
+
diff --git a/SPECS/iproute.spec b/SPECS/iproute.spec
index 43be57b..9c2fe0a 100644
--- a/SPECS/iproute.spec
+++ b/SPECS/iproute.spec
@@ -1,5 +1,5 @@
 %define rpmversion 5.3.0
-%define specrelease 1%{?dist}
+%define specrelease 5%{?dist}
 %define pkg_release %{specrelease}%{?buildid}
 
 Summary:            Advanced IP routing and network device configuration tools
@@ -12,6 +12,43 @@ Source0:            http://kernel.org/pub/linux/utils/net/%{name}2/%{name}2-%{ve
 Source1:            cbq-0000.example
 Source2:            avpkt
 Source3:            rt_dsfield.deprecated
+Patch0:             0001-Update-kernel-headers.patch
+Patch1:             0002-Update-kernel-headers.patch
+Patch2:             0003-tc-implement-support-for-action-flags.patch
+Patch3:             0004-man-rdma-statistic-Add-filter-description.patch
+Patch4:             0005-man-rdma.8-Add-missing-resource-subcommand-descripti.patch
+Patch5:             0006-ip-xfrm-Fix-help-messages.patch
+Patch6:             0007-xfrm-not-try-to-delete-ipcomp-states-when-using-dele.patch
+Patch7:             0008-man-ip.8-Add-missing-vrf-subcommand-description.patch
+Patch8:             0009-nstat-print-useful-error-messages-in-abort-cases.patch
+Patch9:             0010-ip-link-xstats-fix-TX-IGMP-reports-string.patch
+Patch10:            0011-ip-fix-ip-route-show-json-output-for-multipath-nexth.patch
+Patch11:            0012-man-bridge.8-fix-bridge-link-show-description.patch
+Patch12:            0013-xfrm-also-check-for-ipv6-state-in-xfrm_state_keep.patch
+Patch13:            0014-Update-kernel-headers-and-import-udp.h.patch
+Patch14:            0015-ip-xfrm-add-espintcp-encapsulation.patch
+Patch15:            0016-Update-kernel-headers-and-import-mptcp.h.patch
+Patch16:            0017-add-support-for-mptcp-netlink-interface.patch
+Patch17:            0018-Update-kernel-headers.patch
+Patch18:            0019-Update-kernel-headers.patch
+Patch19:            0020-ss-allow-dumping-MPTCP-subflow-information.patch
+Patch20:            0021-man-mptcp-man-page.patch
+Patch21:            0022-man-ip.8-add-reference-to-mptcp-man-page.patch
+Patch22:            0023-Update-kernel-headers.patch
+Patch23:            0024-iproute_lwtunnel-add-options-support-for-geneve-meta.patch
+Patch24:            0025-iproute_lwtunnel-add-options-support-for-vxlan-metad.patch
+Patch25:            0026-iproute_lwtunnel-add-options-support-for-erspan-meta.patch
+Patch26:            0027-tc-m_tunnel_key-add-options-support-for-vxlan.patch
+Patch27:            0028-tc-m_tunnel_key-add-options-support-for-erpsan.patch
+Patch28:            0029-tc-f_flower-add-options-support-for-vxlan.patch
+Patch29:            0030-tc-f_flower-add-options-support-for-erspan.patch
+Patch30:            0031-devlink-Add-health-error-recovery-status-monitoring.patch
+Patch31:            0032-ss-allow-dumping-kTLS-info.patch
+Patch32:            0033-Import-tc_act-tc_ct.h-uapi-file.patch
+Patch33:            0034-tc-add-NLA_F_NESTED-flag-to-all-actions-options-nest.patch
+Patch34:            0035-tc-Introduce-tc-ct-action.patch
+Patch35:            0036-tc-flower-Add-matching-on-conntrack-info.patch
+Patch36:            0037-man-tc-ct.8-Add-manual-page-for-ct-tc-action.patch
 License:            GPLv2+ and Public Domain
 BuildRequires:      bison
 BuildRequires:      elfutils-libelf-devel
@@ -156,6 +193,51 @@ cat %{SOURCE3} >>%{buildroot}%{_sysconfdir}/iproute2/rt_dsfield
 %{_includedir}/iproute2/bpf_elf.h
 
 %changelog
+* Mon Jun 29 2020 Andrea Claudi <aclaudi@redhat.com> [5.3.0-5.el8]
+- man: tc-ct.8: Add manual page for ct tc action (Andrea Claudi) [1844637]
+- tc: flower: Add matching on conntrack info (Andrea Claudi) [1844637]
+- tc: Introduce tc ct action (Andrea Claudi) [1844637]
+- tc: add NLA_F_NESTED flag to all actions options nested block (Andrea Claudi) [1844637]
+- Import tc_act/tc_ct.h uapi file (Andrea Claudi) [1844637]
+- ss: allow dumping kTLS info (Andrea Claudi) [1812207]
+- devlink: Add health error recovery status monitoring (Andrea Claudi) [1821039]
+
+* Fri Jun 05 2020 Andrea Claudi <aclaudi@redhat.com> [5.3.0-4.el8]
+- tc: f_flower: add options support for erspan (Andrea Claudi) [1830485]
+- tc: f_flower: add options support for vxlan (Andrea Claudi) [1830485]
+- tc: m_tunnel_key: add options support for erpsan (Andrea Claudi) [1830485]
+- tc: m_tunnel_key: add options support for vxlan (Andrea Claudi) [1830485]
+- iproute_lwtunnel: add options support for erspan metadata (Andrea Claudi) [1830485]
+- iproute_lwtunnel: add options support for vxlan metadata (Andrea Claudi) [1830485]
+- iproute_lwtunnel: add options support for geneve metadata (Andrea Claudi) [1830485]
+- Update kernel headers (Andrea Claudi) [1830485]
+- man: ip.8: add reference to mptcp man-page (Andrea Claudi) [1812207]
+- man: mptcp man page (Andrea Claudi) [1812207]
+- ss: allow dumping MPTCP subflow information (Andrea Claudi) [1812207]
+- Update kernel headers (Andrea Claudi) [1812207]
+- Update kernel headers (Andrea Claudi) [1812207]
+- add support for mptcp netlink interface (Andrea Claudi) [1812207]
+- Update kernel headers and import mptcp.h (Andrea Claudi) [1812207]
+- ip: xfrm: add espintcp encapsulation (Andrea Claudi) [1844045]
+- Update kernel headers and import udp.h (Andrea Claudi) [1844045]
+
+* Thu Apr 30 2020 Andrea Claudi <aclaudi@redhat.com> [5.3.0-3.el8]
+- xfrm: also check for ipv6 state in xfrm_state_keep (Andrea Claudi) [1828033]
+- man: bridge.8: fix bridge link show description (Andrea Claudi) [1817571]
+- ip: fix ip route show json output for multipath nexthops (Andrea Claudi) [1738633]
+- ip link: xstats: fix TX IGMP reports string (Andrea Claudi) [1796041]
+- nstat: print useful error messages in abort() cases (Andrea Claudi) [1824896]
+
+* Thu Apr 23 2020 Andrea Claudi <aclaudi@redhat.com> [5.3.0-2.el8]
+- man: ip.8: Add missing vrf subcommand description (Andrea Claudi) [1780010]
+- xfrm: not try to delete ipcomp states when using deleteall (Andrea Claudi) [1808634]
+- ip-xfrm: Fix help messages (Andrea Claudi) [1796045]
+- man: rdma.8: Add missing resource subcommand description (Andrea Claudi) [1786576]
+- man: rdma-statistic: Add filter description (Andrea Claudi) [1786565]
+- tc: implement support for action flags (Andrea Claudi) [1770671]
+- Update kernel headers (Andrea Claudi) [1770671]
+- Update kernel headers (Andrea Claudi) [1770671]
+
 * Tue Oct 15 2019 Andrea Claudi <aclaudi@redhat.com> [5.3.0-1.el8]
 - New version 5.3.0 [1752857]