Commit efbae716 authored by David S. Miller's avatar David S. Miller

Merge branch 'ip6_gre-add-erspan-native-tunnel-for-ipv6'

William Tu says:

====================
ip6_gre: add erspan native tunnel for ipv6

The patch series add support for ERSPAN tunnel over ipv6.  The first patch
refectors the existing ipv4 gre implementation and the second refactors the
ipv6 gre's xmit code.  Finally the last patch introduces erspan protocol.

change in v5:
  - add cover-letter description

change in v4:
  - rebase on top of net-next
  - use log_ecn_error in ip6_tnl_rcv

change in v3:
  - add inline for functions in header
  - rebase on top of net-next

change in v2:
  - remove inline
  - fix some indent
  - fix errors reports by clang and scan-build
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 50e0f5c0 5a963eb6
...@@ -58,4 +58,55 @@ struct erspanhdr { ...@@ -58,4 +58,55 @@ struct erspanhdr {
struct erspan_metadata md; struct erspan_metadata md;
}; };
static inline u8 tos_to_cos(u8 tos)
{
u8 dscp, cos;
dscp = tos >> 2;
cos = dscp >> 3;
return cos;
}
static inline void erspan_build_header(struct sk_buff *skb,
__be32 id, u32 index,
bool truncate, bool is_ipv4)
{
struct ethhdr *eth = eth_hdr(skb);
enum erspan_encap_type enc_type;
struct erspanhdr *ershdr;
struct qtag_prefix {
__be16 eth_type;
__be16 tci;
} *qp;
u16 vlan_tci = 0;
u8 tos;
tos = is_ipv4 ? ip_hdr(skb)->tos :
(ipv6_hdr(skb)->priority << 4) +
(ipv6_hdr(skb)->flow_lbl[0] >> 4);
enc_type = ERSPAN_ENCAP_NOVLAN;
/* If mirrored packet has vlan tag, extract tci and
* perserve vlan header in the mirrored frame.
*/
if (eth->h_proto == htons(ETH_P_8021Q)) {
qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN);
vlan_tci = ntohs(qp->tci);
enc_type = ERSPAN_ENCAP_INFRAME;
}
skb_push(skb, sizeof(*ershdr));
ershdr = (struct erspanhdr *)skb->data;
memset(ershdr, 0, sizeof(*ershdr));
ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) |
(ERSPAN_VERSION << VER_OFFSET));
ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) |
((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) |
(enc_type << EN_OFFSET & EN_MASK) |
((truncate << T_OFFSET) & T_MASK));
ershdr->md.index = htonl(index & INDEX_MASK);
}
#endif #endif
...@@ -36,6 +36,7 @@ struct __ip6_tnl_parm { ...@@ -36,6 +36,7 @@ struct __ip6_tnl_parm {
__be32 o_key; __be32 o_key;
__u32 fwmark; __u32 fwmark;
__u32 index; /* ERSPAN type II index */
}; };
/* IPv6 tunnel */ /* IPv6 tunnel */
......
...@@ -114,7 +114,8 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); ...@@ -114,7 +114,8 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
static struct rtnl_link_ops ipgre_link_ops __read_mostly; static struct rtnl_link_ops ipgre_link_ops __read_mostly;
static int ipgre_tunnel_init(struct net_device *dev); static int ipgre_tunnel_init(struct net_device *dev);
static void erspan_build_header(struct sk_buff *skb, static void erspan_build_header(struct sk_buff *skb,
__be32 id, u32 index, bool truncate); __be32 id, u32 index,
bool truncate, bool is_ipv4);
static unsigned int ipgre_net_id __read_mostly; static unsigned int ipgre_net_id __read_mostly;
static unsigned int gre_tap_net_id __read_mostly; static unsigned int gre_tap_net_id __read_mostly;
...@@ -589,7 +590,7 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, ...@@ -589,7 +590,7 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
goto err_free_rt; goto err_free_rt;
erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), erspan_build_header(skb, tunnel_id_to_key32(key->tun_id),
ntohl(md->index), truncate); ntohl(md->index), truncate, true);
gre_build_header(skb, 8, TUNNEL_SEQ, gre_build_header(skb, 8, TUNNEL_SEQ,
htons(ETH_P_ERSPAN), 0, htonl(tunnel->o_seqno++)); htons(ETH_P_ERSPAN), 0, htonl(tunnel->o_seqno++));
...@@ -668,52 +669,6 @@ static netdev_tx_t ipgre_xmit(struct sk_buff *skb, ...@@ -668,52 +669,6 @@ static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
static inline u8 tos_to_cos(u8 tos)
{
u8 dscp, cos;
dscp = tos >> 2;
cos = dscp >> 3;
return cos;
}
static void erspan_build_header(struct sk_buff *skb,
__be32 id, u32 index, bool truncate)
{
struct iphdr *iphdr = ip_hdr(skb);
struct ethhdr *eth = eth_hdr(skb);
enum erspan_encap_type enc_type;
struct erspanhdr *ershdr;
struct qtag_prefix {
__be16 eth_type;
__be16 tci;
} *qp;
u16 vlan_tci = 0;
enc_type = ERSPAN_ENCAP_NOVLAN;
/* If mirrored packet has vlan tag, extract tci and
* perserve vlan header in the mirrored frame.
*/
if (eth->h_proto == htons(ETH_P_8021Q)) {
qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN);
vlan_tci = ntohs(qp->tci);
enc_type = ERSPAN_ENCAP_INFRAME;
}
skb_push(skb, sizeof(*ershdr));
ershdr = (struct erspanhdr *)skb->data;
memset(ershdr, 0, sizeof(*ershdr));
ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) |
(ERSPAN_VERSION << VER_OFFSET));
ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) |
((tos_to_cos(iphdr->tos) << COS_OFFSET) & COS_MASK) |
(enc_type << EN_OFFSET & EN_MASK) |
((truncate << T_OFFSET) & T_MASK));
ershdr->md.index = htonl(index & INDEX_MASK);
}
static netdev_tx_t erspan_xmit(struct sk_buff *skb, static netdev_tx_t erspan_xmit(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
...@@ -737,7 +692,8 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb, ...@@ -737,7 +692,8 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb,
} }
/* Push ERSPAN header */ /* Push ERSPAN header */
erspan_build_header(skb, tunnel->parms.o_key, tunnel->index, truncate); erspan_build_header(skb, tunnel->parms.o_key, tunnel->index,
truncate, true);
tunnel->parms.o_flags &= ~TUNNEL_KEY; tunnel->parms.o_flags &= ~TUNNEL_KEY;
__gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN)); __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN));
return NETDEV_TX_OK; return NETDEV_TX_OK;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment