Skip to content

Commit f9dbd5a

Browse files
committed
Merge branch 'ila-cached-route'
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>
2 parents 02dc765 + 79ff2fc commit f9dbd5a

File tree

3 files changed

+90
-10
lines changed

3 files changed

+90
-10
lines changed

include/net/lwtunnel.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ struct lwtunnel_state {
2929
int (*orig_input)(struct sk_buff *);
3030
int len;
3131
__u16 headroom;
32+
struct rcu_head rcu;
3233
__u8 data[0];
3334
};
3435

3536
struct lwtunnel_encap_ops {
3637
int (*build_state)(struct net_device *dev, struct nlattr *encap,
3738
unsigned int family, const void *cfg,
3839
struct lwtunnel_state **ts);
40+
void (*destroy_state)(struct lwtunnel_state *lws);
3941
int (*output)(struct net *net, struct sock *sk, struct sk_buff *skb);
4042
int (*input)(struct sk_buff *skb);
4143
int (*fill_encap)(struct sk_buff *skb,
@@ -46,10 +48,7 @@ struct lwtunnel_encap_ops {
4648
};
4749

4850
#ifdef CONFIG_LWTUNNEL
49-
static inline void lwtstate_free(struct lwtunnel_state *lws)
50-
{
51-
kfree(lws);
52-
}
51+
void lwtstate_free(struct lwtunnel_state *lws);
5352

5453
static inline struct lwtunnel_state *
5554
lwtstate_get(struct lwtunnel_state *lws)

net/core/lwtunnel.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,19 @@ int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
130130
}
131131
EXPORT_SYMBOL(lwtunnel_build_state);
132132

133+
void lwtstate_free(struct lwtunnel_state *lws)
134+
{
135+
const struct lwtunnel_encap_ops *ops = lwtun_encaps[lws->type];
136+
137+
if (ops->destroy_state) {
138+
ops->destroy_state(lws);
139+
kfree_rcu(lws, rcu);
140+
} else {
141+
kfree(lws);
142+
}
143+
}
144+
EXPORT_SYMBOL(lwtstate_free);
145+
133146
int lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate)
134147
{
135148
const struct lwtunnel_encap_ops *ops;

net/ipv6/ila/ila_lwt.c

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,80 @@
66
#include <linux/socket.h>
77
#include <linux/types.h>
88
#include <net/checksum.h>
9+
#include <net/dst_cache.h>
910
#include <net/ip.h>
1011
#include <net/ip6_fib.h>
12+
#include <net/ip6_route.h>
1113
#include <net/lwtunnel.h>
1214
#include <net/protocol.h>
1315
#include <uapi/linux/ila.h>
1416
#include "ila.h"
1517

18+
struct ila_lwt {
19+
struct ila_params p;
20+
struct dst_cache dst_cache;
21+
u32 connected : 1;
22+
};
23+
24+
static inline struct ila_lwt *ila_lwt_lwtunnel(
25+
struct lwtunnel_state *lwt)
26+
{
27+
return (struct ila_lwt *)lwt->data;
28+
}
29+
1630
static inline struct ila_params *ila_params_lwtunnel(
17-
struct lwtunnel_state *lwstate)
31+
struct lwtunnel_state *lwt)
1832
{
19-
return (struct ila_params *)lwstate->data;
33+
return &ila_lwt_lwtunnel(lwt)->p;
2034
}
2135

2236
static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb)
2337
{
24-
struct dst_entry *dst = skb_dst(skb);
38+
struct dst_entry *orig_dst = skb_dst(skb);
39+
struct ila_lwt *ilwt = ila_lwt_lwtunnel(orig_dst->lwtstate);
40+
struct dst_entry *dst;
41+
int err = -EINVAL;
2542

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

29-
ila_update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate), true);
46+
ila_update_ipv6_locator(skb, ila_params_lwtunnel(orig_dst->lwtstate),
47+
true);
48+
49+
dst = dst_cache_get(&ilwt->dst_cache);
50+
if (unlikely(!dst)) {
51+
struct ipv6hdr *ip6h = ipv6_hdr(skb);
52+
struct flowi6 fl6;
53+
54+
/* Lookup a route for the new destination. Take into
55+
* account that the base route may already have a gateway.
56+
*/
57+
58+
memset(&fl6, 0, sizeof(fl6));
59+
fl6.flowi6_oif = orig_dst->dev->ifindex;
60+
fl6.flowi6_iif = LOOPBACK_IFINDEX;
61+
fl6.daddr = *rt6_nexthop((struct rt6_info *)orig_dst,
62+
&ip6h->daddr);
63+
64+
dst = ip6_route_output(net, NULL, &fl6);
65+
if (dst->error) {
66+
err = -EHOSTUNREACH;
67+
dst_release(dst);
68+
goto drop;
69+
}
70+
71+
dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
72+
if (IS_ERR(dst)) {
73+
err = PTR_ERR(dst);
74+
goto drop;
75+
}
76+
77+
if (ilwt->connected)
78+
dst_cache_set_ip6(&ilwt->dst_cache, dst, &fl6.saddr);
79+
}
3080

31-
return dst->lwtstate->orig_output(net, sk, skb);
81+
skb_dst_set(skb, dst);
82+
return dst_output(net, sk, skb);
3283

3384
drop:
3485
kfree_skb(skb);
@@ -60,6 +111,7 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla,
60111
unsigned int family, const void *cfg,
61112
struct lwtunnel_state **ts)
62113
{
114+
struct ila_lwt *ilwt;
63115
struct ila_params *p;
64116
struct nlattr *tb[ILA_ATTR_MAX + 1];
65117
size_t encap_len = sizeof(*p);
@@ -71,7 +123,7 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla,
71123
if (family != AF_INET6)
72124
return -EINVAL;
73125

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

154+
ilwt = ila_lwt_lwtunnel(newts);
155+
ret = dst_cache_init(&ilwt->dst_cache, GFP_ATOMIC);
156+
if (ret) {
157+
kfree(newts);
158+
return ret;
159+
}
160+
102161
newts->len = encap_len;
103162
p = ila_params_lwtunnel(newts);
104163

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

182+
if (cfg6->fc_dst_len == 8 * sizeof(struct in6_addr))
183+
ilwt->connected = 1;
184+
123185
*ts = newts;
124186

125187
return 0;
126188
}
127189

190+
static void ila_destroy_state(struct lwtunnel_state *lwt)
191+
{
192+
dst_cache_destroy(&ila_lwt_lwtunnel(lwt)->dst_cache);
193+
}
194+
128195
static int ila_fill_encap_info(struct sk_buff *skb,
129196
struct lwtunnel_state *lwtstate)
130197
{
@@ -159,6 +226,7 @@ static int ila_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
159226

160227
static const struct lwtunnel_encap_ops ila_encap_ops = {
161228
.build_state = ila_build_state,
229+
.destroy_state = ila_destroy_state,
162230
.output = ila_output,
163231
.input = ila_input,
164232
.fill_encap = ila_fill_encap_info,

0 commit comments

Comments
 (0)