Skip to content

Commit

Permalink
ip6_gre: Refactor ip6gre xmit codes
Browse files Browse the repository at this point in the history
This patch refactors the ip6gre_xmit_{ipv4, ipv6}.
It is a prep work to add the ip6erspan tunnel.

Signed-off-by: William Tu <u9012063@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
William Tu authored and David S. Miller committed Dec 1, 2017
1 parent a3222dc commit 898b297
Showing 1 changed file with 75 additions and 48 deletions.
123 changes: 75 additions & 48 deletions net/ipv6/ip6_gre.c
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,78 @@ static int gre_handle_offloads(struct sk_buff *skb, bool csum)
csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE);
}

static void prepare_ip6gre_xmit_ipv4(struct sk_buff *skb,
struct net_device *dev,
struct flowi6 *fl6, __u8 *dsfield,
int *encap_limit)
{
const struct iphdr *iph = ip_hdr(skb);
struct ip6_tnl *t = netdev_priv(dev);

if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
*encap_limit = t->parms.encap_limit;

memcpy(fl6, &t->fl.u.ip6, sizeof(*fl6));

if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
*dsfield = ipv4_get_dsfield(iph);
else
*dsfield = ip6_tclass(t->parms.flowinfo);

if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
fl6->flowi6_mark = skb->mark;
else
fl6->flowi6_mark = t->parms.fwmark;

fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL);
}

static int prepare_ip6gre_xmit_ipv6(struct sk_buff *skb,
struct net_device *dev,
struct flowi6 *fl6, __u8 *dsfield,
int *encap_limit)
{
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
struct ip6_tnl *t = netdev_priv(dev);
__u16 offset;

offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
/* ip6_tnl_parse_tlv_enc_lim() might have reallocated skb->head */

if (offset > 0) {
struct ipv6_tlv_tnl_enc_lim *tel;

tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
if (tel->encap_limit == 0) {
icmpv6_send(skb, ICMPV6_PARAMPROB,
ICMPV6_HDR_FIELD, offset + 2);
return -1;
}
*encap_limit = tel->encap_limit - 1;
} else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) {
*encap_limit = t->parms.encap_limit;
}

memcpy(fl6, &t->fl.u.ip6, sizeof(*fl6));

if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
*dsfield = ipv6_get_dsfield(ipv6h);
else
*dsfield = ip6_tclass(t->parms.flowinfo);

if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
fl6->flowlabel |= ip6_flowlabel(ipv6h);

if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
fl6->flowi6_mark = skb->mark;
else
fl6->flowi6_mark = t->parms.fwmark;

fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL);

return 0;
}

static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
struct net_device *dev, __u8 dsfield,
struct flowi6 *fl6, int encap_limit,
Expand Down Expand Up @@ -527,7 +599,6 @@ static netdev_tx_t __gre6_xmit(struct sk_buff *skb,
static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
const struct iphdr *iph = ip_hdr(skb);
int encap_limit = -1;
struct flowi6 fl6;
__u8 dsfield;
Expand All @@ -536,21 +607,7 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)

memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));

if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
encap_limit = t->parms.encap_limit;

memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));

if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
dsfield = ipv4_get_dsfield(iph);
else
dsfield = ip6_tclass(t->parms.flowinfo);
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
fl6.flowi6_mark = skb->mark;
else
fl6.flowi6_mark = t->parms.fwmark;

fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
prepare_ip6gre_xmit_ipv4(skb, dev, &fl6, &dsfield, &encap_limit);

err = gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM));
if (err)
Expand All @@ -574,7 +631,6 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
struct ip6_tnl *t = netdev_priv(dev);
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
int encap_limit = -1;
__u16 offset;
struct flowi6 fl6;
__u8 dsfield;
__u32 mtu;
Expand All @@ -583,37 +639,8 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
if (ipv6_addr_equal(&t->parms.raddr, &ipv6h->saddr))
return -1;

offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
/* ip6_tnl_parse_tlv_enc_lim() might have reallocated skb->head */
ipv6h = ipv6_hdr(skb);

if (offset > 0) {
struct ipv6_tlv_tnl_enc_lim *tel;
tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
if (tel->encap_limit == 0) {
icmpv6_send(skb, ICMPV6_PARAMPROB,
ICMPV6_HDR_FIELD, offset + 2);
return -1;
}
encap_limit = tel->encap_limit - 1;
} else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
encap_limit = t->parms.encap_limit;

memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));

if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
dsfield = ipv6_get_dsfield(ipv6h);
else
dsfield = ip6_tclass(t->parms.flowinfo);

if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
fl6.flowlabel |= ip6_flowlabel(ipv6h);
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
fl6.flowi6_mark = skb->mark;
else
fl6.flowi6_mark = t->parms.fwmark;

fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
if (prepare_ip6gre_xmit_ipv6(skb, dev, &fl6, &dsfield, &encap_limit))
return -1;

if (gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM)))
return -1;
Expand Down

0 comments on commit 898b297

Please sign in to comment.