Skip to content

Commit

Permalink
net: frags: Add VRF device index to cache and lookup
Browse files Browse the repository at this point in the history
Fragmentation cache uses information from the IP header to reassemble
packets. That information can be duplicated across VRFs -- same source
and destination addresses, protocol and id. Handle fragmentation with
VRFs by adding the VRF device index to entries in the cache and the
lookup arg.

Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David Ahern authored and davem330 committed Aug 14, 2015
1 parent f7ba868 commit 9972f13
Showing 1 changed file with 13 additions and 5 deletions.
18 changes: 13 additions & 5 deletions net/ipv4/ip_fragment.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include <linux/inet.h>
#include <linux/netfilter_ipv4.h>
#include <net/inet_ecn.h>
#include <net/vrf.h>

/* NOTE. Logic of IP defragmentation is parallel to corresponding IPv6
* code now. If you change something here, _PLEASE_ update ipv6/reassembly.c
Expand Down Expand Up @@ -77,6 +78,7 @@ struct ipq {
u8 ecn; /* RFC3168 support */
u16 max_df_size; /* largest frag with DF set seen */
int iif;
int vif; /* VRF device index */
unsigned int rid;
struct inet_peer *peer;
};
Expand All @@ -99,6 +101,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
struct ip4_create_arg {
struct iphdr *iph;
u32 user;
int vif;
};

static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot)
Expand Down Expand Up @@ -127,7 +130,8 @@ static bool ip4_frag_match(const struct inet_frag_queue *q, const void *a)
qp->saddr == arg->iph->saddr &&
qp->daddr == arg->iph->daddr &&
qp->protocol == arg->iph->protocol &&
qp->user == arg->user;
qp->user == arg->user &&
qp->vif == arg->vif;
}

static void ip4_frag_init(struct inet_frag_queue *q, const void *a)
Expand All @@ -144,6 +148,7 @@ static void ip4_frag_init(struct inet_frag_queue *q, const void *a)
qp->ecn = ip4_frag_ecn(arg->iph->tos);
qp->saddr = arg->iph->saddr;
qp->daddr = arg->iph->daddr;
qp->vif = arg->vif;
qp->user = arg->user;
qp->peer = sysctl_ipfrag_max_dist ?
inet_getpeer_v4(net->ipv4.peers, arg->iph->saddr, 1) : NULL;
Expand Down Expand Up @@ -244,14 +249,16 @@ static void ip_expire(unsigned long arg)
/* Find the correct entry in the "incomplete datagrams" queue for
* this IP datagram, and create new one, if nothing is found.
*/
static struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user)
static struct ipq *ip_find(struct net *net, struct iphdr *iph,
u32 user, int vif)
{
struct inet_frag_queue *q;
struct ip4_create_arg arg;
unsigned int hash;

arg.iph = iph;
arg.user = user;
arg.vif = vif;

hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);

Expand Down Expand Up @@ -648,14 +655,15 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
/* Process an incoming IP datagram fragment. */
int ip_defrag(struct sk_buff *skb, u32 user)
{
struct net_device *dev = skb->dev ? : skb_dst(skb)->dev;
int vif = vrf_master_ifindex_rcu(dev);
struct net *net = dev_net(dev);
struct ipq *qp;
struct net *net;

net = skb->dev ? dev_net(skb->dev) : dev_net(skb_dst(skb)->dev);
IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS);

/* Lookup (or create) queue header */
qp = ip_find(net, ip_hdr(skb), user);
qp = ip_find(net, ip_hdr(skb), user, vif);
if (qp) {
int ret;

Expand Down

0 comments on commit 9972f13

Please sign in to comment.