mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 05:41:55 +00:00
Merge branch 'kill_rtcache'
The ipv4 routing cache is non-deterministic, performance wise, and is subject to reasonably easy to launch denial of service attacks. The routing cache works great for well behaved traffic, and the world was a much friendlier place when the tradeoffs that led to the routing cache's design were considered. What it boils down to is that the performance of the routing cache is a product of the traffic patterns seen by a system rather than being a product of the contents of the routing tables. The former of which is controllable by external entitites. Even for "well behaved" legitimate traffic, high volume sites can see hit rates in the routing cache of only ~%10. The general flow of this patch series is that first the routing cache is removed. We build a completely new rtable entry every lookup request. Next we make some simplifications due to the fact that removing the routing cache causes several members of struct rtable to become no longer necessary. Then we need to make some amends such that we can legally cache pre-constructed routes in the FIB nexthops. Firstly, we need to invalidate routes which are hit with nexthop exceptions. Secondly we have to change the semantics of rt->rt_gateway such that zero means that the destination is on-link and non-zero otherwise. Now that the preparations are ready, we start caching precomputed routes in the FIB nexthops. Output and input routes need different kinds of care when determining if we can legally do such caching or not. The details are in the commit log messages for those changes. The patch series then winds down with some more struct rtable simplifications and other tidy ups that remove unnecessary overhead. On a SPARC-T3 output route lookups are ~876 cycles. Input route lookups are ~1169 cycles with rpfilter disabled, and about ~1468 cycles with rpfilter enabled. These measurements were taken with the kbench_mod test module in the net_test_tools GIT tree: git://git.kernel.org/pub/scm/linux/kernel/git/davem/net_test_tools.git That GIT tree also includes a udpflood tester tool and stresses route lookups on packet output. For example, on the same SPARC-T3 system we can run: time ./udpflood -l 10000000 10.2.2.11 with routing cache: real 1m21.955s user 0m6.530s sys 1m15.390s without routing cache: real 1m31.678s user 0m6.520s sys 1m25.140s Performance undoubtedly can easily be improved further. For example fib_table_lookup() performs a lot of excessive computations with all the masking and shifting, some of it conditionalized to deal with edge cases. Also, Eric's no-ref optimization for input route lookups can be re-instated for the FIB nexthop caching code path. I would be really pleased if someone would work on that. In fact anyone suitable motivated can just fire up perf on the loading of the test net_test_tools benchmark kernel module. I spend much of my time going: bash# perf record insmod ./kbench_mod.ko dst=172.30.42.22 src=74.128.0.1 iif=2 bash# perf report Thanks to helpful feedback from Joe Perches, Eric Dumazet, Ben Hutchings, and others. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
5e9965c15b
@ -65,7 +65,20 @@ struct dst_entry {
|
||||
unsigned short pending_confirm;
|
||||
|
||||
short error;
|
||||
|
||||
/* A non-zero value of dst->obsolete forces by-hand validation
|
||||
* of the route entry. Positive values are set by the generic
|
||||
* dst layer to indicate that the entry has been forcefully
|
||||
* destroyed.
|
||||
*
|
||||
* Negative values are used by the implementation layer code to
|
||||
* force invocation of the dst_ops->check() method.
|
||||
*/
|
||||
short obsolete;
|
||||
#define DST_OBSOLETE_NONE 0
|
||||
#define DST_OBSOLETE_DEAD 2
|
||||
#define DST_OBSOLETE_FORCE_CHK -1
|
||||
#define DST_OBSOLETE_KILL -2
|
||||
unsigned short header_len; /* more space at head required */
|
||||
unsigned short trailer_len; /* space to reserve at tail */
|
||||
#ifdef CONFIG_IP_ROUTE_CLASSID
|
||||
@ -359,7 +372,7 @@ extern struct dst_entry *dst_destroy(struct dst_entry *dst);
|
||||
|
||||
static inline void dst_free(struct dst_entry *dst)
|
||||
{
|
||||
if (dst->obsolete > 1)
|
||||
if (dst->obsolete > 0)
|
||||
return;
|
||||
if (!atomic_read(&dst->__refcnt)) {
|
||||
dst = dst_destroy(dst);
|
||||
|
@ -21,7 +21,6 @@ struct flowi_common {
|
||||
__u8 flowic_flags;
|
||||
#define FLOWI_FLAG_ANYSRC 0x01
|
||||
#define FLOWI_FLAG_CAN_SLEEP 0x02
|
||||
#define FLOWI_FLAG_RT_NOCACHE 0x04
|
||||
__u32 flowic_secid;
|
||||
};
|
||||
|
||||
|
@ -250,8 +250,7 @@ extern int inet_csk_get_port(struct sock *sk, unsigned short snum);
|
||||
|
||||
extern struct dst_entry* inet_csk_route_req(struct sock *sk,
|
||||
struct flowi4 *fl4,
|
||||
const struct request_sock *req,
|
||||
bool nocache);
|
||||
const struct request_sock *req);
|
||||
extern struct dst_entry* inet_csk_route_child_sock(struct sock *sk,
|
||||
struct sock *newsk,
|
||||
const struct request_sock *req);
|
||||
|
@ -46,6 +46,7 @@ struct fib_config {
|
||||
};
|
||||
|
||||
struct fib_info;
|
||||
struct rtable;
|
||||
|
||||
struct fib_nh_exception {
|
||||
struct fib_nh_exception __rcu *fnhe_next;
|
||||
@ -80,6 +81,8 @@ struct fib_nh {
|
||||
__be32 nh_gw;
|
||||
__be32 nh_saddr;
|
||||
int nh_saddr_genid;
|
||||
struct rtable *nh_rth_output;
|
||||
struct rtable *nh_rth_input;
|
||||
struct fnhe_hash_bucket *nh_exceptions;
|
||||
};
|
||||
|
||||
|
@ -44,38 +44,35 @@ struct fib_info;
|
||||
struct rtable {
|
||||
struct dst_entry dst;
|
||||
|
||||
/* Lookup key. */
|
||||
__be32 rt_key_dst;
|
||||
__be32 rt_key_src;
|
||||
|
||||
int rt_genid;
|
||||
unsigned int rt_flags;
|
||||
__u16 rt_type;
|
||||
__u8 rt_key_tos;
|
||||
__u16 rt_is_input;
|
||||
|
||||
__be32 rt_dst; /* Path destination */
|
||||
__be32 rt_src; /* Path source */
|
||||
int rt_route_iif;
|
||||
int rt_iif;
|
||||
int rt_oif;
|
||||
__u32 rt_mark;
|
||||
|
||||
/* Info on neighbour */
|
||||
__be32 rt_gateway;
|
||||
|
||||
/* Miscellaneous cached information */
|
||||
u32 rt_pmtu;
|
||||
struct fib_info *fi; /* for client ref to shared metrics */
|
||||
};
|
||||
|
||||
static inline bool rt_is_input_route(const struct rtable *rt)
|
||||
{
|
||||
return rt->rt_route_iif != 0;
|
||||
return rt->rt_is_input != 0;
|
||||
}
|
||||
|
||||
static inline bool rt_is_output_route(const struct rtable *rt)
|
||||
{
|
||||
return rt->rt_route_iif == 0;
|
||||
return rt->rt_is_input == 0;
|
||||
}
|
||||
|
||||
static inline __be32 rt_nexthop(const struct rtable *rt, __be32 daddr)
|
||||
{
|
||||
if (rt->rt_gateway)
|
||||
return rt->rt_gateway;
|
||||
return daddr;
|
||||
}
|
||||
|
||||
struct ip_rt_acct {
|
||||
@ -109,7 +106,6 @@ extern struct ip_rt_acct __percpu *ip_rt_acct;
|
||||
struct in_device;
|
||||
extern int ip_rt_init(void);
|
||||
extern void rt_cache_flush(struct net *net, int how);
|
||||
extern void rt_cache_flush_batch(struct net *net);
|
||||
extern struct rtable *__ip_route_output_key(struct net *, struct flowi4 *flp);
|
||||
extern struct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp,
|
||||
struct sock *sk);
|
||||
@ -161,20 +157,8 @@ static inline struct rtable *ip_route_output_gre(struct net *net, struct flowi4
|
||||
return ip_route_output_key(net, fl4);
|
||||
}
|
||||
|
||||
extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src,
|
||||
u8 tos, struct net_device *devin, bool noref);
|
||||
|
||||
static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src,
|
||||
u8 tos, struct net_device *devin)
|
||||
{
|
||||
return ip_route_input_common(skb, dst, src, tos, devin, false);
|
||||
}
|
||||
|
||||
static inline int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 src,
|
||||
u8 tos, struct net_device *devin)
|
||||
{
|
||||
return ip_route_input_common(skb, dst, src, tos, devin, true);
|
||||
}
|
||||
extern int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src,
|
||||
u8 tos, struct net_device *devin);
|
||||
|
||||
extern void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
|
||||
int oif, u32 mark, u8 protocol, int flow_flags);
|
||||
|
@ -94,7 +94,7 @@ loop:
|
||||
* But we do not have state "obsoleted, but
|
||||
* referenced by parent", so it is right.
|
||||
*/
|
||||
if (dst->obsolete > 1)
|
||||
if (dst->obsolete > 0)
|
||||
continue;
|
||||
|
||||
___dst_free(dst);
|
||||
@ -202,7 +202,7 @@ static void ___dst_free(struct dst_entry *dst)
|
||||
*/
|
||||
if (dst->dev == NULL || !(dst->dev->flags&IFF_UP))
|
||||
dst->input = dst->output = dst_discard;
|
||||
dst->obsolete = 2;
|
||||
dst->obsolete = DST_OBSOLETE_DEAD;
|
||||
}
|
||||
|
||||
void __dst_free(struct dst_entry *dst)
|
||||
|
@ -508,7 +508,7 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
|
||||
struct dst_entry *dst;
|
||||
struct flowi4 fl4;
|
||||
|
||||
dst = inet_csk_route_req(sk, &fl4, req, false);
|
||||
dst = inet_csk_route_req(sk, &fl4, req);
|
||||
if (dst == NULL)
|
||||
goto out;
|
||||
|
||||
|
@ -1176,7 +1176,7 @@ make_route:
|
||||
if (dev_out->flags & IFF_LOOPBACK)
|
||||
flags |= RTCF_LOCAL;
|
||||
|
||||
rt = dst_alloc(&dn_dst_ops, dev_out, 1, 0, DST_HOST);
|
||||
rt = dst_alloc(&dn_dst_ops, dev_out, 1, DST_OBSOLETE_NONE, DST_HOST);
|
||||
if (rt == NULL)
|
||||
goto e_nobufs;
|
||||
|
||||
@ -1444,7 +1444,7 @@ static int dn_route_input_slow(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
make_route:
|
||||
rt = dst_alloc(&dn_dst_ops, out_dev, 0, 0, DST_HOST);
|
||||
rt = dst_alloc(&dn_dst_ops, out_dev, 0, DST_OBSOLETE_NONE, DST_HOST);
|
||||
if (rt == NULL)
|
||||
goto e_nobufs;
|
||||
|
||||
|
@ -475,8 +475,7 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb)
|
||||
return 1;
|
||||
}
|
||||
|
||||
paddr = skb_rtable(skb)->rt_gateway;
|
||||
|
||||
paddr = rt_nexthop(skb_rtable(skb), ip_hdr(skb)->daddr);
|
||||
if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr,
|
||||
paddr, dev))
|
||||
return 0;
|
||||
@ -828,7 +827,7 @@ static int arp_process(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
if (arp->ar_op == htons(ARPOP_REQUEST) &&
|
||||
ip_route_input_noref(skb, tip, sip, 0, dev) == 0) {
|
||||
ip_route_input(skb, tip, sip, 0, dev) == 0) {
|
||||
|
||||
rt = skb_rtable(skb);
|
||||
addr_type = rt->rt_type;
|
||||
|
@ -1072,11 +1072,6 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
|
||||
rt_cache_flush(dev_net(dev), 0);
|
||||
break;
|
||||
case NETDEV_UNREGISTER_BATCH:
|
||||
/* The batch unregister is only called on the first
|
||||
* device in the list of devices being unregistered.
|
||||
* Therefore we should not pass dev_net(dev) in here.
|
||||
*/
|
||||
rt_cache_flush_batch(NULL);
|
||||
break;
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
|
@ -171,6 +171,10 @@ static void free_fib_info_rcu(struct rcu_head *head)
|
||||
dev_put(nexthop_nh->nh_dev);
|
||||
if (nexthop_nh->nh_exceptions)
|
||||
free_nh_exceptions(nexthop_nh);
|
||||
if (nexthop_nh->nh_rth_output)
|
||||
dst_release(&nexthop_nh->nh_rth_output->dst);
|
||||
if (nexthop_nh->nh_rth_input)
|
||||
dst_release(&nexthop_nh->nh_rth_input->dst);
|
||||
} endfor_nexthops(fi);
|
||||
|
||||
release_net(fi->fib_net);
|
||||
|
@ -368,8 +368,7 @@ EXPORT_SYMBOL(inet_csk_reset_keepalive_timer);
|
||||
|
||||
struct dst_entry *inet_csk_route_req(struct sock *sk,
|
||||
struct flowi4 *fl4,
|
||||
const struct request_sock *req,
|
||||
bool nocache)
|
||||
const struct request_sock *req)
|
||||
{
|
||||
struct rtable *rt;
|
||||
const struct inet_request_sock *ireq = inet_rsk(req);
|
||||
@ -377,8 +376,6 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
|
||||
struct net *net = sock_net(sk);
|
||||
int flags = inet_sk_flowi_flags(sk);
|
||||
|
||||
if (nocache)
|
||||
flags |= FLOWI_FLAG_RT_NOCACHE;
|
||||
flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark,
|
||||
RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
|
||||
sk->sk_protocol,
|
||||
@ -389,7 +386,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
|
||||
rt = ip_route_output_flow(net, fl4, sk);
|
||||
if (IS_ERR(rt))
|
||||
goto no_route;
|
||||
if (opt && opt->opt.is_strictroute && fl4->daddr != rt->rt_gateway)
|
||||
if (opt && opt->opt.is_strictroute && rt->rt_gateway)
|
||||
goto route_err;
|
||||
return &rt->dst;
|
||||
|
||||
@ -422,7 +419,7 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk,
|
||||
rt = ip_route_output_flow(net, fl4, sk);
|
||||
if (IS_ERR(rt))
|
||||
goto no_route;
|
||||
if (opt && opt->opt.is_strictroute && fl4->daddr != rt->rt_gateway)
|
||||
if (opt && opt->opt.is_strictroute && rt->rt_gateway)
|
||||
goto route_err;
|
||||
return &rt->dst;
|
||||
|
||||
|
@ -258,8 +258,8 @@ static void ip_expire(unsigned long arg)
|
||||
/* skb dst is stale, drop it, and perform route lookup again */
|
||||
skb_dst_drop(head);
|
||||
iph = ip_hdr(head);
|
||||
err = ip_route_input_noref(head, iph->daddr, iph->saddr,
|
||||
iph->tos, head->dev);
|
||||
err = ip_route_input(head, iph->daddr, iph->saddr,
|
||||
iph->tos, head->dev);
|
||||
if (err)
|
||||
goto out_rcu_unlock;
|
||||
|
||||
|
@ -766,7 +766,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
|
||||
|
||||
if (skb->protocol == htons(ETH_P_IP)) {
|
||||
rt = skb_rtable(skb);
|
||||
dst = rt->rt_gateway;
|
||||
dst = rt_nexthop(rt, old_iph->daddr);
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
else if (skb->protocol == htons(ETH_P_IPV6)) {
|
||||
|
@ -336,8 +336,8 @@ static int ip_rcv_finish(struct sk_buff *skb)
|
||||
* how the packet travels inside Linux networking.
|
||||
*/
|
||||
if (!skb_dst(skb)) {
|
||||
int err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
|
||||
iph->tos, skb->dev);
|
||||
int err = ip_route_input(skb, iph->daddr, iph->saddr,
|
||||
iph->tos, skb->dev);
|
||||
if (unlikely(err)) {
|
||||
if (err == -EXDEV)
|
||||
NET_INC_STATS_BH(dev_net(skb->dev),
|
||||
|
@ -371,7 +371,7 @@ int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl)
|
||||
skb_dst_set_noref(skb, &rt->dst);
|
||||
|
||||
packet_routed:
|
||||
if (inet_opt && inet_opt->opt.is_strictroute && fl4->daddr != rt->rt_gateway)
|
||||
if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_gateway)
|
||||
goto no_route;
|
||||
|
||||
/* OK, we know where to send it, allocate and build IP header. */
|
||||
|
@ -487,7 +487,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
dev->stats.tx_fifo_errors++;
|
||||
goto tx_error;
|
||||
}
|
||||
dst = rt->rt_gateway;
|
||||
dst = rt_nexthop(rt, old_iph->daddr);
|
||||
}
|
||||
|
||||
rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
|
||||
|
@ -1795,9 +1795,12 @@ static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct sk_buff *skb)
|
||||
.daddr = iph->daddr,
|
||||
.saddr = iph->saddr,
|
||||
.flowi4_tos = RT_TOS(iph->tos),
|
||||
.flowi4_oif = rt->rt_oif,
|
||||
.flowi4_iif = rt->rt_iif,
|
||||
.flowi4_mark = rt->rt_mark,
|
||||
.flowi4_oif = (rt_is_output_route(rt) ?
|
||||
skb->dev->ifindex : 0),
|
||||
.flowi4_iif = (rt_is_output_route(rt) ?
|
||||
net->loopback_dev->ifindex :
|
||||
skb->dev->ifindex),
|
||||
.flowi4_mark = skb->mark,
|
||||
};
|
||||
struct mr_table *mrt;
|
||||
int err;
|
||||
|
@ -52,7 +52,7 @@ masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
struct nf_nat_ipv4_range newrange;
|
||||
const struct nf_nat_ipv4_multi_range_compat *mr;
|
||||
const struct rtable *rt;
|
||||
__be32 newsrc;
|
||||
__be32 newsrc, nh;
|
||||
|
||||
NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING);
|
||||
|
||||
@ -70,7 +70,8 @@ masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
|
||||
mr = par->targinfo;
|
||||
rt = skb_rtable(skb);
|
||||
newsrc = inet_select_addr(par->out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
|
||||
nh = rt_nexthop(rt, ip_hdr(skb)->daddr);
|
||||
newsrc = inet_select_addr(par->out, nh, RT_SCOPE_UNIVERSE);
|
||||
if (!newsrc) {
|
||||
pr_info("%s ate my IP address\n", par->out->name);
|
||||
return NF_DROP;
|
||||
|
1327
net/ipv4/route.c
1327
net/ipv4/route.c
File diff suppressed because it is too large
Load Diff
@ -824,7 +824,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
|
||||
struct sk_buff * skb;
|
||||
|
||||
/* First, grab a route. */
|
||||
if (!dst && (dst = inet_csk_route_req(sk, &fl4, req, nocache)) == NULL)
|
||||
if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)
|
||||
return -1;
|
||||
|
||||
skb = tcp_make_synack(sk, dst, req, rvp);
|
||||
@ -1378,7 +1378,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
|
||||
*/
|
||||
if (tmp_opt.saw_tstamp &&
|
||||
tcp_death_row.sysctl_tw_recycle &&
|
||||
(dst = inet_csk_route_req(sk, &fl4, req, want_cookie)) != NULL &&
|
||||
(dst = inet_csk_route_req(sk, &fl4, req)) != NULL &&
|
||||
fl4.daddr == saddr) {
|
||||
if (!tcp_peer_is_proven(req, dst, true)) {
|
||||
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
|
||||
|
@ -27,8 +27,8 @@ static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
|
||||
if (skb_dst(skb) == NULL) {
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
|
||||
if (ip_route_input_noref(skb, iph->daddr, iph->saddr,
|
||||
iph->tos, skb->dev))
|
||||
if (ip_route_input(skb, iph->daddr, iph->saddr,
|
||||
iph->tos, skb->dev))
|
||||
goto drop;
|
||||
}
|
||||
return dst_input(skb);
|
||||
|
@ -79,24 +79,17 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
|
||||
struct rtable *rt = (struct rtable *)xdst->route;
|
||||
const struct flowi4 *fl4 = &fl->u.ip4;
|
||||
|
||||
xdst->u.rt.rt_key_dst = fl4->daddr;
|
||||
xdst->u.rt.rt_key_src = fl4->saddr;
|
||||
xdst->u.rt.rt_key_tos = fl4->flowi4_tos;
|
||||
xdst->u.rt.rt_route_iif = fl4->flowi4_iif;
|
||||
xdst->u.rt.rt_iif = fl4->flowi4_iif;
|
||||
xdst->u.rt.rt_oif = fl4->flowi4_oif;
|
||||
xdst->u.rt.rt_mark = fl4->flowi4_mark;
|
||||
|
||||
xdst->u.dst.dev = dev;
|
||||
dev_hold(dev);
|
||||
|
||||
/* Sheit... I remember I did this right. Apparently,
|
||||
* it was magically lost, so this code needs audit */
|
||||
xdst->u.rt.rt_is_input = rt->rt_is_input;
|
||||
xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST |
|
||||
RTCF_LOCAL);
|
||||
xdst->u.rt.rt_type = rt->rt_type;
|
||||
xdst->u.rt.rt_src = rt->rt_src;
|
||||
xdst->u.rt.rt_dst = rt->rt_dst;
|
||||
xdst->u.rt.rt_gateway = rt->rt_gateway;
|
||||
xdst->u.rt.rt_pmtu = rt->rt_pmtu;
|
||||
|
||||
|
@ -281,7 +281,7 @@ static inline struct rt6_info *ip6_dst_alloc(struct net *net,
|
||||
struct fib6_table *table)
|
||||
{
|
||||
struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev,
|
||||
0, 0, flags);
|
||||
0, DST_OBSOLETE_NONE, flags);
|
||||
|
||||
if (rt) {
|
||||
struct dst_entry *dst = &rt->dst;
|
||||
@ -985,7 +985,7 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori
|
||||
struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig;
|
||||
struct dst_entry *new = NULL;
|
||||
|
||||
rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, 0, 0);
|
||||
rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0);
|
||||
if (rt) {
|
||||
new = &rt->dst;
|
||||
|
||||
|
@ -217,7 +217,7 @@ void sctp_transport_set_owner(struct sctp_transport *transport,
|
||||
void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk)
|
||||
{
|
||||
/* If we don't have a fresh route, look one up */
|
||||
if (!transport->dst || transport->dst->obsolete > 1) {
|
||||
if (!transport->dst || transport->dst->obsolete) {
|
||||
dst_release(transport->dst);
|
||||
transport->af_specific->get_dst(transport, &transport->saddr,
|
||||
&transport->fl, sk);
|
||||
|
@ -1350,7 +1350,7 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
xdst = dst_alloc(dst_ops, NULL, 0, 0, 0);
|
||||
xdst = dst_alloc(dst_ops, NULL, 0, DST_OBSOLETE_NONE, 0);
|
||||
|
||||
if (likely(xdst)) {
|
||||
struct dst_entry *dst = &xdst->u.dst;
|
||||
@ -1477,7 +1477,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
|
||||
dst1->xfrm = xfrm[i];
|
||||
xdst->xfrm_genid = xfrm[i]->genid;
|
||||
|
||||
dst1->obsolete = -1;
|
||||
dst1->obsolete = DST_OBSOLETE_FORCE_CHK;
|
||||
dst1->flags |= DST_HOST;
|
||||
dst1->lastuse = now;
|
||||
|
||||
@ -2219,12 +2219,13 @@ EXPORT_SYMBOL(__xfrm_route_forward);
|
||||
static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie)
|
||||
{
|
||||
/* Code (such as __xfrm4_bundle_create()) sets dst->obsolete
|
||||
* to "-1" to force all XFRM destinations to get validated by
|
||||
* dst_ops->check on every use. We do this because when a
|
||||
* normal route referenced by an XFRM dst is obsoleted we do
|
||||
* not go looking around for all parent referencing XFRM dsts
|
||||
* so that we can invalidate them. It is just too much work.
|
||||
* Instead we make the checks here on every use. For example:
|
||||
* to DST_OBSOLETE_FORCE_CHK to force all XFRM destinations to
|
||||
* get validated by dst_ops->check on every use. We do this
|
||||
* because when a normal route referenced by an XFRM dst is
|
||||
* obsoleted we do not go looking around for all parent
|
||||
* referencing XFRM dsts so that we can invalidate them. It
|
||||
* is just too much work. Instead we make the checks here on
|
||||
* every use. For example:
|
||||
*
|
||||
* XFRM dst A --> IPv4 dst X
|
||||
*
|
||||
@ -2234,9 +2235,9 @@ static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie)
|
||||
* stale_bundle() check.
|
||||
*
|
||||
* When a policy's bundle is pruned, we dst_free() the XFRM
|
||||
* dst which causes it's ->obsolete field to be set to a
|
||||
* positive non-zero integer. If an XFRM dst has been pruned
|
||||
* like this, we want to force a new route lookup.
|
||||
* dst which causes it's ->obsolete field to be set to
|
||||
* DST_OBSOLETE_DEAD. If an XFRM dst has been pruned like
|
||||
* this, we want to force a new route lookup.
|
||||
*/
|
||||
if (dst->obsolete < 0 && !stale_bundle(dst))
|
||||
return dst;
|
||||
|
Loading…
Reference in New Issue
Block a user