Skip to content

Commit

Permalink
Merge branch 'ila-cached-route'
Browse files Browse the repository at this point in the history
Tom Herbert says:

====================
ila: Cache a route in ILA lwt structure

Add a dst_cache to ila_lwt structure. This holds a cached route for the
translated address. In ila_output we now perform a route lookup after
translation and if possible (destination in original route is full 128
bits) we set the dst_cache. Subsequent calls to ila_output can then use
the cache to avoid the route lookup.

This eliminates the need to set the gateway on ILA routes as previously
was being done. Now we can do somthing like:

./ip route add 3333::2000:0:0:2/128 encap ila 2222:0:0:2 \
    csum-mode neutral-map dev eth0  ## No via needed!

Also, add destroy_state to lwt ops. We need this do destroy the
dst_cache.

- v2
  - Fixed comparisons to fc_dst_len to make comparison against number
    of bits in data structure not bytes.
  - Move destroy_state under build_state (requested by Jiri)
  - Other minor cleanup

Tested:

Running 200 TCP_RR streams:

  Baseline, no ILA

    1730716 tps
    102/170/313 50/90/99% latencies
    88.11 CPU utilization

  Using ILA in both directions

    1680428 tps
    105/176/325 50/90/99% latencies
    88.16 CPU utilization
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Oct 15, 2016
2 parents 02dc765 + 79ff2fc commit f9dbd5a
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 10 deletions.
7 changes: 3 additions & 4 deletions include/net/lwtunnel.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ struct lwtunnel_state {
int (*orig_input)(struct sk_buff *);
int len;
__u16 headroom;
struct rcu_head rcu;
__u8 data[0];
};

struct lwtunnel_encap_ops {
int (*build_state)(struct net_device *dev, struct nlattr *encap,
unsigned int family, const void *cfg,
struct lwtunnel_state **ts);
void (*destroy_state)(struct lwtunnel_state *lws);
int (*output)(struct net *net, struct sock *sk, struct sk_buff *skb);
int (*input)(struct sk_buff *skb);
int (*fill_encap)(struct sk_buff *skb,
Expand All @@ -46,10 +48,7 @@ struct lwtunnel_encap_ops {
};

#ifdef CONFIG_LWTUNNEL
static inline void lwtstate_free(struct lwtunnel_state *lws)
{
kfree(lws);
}
void lwtstate_free(struct lwtunnel_state *lws);

static inline struct lwtunnel_state *
lwtstate_get(struct lwtunnel_state *lws)
Expand Down
13 changes: 13 additions & 0 deletions net/core/lwtunnel.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,19 @@ int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
}
EXPORT_SYMBOL(lwtunnel_build_state);

void lwtstate_free(struct lwtunnel_state *lws)
{
const struct lwtunnel_encap_ops *ops = lwtun_encaps[lws->type];

if (ops->destroy_state) {
ops->destroy_state(lws);
kfree_rcu(lws, rcu);
} else {
kfree(lws);
}
}
EXPORT_SYMBOL(lwtstate_free);

int lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate)
{
const struct lwtunnel_encap_ops *ops;
Expand Down
80 changes: 74 additions & 6 deletions net/ipv6/ila/ila_lwt.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,80 @@
#include <linux/socket.h>
#include <linux/types.h>
#include <net/checksum.h>
#include <net/dst_cache.h>
#include <net/ip.h>
#include <net/ip6_fib.h>
#include <net/ip6_route.h>
#include <net/lwtunnel.h>
#include <net/protocol.h>
#include <uapi/linux/ila.h>
#include "ila.h"

struct ila_lwt {
struct ila_params p;
struct dst_cache dst_cache;
u32 connected : 1;
};

static inline struct ila_lwt *ila_lwt_lwtunnel(
struct lwtunnel_state *lwt)
{
return (struct ila_lwt *)lwt->data;
}

static inline struct ila_params *ila_params_lwtunnel(
struct lwtunnel_state *lwstate)
struct lwtunnel_state *lwt)
{
return (struct ila_params *)lwstate->data;
return &ila_lwt_lwtunnel(lwt)->p;
}

static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct dst_entry *orig_dst = skb_dst(skb);
struct ila_lwt *ilwt = ila_lwt_lwtunnel(orig_dst->lwtstate);
struct dst_entry *dst;
int err = -EINVAL;

if (skb->protocol != htons(ETH_P_IPV6))
goto drop;

ila_update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate), true);
ila_update_ipv6_locator(skb, ila_params_lwtunnel(orig_dst->lwtstate),
true);

dst = dst_cache_get(&ilwt->dst_cache);
if (unlikely(!dst)) {
struct ipv6hdr *ip6h = ipv6_hdr(skb);
struct flowi6 fl6;

/* Lookup a route for the new destination. Take into
* account that the base route may already have a gateway.
*/

memset(&fl6, 0, sizeof(fl6));
fl6.flowi6_oif = orig_dst->dev->ifindex;
fl6.flowi6_iif = LOOPBACK_IFINDEX;
fl6.daddr = *rt6_nexthop((struct rt6_info *)orig_dst,
&ip6h->daddr);

dst = ip6_route_output(net, NULL, &fl6);
if (dst->error) {
err = -EHOSTUNREACH;
dst_release(dst);
goto drop;
}

dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
goto drop;
}

if (ilwt->connected)
dst_cache_set_ip6(&ilwt->dst_cache, dst, &fl6.saddr);
}

return dst->lwtstate->orig_output(net, sk, skb);
skb_dst_set(skb, dst);
return dst_output(net, sk, skb);

drop:
kfree_skb(skb);
Expand Down Expand Up @@ -60,6 +111,7 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla,
unsigned int family, const void *cfg,
struct lwtunnel_state **ts)
{
struct ila_lwt *ilwt;
struct ila_params *p;
struct nlattr *tb[ILA_ATTR_MAX + 1];
size_t encap_len = sizeof(*p);
Expand All @@ -71,7 +123,7 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla,
if (family != AF_INET6)
return -EINVAL;

if (cfg6->fc_dst_len < sizeof(struct ila_locator) + 1) {
if (cfg6->fc_dst_len < 8 * sizeof(struct ila_locator) + 3) {
/* Need to have full locator and at least type field
* included in destination
*/
Expand Down Expand Up @@ -99,6 +151,13 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla,
if (!newts)
return -ENOMEM;

ilwt = ila_lwt_lwtunnel(newts);
ret = dst_cache_init(&ilwt->dst_cache, GFP_ATOMIC);
if (ret) {
kfree(newts);
return ret;
}

newts->len = encap_len;
p = ila_params_lwtunnel(newts);

Expand All @@ -120,11 +179,19 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla,
newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT |
LWTUNNEL_STATE_INPUT_REDIRECT;

if (cfg6->fc_dst_len == 8 * sizeof(struct in6_addr))
ilwt->connected = 1;

*ts = newts;

return 0;
}

static void ila_destroy_state(struct lwtunnel_state *lwt)
{
dst_cache_destroy(&ila_lwt_lwtunnel(lwt)->dst_cache);
}

static int ila_fill_encap_info(struct sk_buff *skb,
struct lwtunnel_state *lwtstate)
{
Expand Down Expand Up @@ -159,6 +226,7 @@ static int ila_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)

static const struct lwtunnel_encap_ops ila_encap_ops = {
.build_state = ila_build_state,
.destroy_state = ila_destroy_state,
.output = ila_output,
.input = ila_input,
.fill_encap = ila_fill_encap_info,
Expand Down

0 comments on commit f9dbd5a

Please sign in to comment.