aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller2015-08-24 10:34:40 -0700
committerDavid S. Miller2015-08-24 10:34:40 -0700
commitb17f29646dfabe147a7a4d54cc628e8046be3761 (patch)
tree78be9bc4e05a76f531a7798b7f45529b205fa202
parent54cf7be992fe86571a3f07b96446cd5334b014ab (diff)
parent92b78aff855a4815afe5311e3473ec829d3f2a9e (diff)
Merge branch 'ila-precompute'
Tom Herbert says: ==================== ila: Precompute checksums This patch set: - Adds argument ot LWT build_state that holds a pointer to the fib configuration being applied to the new route - Adds support in ILA to precompute checksum difference for performance optimization v2: - Move return argument in build_state to end of arguments v3: - Update the signature for ip6_tun_build_state() ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/lwtunnel.h3
-rw-r--r--net/core/lwtunnel.c5
-rw-r--r--net/ipv4/fib_semantics.c17
-rw-r--r--net/ipv4/ip_tunnel_core.c2
-rw-r--r--net/ipv6/ila.c19
-rw-r--r--net/ipv6/route.c3
-rw-r--r--net/mpls/mpls_iptunnel.c1
7 files changed, 40 insertions, 10 deletions
diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h
index 843489884448..fce0e35e74d0 100644
--- a/include/net/lwtunnel.h
+++ b/include/net/lwtunnel.h
@@ -26,6 +26,7 @@ struct lwtunnel_state {
struct lwtunnel_encap_ops {
int (*build_state)(struct net_device *dev, struct nlattr *encap,
+ unsigned int family, const void *cfg,
struct lwtunnel_state **ts);
int (*output)(struct sock *sk, struct sk_buff *skb);
int (*input)(struct sk_buff *skb);
@@ -80,6 +81,7 @@ int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
unsigned int num);
int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
struct nlattr *encap,
+ unsigned int family, const void *cfg,
struct lwtunnel_state **lws);
int lwtunnel_fill_encap(struct sk_buff *skb,
struct lwtunnel_state *lwtstate);
@@ -130,6 +132,7 @@ static inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
struct nlattr *encap,
+ unsigned int family, const void *cfg,
struct lwtunnel_state **lws)
{
return -EOPNOTSUPP;
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
index e924c2e08554..dfb1a9ca0835 100644
--- a/net/core/lwtunnel.c
+++ b/net/core/lwtunnel.c
@@ -72,7 +72,8 @@ int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *ops,
EXPORT_SYMBOL(lwtunnel_encap_del_ops);
int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
- struct nlattr *encap, struct lwtunnel_state **lws)
+ struct nlattr *encap, unsigned int family,
+ const void *cfg, struct lwtunnel_state **lws)
{
const struct lwtunnel_encap_ops *ops;
int ret = -EINVAL;
@@ -85,7 +86,7 @@ int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
rcu_read_lock();
ops = rcu_dereference(lwtun_encaps[encap_type]);
if (likely(ops && ops->build_state))
- ret = ops->build_state(dev, encap, lws);
+ ret = ops->build_state(dev, encap, family, cfg, lws);
rcu_read_unlock();
return ret;
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 01f1c7dcd329..1b2d01170a4d 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -511,7 +511,8 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
dev = __dev_get_by_index(net, cfg->fc_oif);
ret = lwtunnel_build_state(dev, nla_get_u16(
nla_entype),
- nla, &lwtstate);
+ nla, AF_INET, cfg,
+ &lwtstate);
if (ret)
goto errout;
nexthop_nh->nh_lwtstate =
@@ -535,7 +536,8 @@ errout:
static int fib_encap_match(struct net *net, u16 encap_type,
struct nlattr *encap,
- int oif, const struct fib_nh *nh)
+ int oif, const struct fib_nh *nh,
+ const struct fib_config *cfg)
{
struct lwtunnel_state *lwtstate;
struct net_device *dev = NULL;
@@ -546,8 +548,8 @@ static int fib_encap_match(struct net *net, u16 encap_type,
if (oif)
dev = __dev_get_by_index(net, oif);
- ret = lwtunnel_build_state(dev, encap_type,
- encap, &lwtstate);
+ ret = lwtunnel_build_state(dev, encap_type, encap,
+ AF_INET, cfg, &lwtstate);
if (!ret) {
result = lwtunnel_cmp_encap(lwtstate, nh->nh_lwtstate);
lwtstate_free(lwtstate);
@@ -571,7 +573,7 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
if (cfg->fc_encap) {
if (fib_encap_match(net, cfg->fc_encap_type,
cfg->fc_encap, cfg->fc_oif,
- fi->fib_nh))
+ fi->fib_nh, cfg))
return 1;
}
if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) &&
@@ -663,7 +665,7 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
struct fib_nh *nh)
{
- int err;
+ int err = 0;
struct net *net;
struct net_device *dev;
@@ -1005,7 +1007,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
if (cfg->fc_oif)
dev = __dev_get_by_index(net, cfg->fc_oif);
err = lwtunnel_build_state(dev, cfg->fc_encap_type,
- cfg->fc_encap, &lwtstate);
+ cfg->fc_encap, AF_INET, cfg,
+ &lwtstate);
if (err)
goto failure;
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c
index 289b6c26ce37..934f2ac8ad61 100644
--- a/net/ipv4/ip_tunnel_core.c
+++ b/net/ipv4/ip_tunnel_core.c
@@ -204,6 +204,7 @@ static const struct nla_policy ip_tun_policy[LWTUNNEL_IP_MAX + 1] = {
};
static int ip_tun_build_state(struct net_device *dev, struct nlattr *attr,
+ unsigned int family, const void *cfg,
struct lwtunnel_state **ts)
{
struct ip_tunnel_info *tun_info;
@@ -311,6 +312,7 @@ static const struct nla_policy ip6_tun_policy[LWTUNNEL_IP6_MAX + 1] = {
};
static int ip6_tun_build_state(struct net_device *dev, struct nlattr *attr,
+ unsigned int family, const void *cfg,
struct lwtunnel_state **ts)
{
struct ip_tunnel_info *tun_info;
diff --git a/net/ipv6/ila.c b/net/ipv6/ila.c
index f011c3d5ca40..678d2df4b8d9 100644
--- a/net/ipv6/ila.c
+++ b/net/ipv6/ila.c
@@ -14,6 +14,8 @@
struct ila_params {
__be64 locator;
+ __be64 locator_match;
+ __wsum csum_diff;
};
static inline struct ila_params *ila_params_lwtunnel(
@@ -33,6 +35,9 @@ static inline __wsum compute_csum_diff8(const __be32 *from, const __be32 *to)
static inline __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p)
{
+ if (*(__be64 *)&ip6h->daddr == p->locator_match)
+ return p->csum_diff;
+ else
return compute_csum_diff8((__be32 *)&ip6h->daddr,
(__be32 *)&p->locator);
}
@@ -123,14 +128,19 @@ static struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = {
};
static int ila_build_state(struct net_device *dev, struct nlattr *nla,
+ unsigned int family, const void *cfg,
struct lwtunnel_state **ts)
{
struct ila_params *p;
struct nlattr *tb[ILA_ATTR_MAX + 1];
size_t encap_len = sizeof(*p);
struct lwtunnel_state *newts;
+ const struct fib6_config *cfg6 = cfg;
int ret;
+ if (family != AF_INET6)
+ return -EINVAL;
+
ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla,
ila_nl_policy);
if (ret < 0)
@@ -148,6 +158,15 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla,
p->locator = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]);
+ if (cfg6->fc_dst_len > sizeof(__be64)) {
+ /* Precompute checksum difference for translation since we
+ * know both the old locator and the new one.
+ */
+ p->locator_match = *(__be64 *)&cfg6->fc_dst;
+ p->csum_diff = compute_csum_diff8(
+ (__be32 *)&p->locator_match, (__be32 *)&p->locator);
+ }
+
newts->type = LWTUNNEL_ENCAP_ILA;
newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT |
LWTUNNEL_STATE_INPUT_REDIRECT;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index e476f01add87..df3e353a012d 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1819,7 +1819,8 @@ int ip6_route_add(struct fib6_config *cfg)
struct lwtunnel_state *lwtstate;
err = lwtunnel_build_state(dev, cfg->fc_encap_type,
- cfg->fc_encap, &lwtstate);
+ cfg->fc_encap, AF_INET6, cfg,
+ &lwtstate);
if (err)
goto out;
rt->dst.lwtstate = lwtstate_get(lwtstate);
diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c
index 3da5ca3ba563..21e70bc9af98 100644
--- a/net/mpls/mpls_iptunnel.c
+++ b/net/mpls/mpls_iptunnel.c
@@ -123,6 +123,7 @@ drop:
}
static int mpls_build_state(struct net_device *dev, struct nlattr *nla,
+ unsigned int family, const void *cfg,
struct lwtunnel_state **ts)
{
struct mpls_iptunnel_encap *tun_encap_info;