ip6_gre: add erspan v2 support
Similar to support for ipv4 erspan, this patch adds erspan v2 to ip6erspan tunnel. Signed-off-by: William Tu <u9012063@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f551c91de2
commit
94d7d8f292
@ -37,6 +37,9 @@ struct __ip6_tnl_parm {
|
|||||||
|
|
||||||
__u32 fwmark;
|
__u32 fwmark;
|
||||||
__u32 index; /* ERSPAN type II index */
|
__u32 index; /* ERSPAN type II index */
|
||||||
|
__u8 erspan_ver; /* ERSPAN version */
|
||||||
|
__u8 dir; /* direction */
|
||||||
|
__u16 hwid; /* hwid */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* IPv6 tunnel */
|
/* IPv6 tunnel */
|
||||||
|
@ -553,13 +553,28 @@ static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len,
|
|||||||
return PACKET_REJECT;
|
return PACKET_REJECT;
|
||||||
|
|
||||||
memcpy(md, pkt_md, sizeof(*md));
|
memcpy(md, pkt_md, sizeof(*md));
|
||||||
|
md->version = ver;
|
||||||
info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
|
info->key.tun_flags |= TUNNEL_ERSPAN_OPT;
|
||||||
info->options_len = sizeof(*md);
|
info->options_len = sizeof(*md);
|
||||||
|
|
||||||
ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
|
ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
tunnel->parms.index = ntohl(pkt_md->u.index);
|
tunnel->parms.erspan_ver = ver;
|
||||||
|
|
||||||
|
if (ver == 1) {
|
||||||
|
tunnel->parms.index = ntohl(pkt_md->u.index);
|
||||||
|
} else {
|
||||||
|
u16 md2_flags;
|
||||||
|
u16 dir, hwid;
|
||||||
|
|
||||||
|
md2_flags = ntohs(pkt_md->u.md2.flags);
|
||||||
|
dir = (md2_flags & DIR_MASK) >> DIR_OFFSET;
|
||||||
|
hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET;
|
||||||
|
tunnel->parms.dir = dir;
|
||||||
|
tunnel->parms.hwid = hwid;
|
||||||
|
}
|
||||||
|
|
||||||
ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
|
ip6_tnl_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,7 +597,8 @@ static int gre_rcv(struct sk_buff *skb)
|
|||||||
if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false))
|
if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false))
|
||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
if (unlikely(tpi.proto == htons(ETH_P_ERSPAN))) {
|
if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) ||
|
||||||
|
tpi.proto == htons(ETH_P_ERSPAN2))) {
|
||||||
if (ip6erspan_rcv(skb, hdr_len, &tpi) == PACKET_RCVD)
|
if (ip6erspan_rcv(skb, hdr_len, &tpi) == PACKET_RCVD)
|
||||||
return 0;
|
return 0;
|
||||||
goto drop;
|
goto drop;
|
||||||
@ -927,9 +943,24 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
|
|||||||
if (!md)
|
if (!md)
|
||||||
goto tx_err;
|
goto tx_err;
|
||||||
|
|
||||||
erspan_build_header(skb, tunnel_id_to_key32(key->tun_id),
|
if (md->version == 1) {
|
||||||
ntohl(md->u.index), truncate, false);
|
erspan_build_header(skb,
|
||||||
|
tunnel_id_to_key32(key->tun_id),
|
||||||
|
ntohl(md->u.index), truncate,
|
||||||
|
false);
|
||||||
|
} else if (md->version == 2) {
|
||||||
|
u16 md2_flags;
|
||||||
|
u16 dir, hwid;
|
||||||
|
|
||||||
|
md2_flags = ntohs(md->u.md2.flags);
|
||||||
|
dir = (md2_flags & DIR_MASK) >> DIR_OFFSET;
|
||||||
|
hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET;
|
||||||
|
|
||||||
|
erspan_build_header_v2(skb,
|
||||||
|
tunnel_id_to_key32(key->tun_id),
|
||||||
|
dir, hwid, truncate,
|
||||||
|
false);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (skb->protocol) {
|
switch (skb->protocol) {
|
||||||
case htons(ETH_P_IP):
|
case htons(ETH_P_IP):
|
||||||
@ -949,8 +980,15 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
erspan_build_header(skb, t->parms.o_key, t->parms.index,
|
if (t->parms.erspan_ver == 1)
|
||||||
truncate, false);
|
erspan_build_header(skb, t->parms.o_key,
|
||||||
|
t->parms.index,
|
||||||
|
truncate, false);
|
||||||
|
else
|
||||||
|
erspan_build_header_v2(skb, t->parms.o_key,
|
||||||
|
t->parms.dir,
|
||||||
|
t->parms.hwid,
|
||||||
|
truncate, false);
|
||||||
fl6.daddr = t->parms.raddr;
|
fl6.daddr = t->parms.raddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1514,7 +1552,7 @@ static int ip6erspan_tap_validate(struct nlattr *tb[], struct nlattr *data[],
|
|||||||
struct netlink_ext_ack *extack)
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
__be16 flags = 0;
|
__be16 flags = 0;
|
||||||
int ret;
|
int ret, ver = 0;
|
||||||
|
|
||||||
if (!data)
|
if (!data)
|
||||||
return 0;
|
return 0;
|
||||||
@ -1543,12 +1581,35 @@ static int ip6erspan_tap_validate(struct nlattr *tb[], struct nlattr *data[],
|
|||||||
(ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK))
|
(ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (data[IFLA_GRE_ERSPAN_INDEX]) {
|
if (data[IFLA_GRE_ERSPAN_VER]) {
|
||||||
u32 index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
|
ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
|
||||||
|
if (ver != 1 && ver != 2)
|
||||||
if (index & ~INDEX_MASK)
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ver == 1) {
|
||||||
|
if (data[IFLA_GRE_ERSPAN_INDEX]) {
|
||||||
|
u32 index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
|
||||||
|
|
||||||
|
if (index & ~INDEX_MASK)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
} else if (ver == 2) {
|
||||||
|
if (data[IFLA_GRE_ERSPAN_DIR]) {
|
||||||
|
u16 dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
|
||||||
|
|
||||||
|
if (dir & ~(DIR_MASK >> DIR_OFFSET))
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data[IFLA_GRE_ERSPAN_HWID]) {
|
||||||
|
u16 hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
|
||||||
|
|
||||||
|
if (hwid & ~(HWID_MASK >> HWID_OFFSET))
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1598,11 +1659,21 @@ static void ip6gre_netlink_parms(struct nlattr *data[],
|
|||||||
if (data[IFLA_GRE_FWMARK])
|
if (data[IFLA_GRE_FWMARK])
|
||||||
parms->fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
|
parms->fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
|
||||||
|
|
||||||
if (data[IFLA_GRE_ERSPAN_INDEX])
|
|
||||||
parms->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
|
|
||||||
|
|
||||||
if (data[IFLA_GRE_COLLECT_METADATA])
|
if (data[IFLA_GRE_COLLECT_METADATA])
|
||||||
parms->collect_md = true;
|
parms->collect_md = true;
|
||||||
|
|
||||||
|
if (data[IFLA_GRE_ERSPAN_VER])
|
||||||
|
parms->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
|
||||||
|
|
||||||
|
if (parms->erspan_ver == 1) {
|
||||||
|
if (data[IFLA_GRE_ERSPAN_INDEX])
|
||||||
|
parms->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]);
|
||||||
|
} else if (parms->erspan_ver == 2) {
|
||||||
|
if (data[IFLA_GRE_ERSPAN_DIR])
|
||||||
|
parms->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]);
|
||||||
|
if (data[IFLA_GRE_ERSPAN_HWID])
|
||||||
|
parms->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ip6gre_tap_init(struct net_device *dev)
|
static int ip6gre_tap_init(struct net_device *dev)
|
||||||
@ -1664,7 +1735,7 @@ static int ip6erspan_tap_init(struct net_device *dev)
|
|||||||
|
|
||||||
tunnel->tun_hlen = 8;
|
tunnel->tun_hlen = 8;
|
||||||
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
|
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
|
||||||
sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE;
|
erspan_hdr_len(tunnel->parms.erspan_ver);
|
||||||
t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
|
t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
|
||||||
|
|
||||||
dev->hard_header_len = LL_MAX_HEADER + t_hlen;
|
dev->hard_header_len = LL_MAX_HEADER + t_hlen;
|
||||||
@ -1932,6 +2003,19 @@ static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
|||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, p->erspan_ver))
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
if (p->erspan_ver == 1) {
|
||||||
|
if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index))
|
||||||
|
goto nla_put_failure;
|
||||||
|
} else if (p->erspan_ver == 2) {
|
||||||
|
if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, p->dir))
|
||||||
|
goto nla_put_failure;
|
||||||
|
if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, p->hwid))
|
||||||
|
goto nla_put_failure;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
@ -1957,6 +2041,9 @@ static const struct nla_policy ip6gre_policy[IFLA_GRE_MAX + 1] = {
|
|||||||
[IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG },
|
[IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG },
|
||||||
[IFLA_GRE_FWMARK] = { .type = NLA_U32 },
|
[IFLA_GRE_FWMARK] = { .type = NLA_U32 },
|
||||||
[IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 },
|
[IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 },
|
||||||
|
[IFLA_GRE_ERSPAN_VER] = { .type = NLA_U8 },
|
||||||
|
[IFLA_GRE_ERSPAN_DIR] = { .type = NLA_U8 },
|
||||||
|
[IFLA_GRE_ERSPAN_HWID] = { .type = NLA_U16 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ip6erspan_tap_setup(struct net_device *dev)
|
static void ip6erspan_tap_setup(struct net_device *dev)
|
||||||
@ -2078,4 +2165,5 @@ MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
|
|||||||
MODULE_DESCRIPTION("GRE over IPv6 tunneling device");
|
MODULE_DESCRIPTION("GRE over IPv6 tunneling device");
|
||||||
MODULE_ALIAS_RTNL_LINK("ip6gre");
|
MODULE_ALIAS_RTNL_LINK("ip6gre");
|
||||||
MODULE_ALIAS_RTNL_LINK("ip6gretap");
|
MODULE_ALIAS_RTNL_LINK("ip6gretap");
|
||||||
|
MODULE_ALIAS_RTNL_LINK("ip6erspan");
|
||||||
MODULE_ALIAS_NETDEV("ip6gre0");
|
MODULE_ALIAS_NETDEV("ip6gre0");
|
||||||
|
Loading…
Reference in New Issue
Block a user