Merge branch 'master' into net-next
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 5e4d373..3aa778d 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 {
@@ -313,6 +314,49 @@
*/
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,
+
__BPF_FUNC_MAX_ID,
};
@@ -347,7 +391,7 @@
#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
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..61e19ff 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -247,8 +247,34 @@
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_queries[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_queries[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_link.h b/include/linux/if_link.h
index 15bbeb8..af0b2d8 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -271,6 +271,7 @@
IFLA_BR_VLAN_DEFAULT_PVID,
IFLA_BR_PAD,
IFLA_BR_VLAN_STATS_ENABLED,
+ IFLA_BR_MCAST_STATS_ENABLED,
__IFLA_BR_MAX,
};
@@ -820,6 +821,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,
};
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/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..44cda25 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;
};
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/ip/iprule.c b/ip/iprule.c
index 7cb19e4..a412804 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;
@@ -344,14 +359,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) {
@@ -374,15 +391,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;
@@ -393,8 +414,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);
@@ -411,35 +430,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) {
@@ -449,7 +479,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))
@@ -461,6 +492,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;
@@ -474,7 +511,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);
@@ -549,7 +587,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);
}
@@ -567,7 +606,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 9ba288c..4f6c2b4 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 {
@@ -152,6 +173,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;
@@ -166,7 +190,7 @@
SPRINT_BUF(b1);
__u32 *priority;
__u32 *mark;
- __u16 *queue_mapping;
+ __u16 *queue_mapping, *ptype;
struct tc_skbedit *p = NULL;
if (arg == NULL)
@@ -194,8 +218,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]) {