Merge branch 'master' into net-next
diff --git a/bridge/vlan.c b/bridge/vlan.c
index c2e635f..d3505b5 100644
--- a/bridge/vlan.c
+++ b/bridge/vlan.c
@@ -188,7 +188,7 @@
 	struct ifinfomsg *ifm = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
 	struct rtattr *tb[IFLA_MAX+1];
-	bool vlan_flags;
+	bool vlan_flags = false;
 
 	if (n->nlmsg_type != RTM_NEWLINK) {
 		fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n",
@@ -276,7 +276,7 @@
 					fprintf(fp, " Egress Untagged");
 				}
 			}
-			if (vlan_flags) {
+			if (jw_global && vlan_flags) {
 				jsonw_end_array(jw_global);
 				vlan_flags = false;
 			}
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 5e4d373..19e0c36 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -84,6 +84,7 @@
 	BPF_MAP_TYPE_PERCPU_HASH,
 	BPF_MAP_TYPE_PERCPU_ARRAY,
 	BPF_MAP_TYPE_STACK_TRACE,
+	BPF_MAP_TYPE_CGROUP_ARRAY,
 };
 
 enum bpf_prog_type {
@@ -93,6 +94,7 @@
 	BPF_PROG_TYPE_SCHED_CLS,
 	BPF_PROG_TYPE_SCHED_ACT,
 	BPF_PROG_TYPE_TRACEPOINT,
+	BPF_PROG_TYPE_XDP,
 };
 
 #define BPF_PSEUDO_MAP_FD	1
@@ -313,6 +315,66 @@
 	 */
 	BPF_FUNC_skb_get_tunnel_opt,
 	BPF_FUNC_skb_set_tunnel_opt,
+
+	/**
+	 * bpf_skb_change_proto(skb, proto, flags)
+	 * Change protocol of the skb. Currently supported is
+	 * v4 -> v6, v6 -> v4 transitions. The helper will also
+	 * resize the skb. eBPF program is expected to fill the
+	 * new headers via skb_store_bytes and lX_csum_replace.
+	 * @skb: pointer to skb
+	 * @proto: new skb->protocol type
+	 * @flags: reserved
+	 * Return: 0 on success or negative error
+	 */
+	BPF_FUNC_skb_change_proto,
+
+	/**
+	 * bpf_skb_change_type(skb, type)
+	 * Change packet type of skb.
+	 * @skb: pointer to skb
+	 * @type: new skb->pkt_type type
+	 * Return: 0 on success or negative error
+	 */
+	BPF_FUNC_skb_change_type,
+
+	/**
+	 * bpf_skb_in_cgroup(skb, map, index) - Check cgroup2 membership of skb
+	 * @skb: pointer to skb
+	 * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type
+	 * @index: index of the cgroup in the bpf_map
+	 * Return:
+	 *   == 0 skb failed the cgroup2 descendant test
+	 *   == 1 skb succeeded the cgroup2 descendant test
+	 *    < 0 error
+	 */
+	BPF_FUNC_skb_in_cgroup,
+
+	/**
+	 * bpf_get_hash_recalc(skb)
+	 * Retrieve and possibly recalculate skb->hash.
+	 * @skb: pointer to skb
+	 * Return: hash
+	 */
+	BPF_FUNC_get_hash_recalc,
+
+	/**
+	 * u64 bpf_get_current_task(void)
+	 * Returns current task_struct
+	 * Return: current
+	 */
+	BPF_FUNC_get_current_task,
+
+	/**
+	 * bpf_probe_write_user(void *dst, void *src, int len)
+	 * safely attempt to write to a location
+	 * @dst: destination address in userspace
+	 * @src: source address on stack
+	 * @len: number of bytes to copy
+	 * Return: 0 on success or negative error
+	 */
+	BPF_FUNC_probe_write_user,
+
 	__BPF_FUNC_MAX_ID,
 };
 
@@ -347,9 +409,11 @@
 #define BPF_F_ZERO_CSUM_TX		(1ULL << 1)
 #define BPF_F_DONT_FRAGMENT		(1ULL << 2)
 
-/* BPF_FUNC_perf_event_output flags. */
+/* BPF_FUNC_perf_event_output and BPF_FUNC_perf_event_read flags. */
 #define BPF_F_INDEX_MASK		0xffffffffULL
 #define BPF_F_CURRENT_CPU		BPF_F_INDEX_MASK
+/* BPF_FUNC_perf_event_output for sk_buff input context. */
+#define BPF_F_CTXLEN_MASK		(0xfffffULL << 32)
 
 /* user accessible mirror of in-kernel sk_buff.
  * new fields can only be added to the end of this structure
@@ -386,4 +450,24 @@
 	__u32 tunnel_label;
 };
 
+/* User return codes for XDP prog type.
+ * A valid XDP program must return one of these defined values. All other
+ * return codes are reserved for future use. Unknown return codes will result
+ * in packet drop.
+ */
+enum xdp_action {
+	XDP_ABORTED = 0,
+	XDP_DROP,
+	XDP_PASS,
+	XDP_TX,
+};
+
+/* user accessible metadata for XDP packet hook
+ * new fields must be added to the end of this structure
+ */
+struct xdp_md {
+	__u32 data;
+	__u32 data_end;
+};
+
 #endif /* __LINUX_BPF_H__ */
diff --git a/include/linux/devlink.h b/include/linux/devlink.h
index 0e21d00..b7c1a06 100644
--- a/include/linux/devlink.h
+++ b/include/linux/devlink.h
@@ -57,6 +57,8 @@
 	DEVLINK_CMD_SB_OCC_SNAPSHOT,
 	DEVLINK_CMD_SB_OCC_MAX_CLEAR,
 
+	DEVLINK_CMD_ESWITCH_MODE_GET,
+	DEVLINK_CMD_ESWITCH_MODE_SET,
 	/* add new commands above here */
 
 	__DEVLINK_CMD_MAX,
@@ -95,6 +97,11 @@
 
 #define DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX 20
 
+enum devlink_eswitch_mode {
+	DEVLINK_ESWITCH_MODE_LEGACY,
+	DEVLINK_ESWITCH_MODE_SWITCHDEV,
+};
+
 enum devlink_attr {
 	/* don't change the order or add anything between, this is ABI! */
 	DEVLINK_ATTR_UNSPEC,
@@ -125,6 +132,7 @@
 	DEVLINK_ATTR_SB_TC_INDEX,		/* u16 */
 	DEVLINK_ATTR_SB_OCC_CUR,		/* u32 */
 	DEVLINK_ATTR_SB_OCC_MAX,		/* u32 */
+	DEVLINK_ATTR_ESWITCH_MODE,		/* u16 */
 
 	/* add new attributes above here, update the policy in devlink.c */
 
diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h
index 620c8a5..14404b3 100644
--- a/include/linux/fib_rules.h
+++ b/include/linux/fib_rules.h
@@ -50,6 +50,7 @@
 	FRA_FWMASK,	/* mask for netfilter mark */
 	FRA_OIFNAME,
 	FRA_PAD,
+	FRA_L3MDEV,	/* iif or oif is l3mdev goto its table */
 	__FRA_MAX
 };
 
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index fc3dcfa..d9c76fe 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -247,8 +247,37 @@
 enum {
 	BRIDGE_XSTATS_UNSPEC,
 	BRIDGE_XSTATS_VLAN,
+	BRIDGE_XSTATS_MCAST,
+	BRIDGE_XSTATS_PAD,
 	__BRIDGE_XSTATS_MAX
 };
 #define BRIDGE_XSTATS_MAX (__BRIDGE_XSTATS_MAX - 1)
 
+enum {
+	BR_MCAST_DIR_RX,
+	BR_MCAST_DIR_TX,
+	BR_MCAST_DIR_SIZE
+};
+
+/* IGMP/MLD statistics */
+struct br_mcast_stats {
+	__u64 igmp_v1queries[BR_MCAST_DIR_SIZE];
+	__u64 igmp_v2queries[BR_MCAST_DIR_SIZE];
+	__u64 igmp_v3queries[BR_MCAST_DIR_SIZE];
+	__u64 igmp_leaves[BR_MCAST_DIR_SIZE];
+	__u64 igmp_v1reports[BR_MCAST_DIR_SIZE];
+	__u64 igmp_v2reports[BR_MCAST_DIR_SIZE];
+	__u64 igmp_v3reports[BR_MCAST_DIR_SIZE];
+	__u64 igmp_parse_errors;
+
+	__u64 mld_v1queries[BR_MCAST_DIR_SIZE];
+	__u64 mld_v2queries[BR_MCAST_DIR_SIZE];
+	__u64 mld_leaves[BR_MCAST_DIR_SIZE];
+	__u64 mld_v1reports[BR_MCAST_DIR_SIZE];
+	__u64 mld_v2reports[BR_MCAST_DIR_SIZE];
+	__u64 mld_parse_errors;
+
+	__u64 mcast_bytes[BR_MCAST_DIR_SIZE];
+	__u64 mcast_packets[BR_MCAST_DIR_SIZE];
+};
 #endif /* _LINUX_IF_BRIDGE_H */
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index c396f31..51898e0 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -87,6 +87,7 @@
 #define ETH_P_8021AH	0x88E7          /* 802.1ah Backbone Service Tag */
 #define ETH_P_MVRP	0x88F5          /* 802.1Q MVRP                  */
 #define ETH_P_1588	0x88F7		/* IEEE 1588 Timesync */
+#define ETH_P_NCSI	0x88F8		/* NCSI protocol		*/
 #define ETH_P_PRP	0x88FB		/* IEC 62439-3 PRP/HSRv0	*/
 #define ETH_P_FCOE	0x8906		/* Fibre Channel over Ethernet  */
 #define ETH_P_TDLS	0x890D          /* TDLS */
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 15bbeb8..1feb708 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -156,6 +156,7 @@
 	IFLA_GSO_MAX_SEGS,
 	IFLA_GSO_MAX_SIZE,
 	IFLA_PAD,
+	IFLA_XDP,
 	__IFLA_MAX
 };
 
@@ -271,6 +272,7 @@
 	IFLA_BR_VLAN_DEFAULT_PVID,
 	IFLA_BR_PAD,
 	IFLA_BR_VLAN_STATS_ENABLED,
+	IFLA_BR_MCAST_STATS_ENABLED,
 	__IFLA_BR_MAX,
 };
 
@@ -820,6 +822,7 @@
 	IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */
 	IFLA_STATS_LINK_64,
 	IFLA_STATS_LINK_XSTATS,
+	IFLA_STATS_LINK_XSTATS_SLAVE,
 	__IFLA_STATS_MAX,
 };
 
@@ -839,4 +842,15 @@
 };
 #define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1)
 
+/* XDP section */
+
+enum {
+	IFLA_XDP_UNSPEC,
+	IFLA_XDP_FD,
+	IFLA_XDP_ATTACHED,
+	__IFLA_XDP_MAX,
+};
+
+#define IFLA_XDP_MAX (__IFLA_XDP_MAX - 1)
+
 #endif /* _LINUX_IF_LINK_H */
diff --git a/include/linux/if_macsec.h b/include/linux/if_macsec.h
index cbd4faa..22939a3 100644
--- a/include/linux/if_macsec.h
+++ b/include/linux/if_macsec.h
@@ -26,6 +26,8 @@
 
 #define MACSEC_MIN_ICV_LEN 8
 #define MACSEC_MAX_ICV_LEN 32
+/* upper limit for ICV length as recommended by IEEE802.1AE-2006 */
+#define MACSEC_STD_ICV_LEN 16
 
 enum macsec_attrs {
 	MACSEC_ATTR_UNSPEC,
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index f0201ca..1fa343d 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -113,6 +113,7 @@
 	IFLA_GRE_ENCAP_SPORT,
 	IFLA_GRE_ENCAP_DPORT,
 	IFLA_GRE_COLLECT_METADATA,
+	IFLA_GRE_IGNORE_DF,
 	__IFLA_GRE_MAX,
 };
 
diff --git a/include/linux/in6.h b/include/linux/in6.h
index aa5b66d..45aaaa4 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -143,6 +143,7 @@
 #define IPV6_TLV_PAD1		0
 #define IPV6_TLV_PADN		1
 #define IPV6_TLV_ROUTERALERT	5
+#define IPV6_TLV_CALIPSO	7	/* RFC 5570 */
 #define IPV6_TLV_JUMBO		194
 #define IPV6_TLV_HAO		201	/* home address option */
 
diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
index 07e486c..beb74ee 100644
--- a/include/linux/inet_diag.h
+++ b/include/linux/inet_diag.h
@@ -72,6 +72,7 @@
 	INET_DIAG_BC_AUTO,
 	INET_DIAG_BC_S_COND,
 	INET_DIAG_BC_D_COND,
+	INET_DIAG_BC_DEV_COND,   /* u32 ifindex */
 };
 
 struct inet_diag_hostcond {
diff --git a/include/linux/netlink_diag.h b/include/linux/netlink_diag.h
index f2159d3..defd25f 100644
--- a/include/linux/netlink_diag.h
+++ b/include/linux/netlink_diag.h
@@ -48,6 +48,7 @@
 
 #define NDIAG_SHOW_MEMINFO	0x00000001 /* show memory info of a socket */
 #define NDIAG_SHOW_GROUPS	0x00000002 /* show groups of a netlink socket */
+/* deprecated since 4.6 */
 #define NDIAG_SHOW_RING_CFG	0x00000004 /* show ring configuration */
 
 #endif
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index 333b171..5e6c61e 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -61,8 +61,8 @@
 	__u32			mtu;
 	struct tc_ratespec	rate;
 	struct tc_ratespec	peakrate;
-	int 			refcnt;
-	int 			bindcnt;
+	int			refcnt;
+	int			bindcnt;
 	__u32			capab;
 };
 
@@ -70,10 +70,11 @@
 	__u64   install;
 	__u64   lastuse;
 	__u64   expires;
+	__u64   firstuse;
 };
 
 struct tc_cnt {
-	int                   refcnt; 
+	int                   refcnt;
 	int                   bindcnt;
 };
 
@@ -378,6 +379,18 @@
 
 #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1)
 
+/* Match-all classifier */
+
+enum {
+	TCA_MATCHALL_UNSPEC,
+	TCA_MATCHALL_CLASSID,
+	TCA_MATCHALL_ACT,
+	TCA_MATCHALL_FLAGS,
+	__TCA_MATCHALL_MAX,
+};
+
+#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1)
+
 /* Extended Matches */
 
 struct tcf_ematch_tree_hdr {
diff --git a/include/linux/tc_act/tc_skbedit.h b/include/linux/tc_act/tc_skbedit.h
index fecb5cc..a4d00c6 100644
--- a/include/linux/tc_act/tc_skbedit.h
+++ b/include/linux/tc_act/tc_skbedit.h
@@ -27,6 +27,7 @@
 #define SKBEDIT_F_PRIORITY		0x1
 #define SKBEDIT_F_QUEUE_MAPPING		0x2
 #define SKBEDIT_F_MARK			0x4
+#define SKBEDIT_F_PTYPE			0x8
 
 struct tc_skbedit {
 	tc_gen;
@@ -40,6 +41,7 @@
 	TCA_SKBEDIT_QUEUE_MAPPING,
 	TCA_SKBEDIT_MARK,
 	TCA_SKBEDIT_PAD,
+	TCA_SKBEDIT_PTYPE,
 	__TCA_SKBEDIT_MAX
 };
 #define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 7f21db9..f3dcdb7 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -115,12 +115,22 @@
 #define TCP_CC_INFO		26	/* Get Congestion Control (optional) info */
 #define TCP_SAVE_SYN		27	/* Record SYN headers for new connections */
 #define TCP_SAVED_SYN		28	/* Get SYN headers recorded for connection */
+#define TCP_REPAIR_WINDOW	29	/* Get/set window parameters */
 
 struct tcp_repair_opt {
 	__u32	opt_code;
 	__u32	opt_val;
 };
 
+struct tcp_repair_window {
+	__u32	snd_wl1;
+	__u32	snd_wnd;
+	__u32	max_window;
+
+	__u32	rcv_wnd;
+	__u32	rcv_wup;
+};
+
 enum {
 	TCP_NO_QUEUE,
 	TCP_RECV_QUEUE,
diff --git a/include/linux/tipc.h b/include/linux/tipc.h
index ebd3b63..4004300 100644
--- a/include/linux/tipc.h
+++ b/include/linux/tipc.h
@@ -60,26 +60,48 @@
 	__u32 upper;
 };
 
+/* TIPC Address Size, Offset, Mask specification for Z.C.N
+ */
+#define TIPC_NODE_BITS          12
+#define TIPC_CLUSTER_BITS       12
+#define TIPC_ZONE_BITS          8
+
+#define TIPC_NODE_OFFSET        0
+#define TIPC_CLUSTER_OFFSET     TIPC_NODE_BITS
+#define TIPC_ZONE_OFFSET        (TIPC_CLUSTER_OFFSET + TIPC_CLUSTER_BITS)
+
+#define TIPC_NODE_SIZE          ((1UL << TIPC_NODE_BITS) - 1)
+#define TIPC_CLUSTER_SIZE       ((1UL << TIPC_CLUSTER_BITS) - 1)
+#define TIPC_ZONE_SIZE          ((1UL << TIPC_ZONE_BITS) - 1)
+
+#define TIPC_NODE_MASK		(TIPC_NODE_SIZE << TIPC_NODE_OFFSET)
+#define TIPC_CLUSTER_MASK	(TIPC_CLUSTER_SIZE << TIPC_CLUSTER_OFFSET)
+#define TIPC_ZONE_MASK		(TIPC_ZONE_SIZE << TIPC_ZONE_OFFSET)
+
+#define TIPC_ZONE_CLUSTER_MASK (TIPC_ZONE_MASK | TIPC_CLUSTER_MASK)
+
 static __inline__ __u32 tipc_addr(unsigned int zone,
 			      unsigned int cluster,
 			      unsigned int node)
 {
-	return (zone << 24) | (cluster << 12) | node;
+	return (zone << TIPC_ZONE_OFFSET) |
+		(cluster << TIPC_CLUSTER_OFFSET) |
+		node;
 }
 
 static __inline__ unsigned int tipc_zone(__u32 addr)
 {
-	return addr >> 24;
+	return addr >> TIPC_ZONE_OFFSET;
 }
 
 static __inline__ unsigned int tipc_cluster(__u32 addr)
 {
-	return (addr >> 12) & 0xfff;
+	return (addr & TIPC_CLUSTER_MASK) >> TIPC_CLUSTER_OFFSET;
 }
 
 static __inline__ unsigned int tipc_node(__u32 addr)
 {
-	return addr & 0xfff;
+	return addr & TIPC_NODE_MASK;
 }
 
 /*
diff --git a/include/linux/tipc_netlink.h b/include/linux/tipc_netlink.h
index d4c8f14..5f3f6d0 100644
--- a/include/linux/tipc_netlink.h
+++ b/include/linux/tipc_netlink.h
@@ -56,6 +56,9 @@
 	TIPC_NL_NET_GET,
 	TIPC_NL_NET_SET,
 	TIPC_NL_NAME_TABLE_GET,
+	TIPC_NL_MON_SET,
+	TIPC_NL_MON_GET,
+	TIPC_NL_MON_PEER_GET,
 
 	__TIPC_NL_CMD_MAX,
 	TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1
@@ -72,6 +75,8 @@
 	TIPC_NLA_NODE,			/* nest */
 	TIPC_NLA_NET,			/* nest */
 	TIPC_NLA_NAME_TABLE,		/* nest */
+	TIPC_NLA_MON,			/* nest */
+	TIPC_NLA_MON_PEER,		/* nest */
 
 	__TIPC_NLA_MAX,
 	TIPC_NLA_MAX = __TIPC_NLA_MAX - 1
@@ -166,6 +171,20 @@
 	TIPC_NLA_NAME_TABLE_MAX = __TIPC_NLA_NAME_TABLE_MAX - 1
 };
 
+/* Monitor info */
+enum {
+	TIPC_NLA_MON_UNSPEC,
+	TIPC_NLA_MON_ACTIVATION_THRESHOLD,	/* u32 */
+	TIPC_NLA_MON_REF,			/* u32 */
+	TIPC_NLA_MON_ACTIVE,			/* flag */
+	TIPC_NLA_MON_BEARER_NAME,		/* string */
+	TIPC_NLA_MON_PEERCNT,			/* u32 */
+	TIPC_NLA_MON_LISTGEN,			/* u32 */
+
+	__TIPC_NLA_MON_MAX,
+	TIPC_NLA_MON_MAX = __TIPC_NLA_MON_MAX - 1
+};
+
 /* Publication info */
 enum {
 	TIPC_NLA_PUBL_UNSPEC,
@@ -182,6 +201,24 @@
 	TIPC_NLA_PUBL_MAX = __TIPC_NLA_PUBL_MAX - 1
 };
 
+/* Monitor peer info */
+enum {
+	TIPC_NLA_MON_PEER_UNSPEC,
+
+	TIPC_NLA_MON_PEER_ADDR,			/* u32 */
+	TIPC_NLA_MON_PEER_DOMGEN,		/* u32 */
+	TIPC_NLA_MON_PEER_APPLIED,		/* u32 */
+	TIPC_NLA_MON_PEER_UPMAP,		/* u64 */
+	TIPC_NLA_MON_PEER_MEMBERS,		/* tlv */
+	TIPC_NLA_MON_PEER_UP,			/* flag */
+	TIPC_NLA_MON_PEER_HEAD,			/* flag */
+	TIPC_NLA_MON_PEER_LOCAL,		/* flag */
+	TIPC_NLA_MON_PEER_PAD,			/* flag */
+
+	__TIPC_NLA_MON_PEER_MAX,
+	TIPC_NLA_MON_PEER_MAX = __TIPC_NLA_MON_PEER_MAX - 1
+};
+
 /* Nest, connection info */
 enum {
 	TIPC_NLA_CON_UNSPEC,
diff --git a/ip/iprule.c b/ip/iprule.c
index f3ada82..8f24206 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -37,7 +37,7 @@
 	fprintf(stderr, "       ip rule { flush | save | restore }\n");
 	fprintf(stderr, "       ip rule [ list ]\n");
 	fprintf(stderr, "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n");
-	fprintf(stderr, "            [ iif STRING ] [ oif STRING ] [ pref NUMBER ]\n");
+	fprintf(stderr, "            [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n");
 	fprintf(stderr, "ACTION := [ table TABLE_ID ]\n");
 	fprintf(stderr, "          [ nat ADDRESS ]\n");
 	fprintf(stderr, "          [ realms [SRCREALM/]DSTREALM ]\n");
@@ -57,6 +57,7 @@
 	int host_len = -1;
 	__u32 table;
 	struct rtattr *tb[FRA_MAX+1];
+
 	SPRINT_BUF(b1);
 
 	if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE)
@@ -74,7 +75,8 @@
 		fprintf(fp, "Deleted ");
 
 	if (tb[FRA_PRIORITY])
-		fprintf(fp, "%u:\t", *(unsigned *)RTA_DATA(tb[FRA_PRIORITY]));
+		fprintf(fp, "%u:\t",
+			rta_getattr_u32(tb[FRA_PRIORITY]));
 	else
 		fprintf(fp, "0:\t");
 
@@ -84,11 +86,11 @@
 	if (tb[FRA_SRC]) {
 		if (r->rtm_src_len != host_len) {
 			fprintf(fp, "from %s/%u ",
-			        rt_addr_n2a_rta(r->rtm_family, tb[FRA_SRC]),
-			        r->rtm_src_len);
+				rt_addr_n2a_rta(r->rtm_family, tb[FRA_SRC]),
+				r->rtm_src_len);
 		} else {
 			fprintf(fp, "from %s ",
-			        format_host_rta(r->rtm_family, tb[FRA_SRC]));
+				format_host_rta(r->rtm_family, tb[FRA_SRC]));
 		}
 	} else if (r->rtm_src_len) {
 		fprintf(fp, "from 0/%d ", r->rtm_src_len);
@@ -99,11 +101,11 @@
 	if (tb[FRA_DST]) {
 		if (r->rtm_dst_len != host_len) {
 			fprintf(fp, "to %s/%u ",
-			        rt_addr_n2a_rta(r->rtm_family, tb[FRA_DST]),
-			        r->rtm_dst_len);
+				rt_addr_n2a_rta(r->rtm_family, tb[FRA_DST]),
+				r->rtm_dst_len);
 		} else {
 			fprintf(fp, "to %s ",
-			        format_host_rta(r->rtm_family, tb[FRA_DST]));
+				format_host_rta(r->rtm_family, tb[FRA_DST]));
 		}
 	} else if (r->rtm_dst_len) {
 		fprintf(fp, "to 0/%d ", r->rtm_dst_len);
@@ -111,7 +113,8 @@
 
 	if (r->rtm_tos) {
 		SPRINT_BUF(b1);
-		fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
+		fprintf(fp, "tos %s ",
+			rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
 	}
 
 	if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
@@ -139,23 +142,29 @@
 			fprintf(fp, "[detached] ");
 	}
 
+	if (tb[FRA_L3MDEV]) {
+		if (rta_getattr_u8(tb[FRA_L3MDEV]))
+			fprintf(fp, "lookup [l3mdev-table] ");
+	}
+
 	table = rtm_get_table(r, tb);
 	if (table) {
-		fprintf(fp, "lookup %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
+		fprintf(fp, "lookup %s ",
+			rtnl_rttable_n2a(table, b1, sizeof(b1)));
 
 		if (tb[FRA_SUPPRESS_PREFIXLEN]) {
 			int pl = rta_getattr_u32(tb[FRA_SUPPRESS_PREFIXLEN]);
 
-			if (pl != -1) {
+			if (pl != -1)
 				fprintf(fp, "suppress_prefixlength %d ", pl);
-			}
 		}
 		if (tb[FRA_SUPPRESS_IFGROUP]) {
 			int group = rta_getattr_u32(tb[FRA_SUPPRESS_IFGROUP]);
 
 			if (group != -1) {
 				SPRINT_BUF(b1);
-				fprintf(fp, "suppress_ifgroup %s ", rtnl_group_n2a(group, b1, sizeof(b1)));
+				fprintf(fp, "suppress_ifgroup %s ",
+					rtnl_group_n2a(group, b1, sizeof(b1)));
 			}
 		}
 	}
@@ -176,8 +185,8 @@
 	if (r->rtm_type == RTN_NAT) {
 		if (tb[RTA_GATEWAY]) {
 			fprintf(fp, "map-to %s ",
-			        format_host_rta(r->rtm_family,
-			                        tb[RTA_GATEWAY]));
+				format_host_rta(r->rtm_family,
+						tb[RTA_GATEWAY]));
 		} else
 			fprintf(fp, "masquerade");
 	} else if (r->rtm_type == FR_ACT_GOTO) {
@@ -191,7 +200,9 @@
 	} else if (r->rtm_type == FR_ACT_NOP)
 		fprintf(fp, "nop");
 	else if (r->rtm_type != RTN_UNICAST)
-		fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
+		fprintf(fp, "%s",
+			rtnl_rtntype_n2a(r->rtm_type,
+					 b1, sizeof(b1)));
 
 	fprintf(fp, "\n");
 	fflush(fp);
@@ -218,7 +229,8 @@
 	return 0;
 }
 
-static int save_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+static int save_rule(const struct sockaddr_nl *who,
+		     struct nlmsghdr *n, void *arg)
 {
 	int ret;
 
@@ -276,7 +288,8 @@
 
 	ret = fread(&magic, sizeof(magic), 1, stdin);
 	if (magic != rule_dump_magic) {
-		fprintf(stderr, "Magic mismatch (%d elems, %x magic)\n", ret, magic);
+		fprintf(stderr, "Magic mismatch (%d elems, %x magic)\n",
+			ret, magic);
 		return -1;
 	}
 
@@ -311,7 +324,9 @@
 
 static int iprule_modify(int cmd, int argc, char **argv)
 {
+	int l3mdev_rule = 0;
 	int table_ok = 0;
+	__u32 tid = 0;
 	struct {
 		struct nlmsghdr	n;
 		struct rtmsg		r;
@@ -340,14 +355,16 @@
 			NEXT_ARG();
 			get_prefix(&dst, *argv, req.r.rtm_family);
 			req.r.rtm_src_len = dst.bitlen;
-			addattr_l(&req.n, sizeof(req), FRA_SRC, &dst.data, dst.bytelen);
+			addattr_l(&req.n, sizeof(req), FRA_SRC,
+				  &dst.data, dst.bytelen);
 		} else if (strcmp(*argv, "to") == 0) {
 			inet_prefix dst;
 
 			NEXT_ARG();
 			get_prefix(&dst, *argv, req.r.rtm_family);
 			req.r.rtm_dst_len = dst.bitlen;
-			addattr_l(&req.n, sizeof(req), FRA_DST, &dst.data, dst.bytelen);
+			addattr_l(&req.n, sizeof(req), FRA_DST,
+				  &dst.data, dst.bytelen);
 		} else if (matches(*argv, "preference") == 0 ||
 			   matches(*argv, "order") == 0 ||
 			   matches(*argv, "priority") == 0) {
@@ -370,15 +387,19 @@
 			__u32 fwmark, fwmask;
 
 			NEXT_ARG();
-			if ((slash = strchr(*argv, '/')) != NULL)
+
+			slash = strchr(*argv, '/');
+			if (slash != NULL)
 				*slash = '\0';
 			if (get_u32(&fwmark, *argv, 0))
 				invarg("fwmark value is invalid\n", *argv);
 			addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark);
 			if (slash) {
 				if (get_u32(&fwmask, slash+1, 0))
-					invarg("fwmask value is invalid\n", slash+1);
-				addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask);
+					invarg("fwmask value is invalid\n",
+					       slash+1);
+				addattr32(&req.n, sizeof(req),
+					  FRA_FWMASK, fwmask);
 			}
 		} else if (matches(*argv, "realms") == 0) {
 			__u32 realm;
@@ -389,8 +410,6 @@
 			addattr32(&req.n, sizeof(req), FRA_FLOW, realm);
 		} else if (matches(*argv, "table") == 0 ||
 			   strcmp(*argv, "lookup") == 0) {
-			__u32 tid;
-
 			NEXT_ARG();
 			if (rtnl_rttable_a2n(&tid, *argv))
 				invarg("invalid table ID\n", *argv);
@@ -407,35 +426,46 @@
 
 			NEXT_ARG();
 			if (get_s32(&pl, *argv, 0) || pl < 0)
-				invarg("suppress_prefixlength value is invalid\n", *argv);
-			addattr32(&req.n, sizeof(req), FRA_SUPPRESS_PREFIXLEN, pl);
+				invarg("suppress_prefixlength value is invalid\n",
+				       *argv);
+			addattr32(&req.n, sizeof(req),
+				  FRA_SUPPRESS_PREFIXLEN, pl);
 		} else if (matches(*argv, "suppress_ifgroup") == 0 ||
 			   strcmp(*argv, "sup_group") == 0) {
 			NEXT_ARG();
 			int group;
 
 			if (rtnl_group_a2n(&group, *argv))
-				invarg("Invalid \"suppress_ifgroup\" value\n", *argv);
-			addattr32(&req.n, sizeof(req), FRA_SUPPRESS_IFGROUP, group);
+				invarg("Invalid \"suppress_ifgroup\" value\n",
+				       *argv);
+			addattr32(&req.n, sizeof(req),
+				  FRA_SUPPRESS_IFGROUP, group);
 		} else if (strcmp(*argv, "dev") == 0 ||
 			   strcmp(*argv, "iif") == 0) {
 			NEXT_ARG();
-			addattr_l(&req.n, sizeof(req), FRA_IFNAME, *argv, strlen(*argv)+1);
+			addattr_l(&req.n, sizeof(req), FRA_IFNAME,
+				  *argv, strlen(*argv)+1);
 		} else if (strcmp(*argv, "oif") == 0) {
 			NEXT_ARG();
-			addattr_l(&req.n, sizeof(req), FRA_OIFNAME, *argv, strlen(*argv)+1);
+			addattr_l(&req.n, sizeof(req), FRA_OIFNAME,
+				  *argv, strlen(*argv)+1);
+		} else if (strcmp(*argv, "l3mdev") == 0) {
+			addattr8(&req.n, sizeof(req), FRA_L3MDEV, 1);
+			table_ok = 1;
+			l3mdev_rule = 1;
 		} else if (strcmp(*argv, "nat") == 0 ||
 			   matches(*argv, "map-to") == 0) {
 			NEXT_ARG();
 			fprintf(stderr, "Warning: route NAT is deprecated\n");
-			addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv));
+			addattr32(&req.n, sizeof(req), RTA_GATEWAY,
+				  get_addr32(*argv));
 			req.r.rtm_type = RTN_NAT;
 		} else {
 			int type;
 
-			if (strcmp(*argv, "type") == 0) {
+			if (strcmp(*argv, "type") == 0)
 				NEXT_ARG();
-			}
+
 			if (matches(*argv, "help") == 0)
 				usage();
 			else if (matches(*argv, "goto") == 0) {
@@ -445,7 +475,8 @@
 				NEXT_ARG();
 				if (get_u32(&target, *argv, 0))
 					invarg("invalid target\n", *argv);
-				addattr32(&req.n, sizeof(req), FRA_GOTO, target);
+				addattr32(&req.n, sizeof(req),
+					  FRA_GOTO, target);
 			} else if (matches(*argv, "nop") == 0)
 				type = FR_ACT_NOP;
 			else if (rtnl_rtntype_a2n(&type, *argv))
@@ -457,6 +488,12 @@
 		argv++;
 	}
 
+	if (l3mdev_rule && tid != 0) {
+		fprintf(stderr,
+			"table can not be specified for l3mdev rules\n");
+		return -EINVAL;
+	}
+
 	if (req.r.rtm_family == AF_UNSPEC)
 		req.r.rtm_family = AF_INET;
 
@@ -470,7 +507,8 @@
 }
 
 
-static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
+		      void *arg)
 {
 	struct rtnl_handle rth2;
 	struct rtmsg *r = NLMSG_DATA(n);
@@ -545,7 +583,8 @@
 	} else if (matches(argv[0], "help") == 0)
 		usage();
 
-	fprintf(stderr, "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv);
+	fprintf(stderr,
+		"Command \"%s\" is unknown, try \"ip rule help\".\n", *argv);
 	exit(-1);
 }
 
@@ -563,7 +602,8 @@
 	case RTNL_FAMILY_IP6MR:
 		break;
 	default:
-		fprintf(stderr, "Multicast rules are only supported for IPv4/IPv6, was: %i\n",
+		fprintf(stderr,
+			"Multicast rules are only supported for IPv4/IPv6, was: %i\n",
 			preferred_family);
 		exit(-1);
 	}
diff --git a/man/man8/ip-fou.8 b/man/man8/ip-fou.8
index 0fa22ee..0c8f0a4 100644
--- a/man/man8/ip-fou.8
+++ b/man/man8/ip-fou.8
@@ -56,7 +56,7 @@
 .PP
 .SS Configure a FOU receive port for GRE bound to 7777
 .nf
-# ip fou add port 8888 ipproto 47
+# ip fou add port 7777 ipproto 47
 .PP
 .SS Configure a FOU receive port for IPIP bound to 8888
 .nf
diff --git a/man/man8/tc-skbedit.8 b/man/man8/tc-skbedit.8
index e690296..003f05c 100644
--- a/man/man8/tc-skbedit.8
+++ b/man/man8/tc-skbedit.8
@@ -11,6 +11,8 @@
 .IR PRIORITY " ] ["
 .B mark
 .IR MARK " ]"
+.B ptype
+.IR PTYPE " ]"
 .SH DESCRIPTION
 The
 .B skbedit
@@ -52,6 +54,13 @@
 is an unsigned 32bit value in automatically detected format (i.e., prefix with
 .RB ' 0x '
 for hexadecimal interpretation, etc.).
+.TP
+.BI ptype " PTYPE"
+Override the packet's type. Useful for setting packet type to host when
+needing to allow ingressing packets with the wrong MAC address but
+correct IP address.
+.I PTYPE
+is one of: host, otherhost, broadcast, multicast
 .SH SEE ALSO
 .BR tc (8),
 .BR tc-pedit (8)
diff --git a/tc/m_skbedit.c b/tc/m_skbedit.c
index eca6a8a..368debc 100644
--- a/tc/m_skbedit.c
+++ b/tc/m_skbedit.c
@@ -26,14 +26,17 @@
 #include "utils.h"
 #include "tc_util.h"
 #include <linux/tc_act/tc_skbedit.h>
+#include <linux/if_packet.h>
 
-static void
-explain(void)
+static void explain(void)
 {
-	fprintf(stderr, "Usage: ... skbedit <[QM] [PM] [MM]>\n"
+	fprintf(stderr, "Usage: ... skbedit <[QM] [PM] [MM] [PT]>\n"
 		"QM = queue_mapping QUEUE_MAPPING\n"
 		"PM = priority PRIORITY\n"
 		"MM = mark MARK\n"
+		"PT = ptype PACKETYPE\n"
+		"PACKETYPE = is one of:\n"
+		"  host, otherhost, broadcast, multicast\n"
 		"QUEUE_MAPPING = device transmit queue to use\n"
 		"PRIORITY = classID to assign to priority field\n"
 		"MARK = firewall mark to set\n");
@@ -55,7 +58,7 @@
 	int ok = 0;
 	struct rtattr *tail;
 	unsigned int tmp;
-	__u16 queue_mapping;
+	__u16 queue_mapping, ptype;
 	__u32 flags = 0, priority, mark;
 	struct tc_skbedit sel = { 0 };
 
@@ -90,6 +93,24 @@
 				return -1;
 			}
 			ok++;
+		} else if (matches(*argv, "ptype") == 0) {
+
+			NEXT_ARG();
+			if (matches(*argv, "host") == 0) {
+				ptype = PACKET_HOST;
+			} else if (matches(*argv, "broadcast") == 0) {
+				ptype = PACKET_BROADCAST;
+			} else if (matches(*argv, "multicast") == 0) {
+				ptype = PACKET_MULTICAST;
+			} else if (matches(*argv, "otherhost") == 0) {
+				ptype = PACKET_OTHERHOST;
+			} else {
+				fprintf(stderr, "Illegal ptype (%s)\n",
+					*argv);
+				return -1;
+			}
+			flags |= SKBEDIT_F_PTYPE;
+			ok++;
 		} else if (matches(*argv, "help") == 0) {
 			usage();
 		} else {
@@ -134,6 +155,9 @@
 	if (flags & SKBEDIT_F_MARK)
 		addattr_l(n, MAX_MSG, TCA_SKBEDIT_MARK,
 			  &mark, sizeof(mark));
+	if (flags & SKBEDIT_F_PTYPE)
+		addattr_l(n, MAX_MSG, TCA_SKBEDIT_PTYPE,
+			  &ptype, sizeof(ptype));
 	tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
 
 	*argc_p = argc;
@@ -148,7 +172,7 @@
 	SPRINT_BUF(b1);
 	__u32 *priority;
 	__u32 *mark;
-	__u16 *queue_mapping;
+	__u16 *queue_mapping, *ptype;
 	struct tc_skbedit *p = NULL;
 
 	if (arg == NULL)
@@ -176,8 +200,22 @@
 		mark = RTA_DATA(tb[TCA_SKBEDIT_MARK]);
 		fprintf(f, " mark %d", *mark);
 	}
+	if (tb[TCA_SKBEDIT_PTYPE] != NULL) {
+		ptype = RTA_DATA(tb[TCA_SKBEDIT_PTYPE]);
+		if (*ptype == PACKET_HOST)
+			fprintf(f, " ptype host");
+		else if (*ptype == PACKET_BROADCAST)
+			fprintf(f, " ptype broadcast");
+		else if (*ptype == PACKET_MULTICAST)
+			fprintf(f, " ptype multicast");
+		else if (*ptype == PACKET_OTHERHOST)
+			fprintf(f, " ptype otherhost");
+		else
+			fprintf(f, " ptype %d", *ptype);
+	}
 
-	fprintf(f, "\n\t index %d ref %d bind %d", p->index, p->refcnt, p->bindcnt);
+	fprintf(f, "\n\t index %d ref %d bind %d",
+		p->index, p->refcnt, p->bindcnt);
 
 	if (show_stats) {
 		if (tb[TCA_SKBEDIT_TM]) {