Commit 0580e4e8 authored by Alexey Kuznetsov's avatar Alexey Kuznetsov Committed by Hideaki Yoshifuji

[NET]: Cleanup DST metrics and abstract MSS/PMTU further.

- Changed dst named metrics, to RTAX_MAX metrics array.
- Add inline shorthands to access them
- Add update_pmtu and get_mss to DST ops.
- Add path component to DST, it is DST itself by default.
parent 145c04ec
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#define _NET_DST_H #define _NET_DST_H
#include <linux/config.h> #include <linux/config.h>
#include <linux/rtnetlink.h>
#include <net/neighbour.h> #include <net/neighbour.h>
/* /*
...@@ -22,6 +23,13 @@ ...@@ -22,6 +23,13 @@
#define DST_GC_INC (5*HZ) #define DST_GC_INC (5*HZ)
#define DST_GC_MAX (120*HZ) #define DST_GC_MAX (120*HZ)
/* Each dst_entry has reference count and sits in some parent list(s).
* When it is removed from parent list, it is "freed" (dst_free).
* After this it enters dead state (dst->obsolete > 0) and if its refcnt
* is zero, it can be destroyed immediately, otherwise it is added
* to gc list and garbage collector periodically checks the refcnt.
*/
struct sk_buff; struct sk_buff;
struct dst_entry struct dst_entry
...@@ -39,15 +47,8 @@ struct dst_entry ...@@ -39,15 +47,8 @@ struct dst_entry
unsigned header_len; /* more space at head required */ unsigned header_len; /* more space at head required */
unsigned mxlock; u32 metrics[RTAX_MAX];
unsigned pmtu; struct dst_entry *path;
unsigned window;
unsigned rtt;
unsigned rttvar;
unsigned ssthresh;
unsigned cwnd;
unsigned advmss;
unsigned reordering;
unsigned long rate_last; /* rate limiting for ICMP */ unsigned long rate_last; /* rate limiting for ICMP */
unsigned long rate_tokens; unsigned long rate_tokens;
...@@ -81,6 +82,8 @@ struct dst_ops ...@@ -81,6 +82,8 @@ struct dst_ops
void (*destroy)(struct dst_entry *); void (*destroy)(struct dst_entry *);
struct dst_entry * (*negative_advice)(struct dst_entry *); struct dst_entry * (*negative_advice)(struct dst_entry *);
void (*link_failure)(struct sk_buff *); void (*link_failure)(struct sk_buff *);
void (*update_pmtu)(struct dst_entry *dst, u32 mtu);
int (*get_mss)(struct dst_entry *dst, u32 mtu);
int entry_size; int entry_size;
atomic_t entries; atomic_t entries;
...@@ -89,6 +92,33 @@ struct dst_ops ...@@ -89,6 +92,33 @@ struct dst_ops
#ifdef __KERNEL__ #ifdef __KERNEL__
static inline u32
dst_metric(struct dst_entry *dst, int metric)
{
return dst->metrics[metric-1];
}
static inline u32
dst_path_metric(struct dst_entry *dst, int metric)
{
return dst->path->metrics[metric-1];
}
static inline u32
dst_pmtu(struct dst_entry *dst)
{
u32 mtu = dst_path_metric(dst, RTAX_MTU);
/* Yes, _exactly_. This is paranoia. */
barrier();
return mtu;
}
static inline int
dst_metric_locked(struct dst_entry *dst, int metric)
{
return dst_metric(dst, RTAX_LOCK) & (1<<metric);
}
static inline void dst_hold(struct dst_entry * dst) static inline void dst_hold(struct dst_entry * dst)
{ {
atomic_inc(&dst->__refcnt); atomic_inc(&dst->__refcnt);
......
...@@ -178,7 +178,7 @@ int ip_dont_fragment(struct sock *sk, struct dst_entry *dst) ...@@ -178,7 +178,7 @@ int ip_dont_fragment(struct sock *sk, struct dst_entry *dst)
{ {
return (inet_sk(sk)->pmtudisc == IP_PMTUDISC_DO || return (inet_sk(sk)->pmtudisc == IP_PMTUDISC_DO ||
(inet_sk(sk)->pmtudisc == IP_PMTUDISC_WANT && (inet_sk(sk)->pmtudisc == IP_PMTUDISC_WANT &&
!(dst->mxlock&(1<<RTAX_MTU)))); !(dst_metric(dst, RTAX_LOCK)&(1<<RTAX_MTU))));
} }
extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more); extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more);
......
...@@ -67,7 +67,7 @@ struct fib_info ...@@ -67,7 +67,7 @@ struct fib_info
int fib_protocol; int fib_protocol;
u32 fib_prefsrc; u32 fib_prefsrc;
u32 fib_priority; u32 fib_priority;
unsigned fib_metrics[RTAX_MAX]; u32 fib_metrics[RTAX_MAX];
#define fib_mtu fib_metrics[RTAX_MTU-1] #define fib_mtu fib_metrics[RTAX_MTU-1]
#define fib_window fib_metrics[RTAX_WINDOW-1] #define fib_window fib_metrics[RTAX_WINDOW-1]
#define fib_rtt fib_metrics[RTAX_RTT-1] #define fib_rtt fib_metrics[RTAX_RTT-1]
......
...@@ -115,7 +115,6 @@ extern void rt_cache_flush(int how); ...@@ -115,7 +115,6 @@ extern void rt_cache_flush(int how);
extern int ip_route_output_key(struct rtable **, const struct flowi *flp); extern int ip_route_output_key(struct rtable **, const struct flowi *flp);
extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin); extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu); extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
extern void ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu);
extern void ip_rt_send_redirect(struct sk_buff *skb); extern void ip_rt_send_redirect(struct sk_buff *skb);
extern unsigned inet_addr_type(u32 addr); extern unsigned inet_addr_type(u32 addr);
......
...@@ -921,9 +921,11 @@ static __inline__ unsigned int tcp_current_mss(struct sock *sk, int large) ...@@ -921,9 +921,11 @@ static __inline__ unsigned int tcp_current_mss(struct sock *sk, int large)
int mss_now = large && (sk->route_caps&NETIF_F_TSO) && !tp->urg_mode ? int mss_now = large && (sk->route_caps&NETIF_F_TSO) && !tp->urg_mode ?
tp->mss_cache : tp->mss_cache_std; tp->mss_cache : tp->mss_cache_std;
if (dst && dst->pmtu != tp->pmtu_cookie) if (dst) {
mss_now = tcp_sync_mss(sk, dst->pmtu); u32 mtu = dst_pmtu(dst);
if (mtu != tp->pmtu_cookie)
mss_now = tcp_sync_mss(sk, mtu);
}
if (tp->eff_sacks) if (tp->eff_sacks)
mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + mss_now -= (TCPOLEN_SACK_BASE_ALIGNED +
(tp->eff_sacks * TCPOLEN_SACK_PERBLOCK)); (tp->eff_sacks * TCPOLEN_SACK_PERBLOCK));
......
...@@ -110,6 +110,7 @@ void * dst_alloc(struct dst_ops * ops) ...@@ -110,6 +110,7 @@ void * dst_alloc(struct dst_ops * ops)
memset(dst, 0, ops->entry_size); memset(dst, 0, ops->entry_size);
dst->ops = ops; dst->ops = ops;
dst->lastuse = jiffies; dst->lastuse = jiffies;
dst->path = dst;
dst->input = dst_discard; dst->input = dst_discard;
dst->output = dst_blackhole; dst->output = dst_blackhole;
#if RT_CACHE_DEBUG >= 2 #if RT_CACHE_DEBUG >= 2
......
...@@ -1058,10 +1058,12 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int ...@@ -1058,10 +1058,12 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int
RTA_PUT(skb, RTA_SRC, 2, &rt->rt_saddr); RTA_PUT(skb, RTA_SRC, 2, &rt->rt_saddr);
if (rt->u.dst.dev) if (rt->u.dst.dev)
RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex); RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
if (rt->u.dst.window) if (dst_metric(&rt->u.dst, RTAX_WINDOW))
RTA_PUT(skb, RTAX_WINDOW, sizeof(unsigned), &rt->u.dst.window); RTA_PUT(skb, RTAX_WINDOW, sizeof(unsigned),
if (rt->u.dst.rtt) &rt->u.dst.metrics[RTAX_WINDOW - 1]);
RTA_PUT(skb, RTAX_RTT, sizeof(unsigned), &rt->u.dst.rtt); if (dst_metric(&rt->u.dst, RTAX_RTT))
RTA_PUT(skb, RTAX_RTT, sizeof(unsigned),
&rt->u.dst.metrics[RTAX_RTT]);
nlh->nlmsg_len = skb->tail - b; nlh->nlmsg_len = skb->tail - b;
return skb->len; return skb->len;
...@@ -1217,7 +1219,7 @@ static int decnet_cache_get_info(char *buffer, char **start, off_t offset, int l ...@@ -1217,7 +1219,7 @@ static int decnet_cache_get_info(char *buffer, char **start, off_t offset, int l
dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2), dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2),
atomic_read(&rt->u.dst.__refcnt), atomic_read(&rt->u.dst.__refcnt),
rt->u.dst.__use, rt->u.dst.__use,
(int)rt->u.dst.rtt (int) dst_metric(&rt->u.dst, RTAX_RTT)
); );
......
...@@ -591,7 +591,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) ...@@ -591,7 +591,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
/* RFC says return as much as we can without exceeding 576 bytes. */ /* RFC says return as much as we can without exceeding 576 bytes. */
room = rt->u.dst.pmtu; room = dst_pmtu(&rt->u.dst);
if (room > 576) if (room > 576)
room = 576; room = 576;
room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen; room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
......
...@@ -40,6 +40,9 @@ ...@@ -40,6 +40,9 @@
#include <net/checksum.h> #include <net/checksum.h>
#include <linux/route.h> #include <linux/route.h>
#include <net/route.h> #include <net/route.h>
#if 0
#include <net/xfrm.h>
#endif
static inline int ip_forward_finish(struct sk_buff *skb) static inline int ip_forward_finish(struct sk_buff *skb)
{ {
...@@ -55,12 +58,14 @@ static inline int ip_forward_finish(struct sk_buff *skb) ...@@ -55,12 +58,14 @@ static inline int ip_forward_finish(struct sk_buff *skb)
int ip_forward(struct sk_buff *skb) int ip_forward(struct sk_buff *skb)
{ {
struct net_device *dev2; /* Output device */
struct iphdr *iph; /* Our header */ struct iphdr *iph; /* Our header */
struct rtable *rt; /* Route we use */ struct rtable *rt; /* Route we use */
struct ip_options * opt = &(IPCB(skb)->opt); struct ip_options * opt = &(IPCB(skb)->opt);
unsigned short mtu;
#if 0
if (!xfrm_policy_check(XFRM_POLICY_FWD, skb))
goto drop;
#endif
if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb)) if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
return NET_RX_SUCCESS; return NET_RX_SUCCESS;
...@@ -76,32 +81,23 @@ int ip_forward(struct sk_buff *skb) ...@@ -76,32 +81,23 @@ int ip_forward(struct sk_buff *skb)
*/ */
iph = skb->nh.iph; iph = skb->nh.iph;
rt = (struct rtable*)skb->dst;
if (iph->ttl <= 1) if (iph->ttl <= 1)
goto too_many_hops; goto too_many_hops;
if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway) #if 0
goto sr_failed; if (!xfrm_route_forward(skb))
goto drop;
/* #endif
* Having picked a route we can now send the frame out
* after asking the firewall permission to do so.
*/
skb->priority = rt_tos2priority(iph->tos); iph = skb->nh.iph;
dev2 = rt->u.dst.dev; rt = (struct rtable*)skb->dst;
mtu = rt->u.dst.pmtu;
/* if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
* We now generate an ICMP HOST REDIRECT giving the route goto sr_failed;
* we calculated.
*/
if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr)
ip_rt_send_redirect(skb);
/* We are about to mangle packet. Copy it! */ /* We are about to mangle packet. Copy it! */
if (skb_cow(skb, dev2->hard_header_len)) if (skb_cow(skb, rt->u.dst.dev->hard_header_len+rt->u.dst.header_len))
goto drop; goto drop;
iph = skb->nh.iph; iph = skb->nh.iph;
...@@ -109,30 +105,17 @@ int ip_forward(struct sk_buff *skb) ...@@ -109,30 +105,17 @@ int ip_forward(struct sk_buff *skb)
ip_decrease_ttl(iph); ip_decrease_ttl(iph);
/* /*
* We now may allocate a new buffer, and copy the datagram into it. * We now generate an ICMP HOST REDIRECT giving the route
* If the indicated interface is up and running, kick it. * we calculated.
*/ */
if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr)
ip_rt_send_redirect(skb);
if (skb->len > mtu && (ntohs(iph->frag_off) & IP_DF)) skb->priority = rt_tos2priority(iph->tos);
goto frag_needed;
#ifdef CONFIG_IP_ROUTE_NAT
if (rt->rt_flags & RTCF_NAT) {
if (ip_do_nat(skb)) {
kfree_skb(skb);
return NET_RX_BAD;
}
}
#endif
return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, dev2, return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, rt->u.dst.dev,
ip_forward_finish); ip_forward_finish);
frag_needed:
IP_INC_STATS_BH(IpFragFails);
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
goto drop;
sr_failed: sr_failed:
/* /*
* Strict routing permits no gatewaying * Strict routing permits no gatewaying
......
...@@ -773,13 +773,16 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -773,13 +773,16 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
df = tiph->frag_off; df = tiph->frag_off;
if (df) if (df)
mtu = rt->u.dst.pmtu - tunnel->hlen; mtu = dst_pmtu(&rt->u.dst) - tunnel->hlen;
else else
mtu = skb->dst ? skb->dst->pmtu : dev->mtu; mtu = skb->dst ? dst_pmtu(skb->dst) : dev->mtu;
if (skb->dst)
skb->dst->ops->update_pmtu(skb->dst, mtu);
if (skb->protocol == htons(ETH_P_IP)) { if (skb->protocol == htons(ETH_P_IP)) {
if (skb->dst && mtu < skb->dst->pmtu && mtu >= 68) if (skb->dst)
skb->dst->pmtu = mtu; skb->dst->ops->update_pmtu(skb->dst, mtu);
df |= (old_iph->frag_off&htons(IP_DF)); df |= (old_iph->frag_off&htons(IP_DF));
...@@ -794,11 +797,11 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -794,11 +797,11 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
else if (skb->protocol == htons(ETH_P_IPV6)) { else if (skb->protocol == htons(ETH_P_IPV6)) {
struct rt6_info *rt6 = (struct rt6_info*)skb->dst; struct rt6_info *rt6 = (struct rt6_info*)skb->dst;
if (rt6 && mtu < rt6->u.dst.pmtu && mtu >= IPV6_MIN_MTU) { if (rt6 && mtu < dst_pmtu(skb->dst) && mtu >= IPV6_MIN_MTU) {
if ((tunnel->parms.iph.daddr && !MULTICAST(tunnel->parms.iph.daddr)) || if ((tunnel->parms.iph.daddr && !MULTICAST(tunnel->parms.iph.daddr)) ||
rt6->rt6i_dst.plen == 128) { rt6->rt6i_dst.plen == 128) {
rt6->rt6i_flags |= RTF_MODIFIED; rt6->rt6i_flags |= RTF_MODIFIED;
skb->dst->pmtu = mtu; skb->dst->metrics[RTAX_MTU-1] = mtu;
} }
} }
......
...@@ -287,6 +287,7 @@ int ip_queue_xmit(struct sk_buff *skb) ...@@ -287,6 +287,7 @@ int ip_queue_xmit(struct sk_buff *skb)
struct ip_options *opt = inet->opt; struct ip_options *opt = inet->opt;
struct rtable *rt; struct rtable *rt;
struct iphdr *iph; struct iphdr *iph;
u32 mtu;
/* Skip all of this if the packet is already routed, /* Skip all of this if the packet is already routed,
* f.e. by something like SCTP. * f.e. by something like SCTP.
...@@ -352,12 +353,13 @@ int ip_queue_xmit(struct sk_buff *skb) ...@@ -352,12 +353,13 @@ int ip_queue_xmit(struct sk_buff *skb)
ip_options_build(skb, opt, inet->daddr, rt, 0); ip_options_build(skb, opt, inet->daddr, rt, 0);
} }
if (skb->len > rt->u.dst.pmtu && (sk->route_caps&NETIF_F_TSO)) { mtu = dst_pmtu(&rt->u.dst);
if (skb->len > mtu && (sk->route_caps&NETIF_F_TSO)) {
unsigned int hlen; unsigned int hlen;
/* Hack zone: all this must be done by TCP. */ /* Hack zone: all this must be done by TCP. */
hlen = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); hlen = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
skb_shinfo(skb)->tso_size = rt->u.dst.pmtu - hlen; skb_shinfo(skb)->tso_size = mtu - hlen;
skb_shinfo(skb)->tso_segs = skb_shinfo(skb)->tso_segs =
(skb->len - hlen + skb_shinfo(skb)->tso_size - 1)/ (skb->len - hlen + skb_shinfo(skb)->tso_size - 1)/
skb_shinfo(skb)->tso_size - 1; skb_shinfo(skb)->tso_size - 1;
...@@ -436,7 +438,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) ...@@ -436,7 +438,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
if (unlikely(iph->frag_off & htons(IP_DF))) { if (unlikely(iph->frag_off & htons(IP_DF))) {
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
htonl(rt->u.dst.pmtu)); htonl(dst_pmtu(&rt->u.dst)));
kfree_skb(skb); kfree_skb(skb);
return -EMSGSIZE; return -EMSGSIZE;
} }
...@@ -446,7 +448,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) ...@@ -446,7 +448,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
*/ */
hlen = iph->ihl * 4; hlen = iph->ihl * 4;
mtu = rt->u.dst.pmtu - hlen; /* Size of data space */ mtu = dst_pmtu(&rt->u.dst) - hlen; /* Size of data space */
/* When frag_list is given, use it. First, check its validity: /* When frag_list is given, use it. First, check its validity:
* some transformers could create wrong frag_list or break existing * some transformers could create wrong frag_list or break existing
...@@ -747,7 +749,7 @@ int ip_append_data(struct sock *sk, ...@@ -747,7 +749,7 @@ int ip_append_data(struct sock *sk,
inet->cork.addr = ipc->addr; inet->cork.addr = ipc->addr;
} }
dst_hold(&rt->u.dst); dst_hold(&rt->u.dst);
inet->cork.fragsize = mtu = rt->u.dst.pmtu; inet->cork.fragsize = mtu = dst_pmtu(&rt->u.dst);
inet->cork.rt = rt; inet->cork.rt = rt;
inet->cork.length = 0; inet->cork.length = 0;
inet->sndmsg_page = NULL; inet->sndmsg_page = NULL;
...@@ -834,7 +836,7 @@ int ip_append_data(struct sock *sk, ...@@ -834,7 +836,7 @@ int ip_append_data(struct sock *sk,
* Find where to start putting bytes. * Find where to start putting bytes.
*/ */
data = skb_put(skb, fraglen); data = skb_put(skb, fraglen);
skb->nh.raw = __skb_pull(skb, exthdrlen); skb->nh.raw = data + exthdrlen;
data += fragheaderlen; data += fragheaderlen;
skb->h.raw = data + exthdrlen; skb->h.raw = data + exthdrlen;
...@@ -1063,6 +1065,9 @@ int ip_push_pending_frames(struct sock *sk) ...@@ -1063,6 +1065,9 @@ int ip_push_pending_frames(struct sock *sk)
goto out; goto out;
tail_skb = &(skb_shinfo(skb)->frag_list); tail_skb = &(skb_shinfo(skb)->frag_list);
/* move skb->data to ip header from ext header */
if (skb->data < skb->nh.raw)
__skb_pull(skb, skb->nh.raw - skb->data);
while ((tmp_skb = __skb_dequeue(&sk->write_queue)) != NULL) { while ((tmp_skb = __skb_dequeue(&sk->write_queue)) != NULL) {
__skb_pull(tmp_skb, skb->h.raw - skb->nh.raw); __skb_pull(tmp_skb, skb->h.raw - skb->nh.raw);
*tail_skb = tmp_skb; *tail_skb = tmp_skb;
......
...@@ -726,7 +726,7 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op ...@@ -726,7 +726,7 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op
val = 0; val = 0;
dst = sk_dst_get(sk); dst = sk_dst_get(sk);
if (dst) { if (dst) {
val = dst->pmtu; val = dst_pmtu(dst) - dst->header_len;
dst_release(dst); dst_release(dst);
} }
if (!val) { if (!val) {
......
...@@ -583,17 +583,17 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -583,17 +583,17 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
} }
if (tiph->frag_off) if (tiph->frag_off)
mtu = rt->u.dst.pmtu - sizeof(struct iphdr); mtu = dst_pmtu(&rt->u.dst) - sizeof(struct iphdr);
else else
mtu = skb->dst ? skb->dst->pmtu : dev->mtu; mtu = skb->dst ? dst_pmtu(skb->dst) : dev->mtu;
if (mtu < 68) { if (mtu < 68) {
tunnel->stat.collisions++; tunnel->stat.collisions++;
ip_rt_put(rt); ip_rt_put(rt);
goto tx_error; goto tx_error;
} }
if (skb->dst && mtu < skb->dst->pmtu) if (skb->dst)
skb->dst->pmtu = mtu; skb->dst->ops->update_pmtu(skb->dst, mtu);
df |= (old_iph->frag_off&htons(IP_DF)); df |= (old_iph->frag_off&htons(IP_DF));
......
...@@ -133,6 +133,7 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); ...@@ -133,6 +133,7 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie);
static void ipv4_dst_destroy(struct dst_entry *dst); static void ipv4_dst_destroy(struct dst_entry *dst);
static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst);
static void ipv4_link_failure(struct sk_buff *skb); static void ipv4_link_failure(struct sk_buff *skb);
static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
static int rt_garbage_collect(void); static int rt_garbage_collect(void);
...@@ -144,6 +145,7 @@ struct dst_ops ipv4_dst_ops = { ...@@ -144,6 +145,7 @@ struct dst_ops ipv4_dst_ops = {
.destroy = ipv4_dst_destroy, .destroy = ipv4_dst_destroy,
.negative_advice = ipv4_negative_advice, .negative_advice = ipv4_negative_advice,
.link_failure = ipv4_link_failure, .link_failure = ipv4_link_failure,
.update_pmtu = ip_rt_update_pmtu,
.entry_size = sizeof(struct rtable), .entry_size = sizeof(struct rtable),
}; };
...@@ -245,10 +247,11 @@ static int rt_cache_get_info(char *buffer, char **start, off_t offset, ...@@ -245,10 +247,11 @@ static int rt_cache_get_info(char *buffer, char **start, off_t offset,
r->u.dst.__use, r->u.dst.__use,
0, 0,
(unsigned long)r->rt_src, (unsigned long)r->rt_src,
(r->u.dst.advmss ? (dst_metric(&r->u.dst, RTAX_ADVMSS) ?
(int) r->u.dst.advmss + 40 : 0), (int) dst_metric(&r->u.dst, RTAX_ADVMSS) + 40 : 0),
r->u.dst.window, dst_metric(&r->u.dst, RTAX_WINDOW),
(int)((r->u.dst.rtt >> 3) + r->u.dst.rttvar), (int)((dst_metric(&r->u.dst, RTAX_RTT) >> 3)
+ dst_metric(&r->u.dst, RTAX_RTTVAR)),
r->fl.fl4_tos, r->fl.fl4_tos,
r->u.dst.hh ? r->u.dst.hh ?
atomic_read(&r->u.dst.hh->hh_refcnt) : atomic_read(&r->u.dst.hh->hh_refcnt) :
...@@ -1056,28 +1059,28 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu) ...@@ -1056,28 +1059,28 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
rth->rt_src == iph->saddr && rth->rt_src == iph->saddr &&
rth->fl.fl4_tos == tos && rth->fl.fl4_tos == tos &&
rth->fl.iif == 0 && rth->fl.iif == 0 &&
!(rth->u.dst.mxlock & (1 << RTAX_MTU))) { !(dst_metric_locked(&rth->u.dst, RTAX_MTU))) {
unsigned short mtu = new_mtu; unsigned short mtu = new_mtu;
if (new_mtu < 68 || new_mtu >= old_mtu) { if (new_mtu < 68 || new_mtu >= old_mtu) {
/* BSD 4.2 compatibility hack :-( */ /* BSD 4.2 compatibility hack :-( */
if (mtu == 0 && if (mtu == 0 &&
old_mtu >= rth->u.dst.pmtu && old_mtu >= rth->u.dst.metrics[RTAX_MTU-1] &&
old_mtu >= 68 + (iph->ihl << 2)) old_mtu >= 68 + (iph->ihl << 2))
old_mtu -= iph->ihl << 2; old_mtu -= iph->ihl << 2;
mtu = guess_mtu(old_mtu); mtu = guess_mtu(old_mtu);
} }
if (mtu <= rth->u.dst.pmtu) { if (mtu <= rth->u.dst.metrics[RTAX_MTU-1]) {
if (mtu < rth->u.dst.pmtu) { if (mtu < rth->u.dst.metrics[RTAX_MTU-1]) {
dst_confirm(&rth->u.dst); dst_confirm(&rth->u.dst);
if (mtu < ip_rt_min_pmtu) { if (mtu < ip_rt_min_pmtu) {
mtu = ip_rt_min_pmtu; mtu = ip_rt_min_pmtu;
rth->u.dst.mxlock |= rth->u.dst.metrics[RTAX_LOCK-1] |=
(1 << RTAX_MTU); (1 << RTAX_MTU);
} }
rth->u.dst.pmtu = mtu; rth->u.dst.metrics[RTAX_MTU-1] = mtu;
dst_set_expires(&rth->u.dst, dst_set_expires(&rth->u.dst,
ip_rt_mtu_expires); ip_rt_mtu_expires);
} }
...@@ -1090,15 +1093,15 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu) ...@@ -1090,15 +1093,15 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
return est_mtu ? : new_mtu; return est_mtu ? : new_mtu;
} }
void ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu) static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
{ {
if (dst->pmtu > mtu && mtu >= 68 && if (dst->metrics[RTAX_MTU-1] > mtu && mtu >= 68 &&
!(dst->mxlock & (1 << RTAX_MTU))) { !(dst_metric_locked(dst, RTAX_MTU))) {
if (mtu < ip_rt_min_pmtu) { if (mtu < ip_rt_min_pmtu) {
mtu = ip_rt_min_pmtu; mtu = ip_rt_min_pmtu;
dst->mxlock |= (1 << RTAX_MTU); dst->metrics[RTAX_LOCK-1] |= (1 << RTAX_MTU);
} }
dst->pmtu = mtu; dst->metrics[RTAX_MTU-1] = mtu;
dst_set_expires(dst, ip_rt_mtu_expires); dst_set_expires(dst, ip_rt_mtu_expires);
} }
} }
...@@ -1189,28 +1192,28 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) ...@@ -1189,28 +1192,28 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
if (FIB_RES_GW(*res) && if (FIB_RES_GW(*res) &&
FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
rt->rt_gateway = FIB_RES_GW(*res); rt->rt_gateway = FIB_RES_GW(*res);
memcpy(&rt->u.dst.mxlock, fi->fib_metrics, memcpy(rt->u.dst.metrics, fi->fib_metrics,
sizeof(fi->fib_metrics)); sizeof(rt->u.dst.metrics));
if (fi->fib_mtu == 0) { if (fi->fib_mtu == 0) {
rt->u.dst.pmtu = rt->u.dst.dev->mtu; rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu;
if (rt->u.dst.mxlock & (1 << RTAX_MTU) && if (rt->u.dst.metrics[RTAX_LOCK-1] & (1 << RTAX_MTU) &&
rt->rt_gateway != rt->rt_dst && rt->rt_gateway != rt->rt_dst &&
rt->u.dst.pmtu > 576) rt->u.dst.dev->mtu > 576)
rt->u.dst.pmtu = 576; rt->u.dst.metrics[RTAX_MTU-1] = 576;
} }
#ifdef CONFIG_NET_CLS_ROUTE #ifdef CONFIG_NET_CLS_ROUTE
rt->u.dst.tclassid = FIB_RES_NH(*res).nh_tclassid; rt->u.dst.tclassid = FIB_RES_NH(*res).nh_tclassid;
#endif #endif
} else } else
rt->u.dst.pmtu = rt->u.dst.dev->mtu; rt->u.dst.metrics[RTAX_MTU-1]= rt->u.dst.dev->mtu;
if (rt->u.dst.pmtu > IP_MAX_MTU) if (rt->u.dst.metrics[RTAX_MTU-1] > IP_MAX_MTU)
rt->u.dst.pmtu = IP_MAX_MTU; rt->u.dst.metrics[RTAX_MTU-1] = IP_MAX_MTU;
if (rt->u.dst.advmss == 0) if (rt->u.dst.metrics[RTAX_ADVMSS-1] == 0)
rt->u.dst.advmss = max_t(unsigned int, rt->u.dst.dev->mtu - 40, rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, rt->u.dst.dev->mtu - 40,
ip_rt_min_advmss); ip_rt_min_advmss);
if (rt->u.dst.advmss > 65535 - 40) if (rt->u.dst.metrics[RTAX_ADVMSS-1] > 65535 - 40)
rt->u.dst.advmss = 65535 - 40; rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535 - 40;
#ifdef CONFIG_NET_CLS_ROUTE #ifdef CONFIG_NET_CLS_ROUTE
#ifdef CONFIG_IP_MULTIPLE_TABLES #ifdef CONFIG_IP_MULTIPLE_TABLES
...@@ -2057,7 +2060,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, ...@@ -2057,7 +2060,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src); RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src);
if (rt->rt_dst != rt->rt_gateway) if (rt->rt_dst != rt->rt_gateway)
RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway); RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway);
if (rtnetlink_put_metrics(skb, &rt->u.dst.mxlock) < 0) if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
goto rtattr_failure; goto rtattr_failure;
ci.rta_lastuse = jiffies - rt->u.dst.lastuse; ci.rta_lastuse = jiffies - rt->u.dst.lastuse;
ci.rta_used = rt->u.dst.__use; ci.rta_used = rt->u.dst.__use;
......
...@@ -526,25 +526,25 @@ void tcp_update_metrics(struct sock *sk) ...@@ -526,25 +526,25 @@ void tcp_update_metrics(struct sock *sk)
* Probably, no packets returned in time. * Probably, no packets returned in time.
* Reset our results. * Reset our results.
*/ */
if (!(dst->mxlock&(1<<RTAX_RTT))) if (!(dst_metric_locked(dst, RTAX_RTT)))
dst->rtt = 0; dst->metrics[RTAX_RTT-1] = 0;
return; return;
} }
m = dst->rtt - tp->srtt; m = dst_metric(dst, RTAX_RTT) - tp->srtt;
/* If newly calculated rtt larger than stored one, /* If newly calculated rtt larger than stored one,
* store new one. Otherwise, use EWMA. Remember, * store new one. Otherwise, use EWMA. Remember,
* rtt overestimation is always better than underestimation. * rtt overestimation is always better than underestimation.
*/ */
if (!(dst->mxlock&(1<<RTAX_RTT))) { if (!(dst_metric_locked(dst, RTAX_RTT))) {
if (m <= 0) if (m <= 0)
dst->rtt = tp->srtt; dst->metrics[RTAX_RTT-1] = tp->srtt;
else else
dst->rtt -= (m>>3); dst->metrics[RTAX_RTT-1] -= (m>>3);
} }
if (!(dst->mxlock&(1<<RTAX_RTTVAR))) { if (!(dst_metric_locked(dst, RTAX_RTTVAR))) {
if (m < 0) if (m < 0)
m = -m; m = -m;
...@@ -553,45 +553,46 @@ void tcp_update_metrics(struct sock *sk) ...@@ -553,45 +553,46 @@ void tcp_update_metrics(struct sock *sk)
if (m < tp->mdev) if (m < tp->mdev)
m = tp->mdev; m = tp->mdev;
if (m >= dst->rttvar) if (m >= dst_metric(dst, RTAX_RTTVAR))
dst->rttvar = m; dst->metrics[RTAX_RTTVAR-1] = m;
else else
dst->rttvar -= (dst->rttvar - m)>>2; dst->metrics[RTAX_RTT-1] -=
(dst->metrics[RTAX_RTT-1] - m)>>2;
} }
if (tp->snd_ssthresh >= 0xFFFF) { if (tp->snd_ssthresh >= 0xFFFF) {
/* Slow start still did not finish. */ /* Slow start still did not finish. */
if (dst->ssthresh && if (dst_metric(dst, RTAX_SSTHRESH) &&
!(dst->mxlock&(1<<RTAX_SSTHRESH)) && !dst_metric_locked(dst, RTAX_SSTHRESH) &&
(tp->snd_cwnd >> 1) > dst->ssthresh) (tp->snd_cwnd >> 1) > dst_metric(dst, RTAX_SSTHRESH))
dst->ssthresh = tp->snd_cwnd >> 1; dst->metrics[RTAX_SSTHRESH-1] = tp->snd_cwnd >> 1;
if (!(dst->mxlock&(1<<RTAX_CWND)) && if (!dst_metric_locked(dst, RTAX_CWND) &&
tp->snd_cwnd > dst->cwnd) tp->snd_cwnd > dst_metric(dst, RTAX_CWND))
dst->cwnd = tp->snd_cwnd; dst->metrics[RTAX_CWND-1] = tp->snd_cwnd;
} else if (tp->snd_cwnd > tp->snd_ssthresh && } else if (tp->snd_cwnd > tp->snd_ssthresh &&
tp->ca_state == TCP_CA_Open) { tp->ca_state == TCP_CA_Open) {
/* Cong. avoidance phase, cwnd is reliable. */ /* Cong. avoidance phase, cwnd is reliable. */
if (!(dst->mxlock&(1<<RTAX_SSTHRESH))) if (!dst_metric_locked(dst, RTAX_SSTHRESH))
dst->ssthresh = max(tp->snd_cwnd >> 1, dst->metrics[RTAX_SSTHRESH-1] =
tp->snd_ssthresh); max(tp->snd_cwnd >> 1, tp->snd_ssthresh);
if (!(dst->mxlock&(1<<RTAX_CWND))) if (!dst_metric_locked(dst, RTAX_CWND))
dst->cwnd = (dst->cwnd + tp->snd_cwnd) >> 1; dst->metrics[RTAX_CWND-1] = (dst->metrics[RTAX_CWND-1] + tp->snd_cwnd) >> 1;
} else { } else {
/* Else slow start did not finish, cwnd is non-sense, /* Else slow start did not finish, cwnd is non-sense,
ssthresh may be also invalid. ssthresh may be also invalid.
*/ */
if (!(dst->mxlock&(1<<RTAX_CWND))) if (!dst_metric_locked(dst, RTAX_CWND))
dst->cwnd = (dst->cwnd + tp->snd_ssthresh) >> 1; dst->metrics[RTAX_CWND-1] = (dst->metrics[RTAX_CWND-1] + tp->snd_ssthresh) >> 1;
if (dst->ssthresh && if (dst->metrics[RTAX_SSTHRESH-1] &&
!(dst->mxlock&(1<<RTAX_SSTHRESH)) && !dst_metric_locked(dst, RTAX_SSTHRESH) &&
tp->snd_ssthresh > dst->ssthresh) tp->snd_ssthresh > dst->metrics[RTAX_SSTHRESH-1])
dst->ssthresh = tp->snd_ssthresh; dst->metrics[RTAX_SSTHRESH-1] = tp->snd_ssthresh;
} }
if (!(dst->mxlock&(1<<RTAX_REORDERING))) { if (!dst_metric_locked(dst, RTAX_REORDERING)) {
if (dst->reordering < tp->reordering && if (dst->metrics[RTAX_REORDERING-1] < tp->reordering &&
tp->reordering != sysctl_tcp_reordering) tp->reordering != sysctl_tcp_reordering)
dst->reordering = tp->reordering; dst->metrics[RTAX_REORDERING-1] = tp->reordering;
} }
} }
} }
...@@ -630,22 +631,23 @@ static void tcp_init_metrics(struct sock *sk) ...@@ -630,22 +631,23 @@ static void tcp_init_metrics(struct sock *sk)
dst_confirm(dst); dst_confirm(dst);
if (dst->mxlock&(1<<RTAX_CWND)) if (dst_metric_locked(dst, RTAX_CWND))
tp->snd_cwnd_clamp = dst->cwnd; tp->snd_cwnd_clamp = dst_metric(dst, RTAX_CWND);
if (dst->ssthresh) { if (dst_metric(dst, RTAX_SSTHRESH)) {
tp->snd_ssthresh = dst->ssthresh; tp->snd_ssthresh = dst_metric(dst, RTAX_SSTHRESH);
if (tp->snd_ssthresh > tp->snd_cwnd_clamp) if (tp->snd_ssthresh > tp->snd_cwnd_clamp)
tp->snd_ssthresh = tp->snd_cwnd_clamp; tp->snd_ssthresh = tp->snd_cwnd_clamp;
} }
if (dst->reordering && tp->reordering != dst->reordering) { if (dst_metric(dst, RTAX_REORDERING) &&
tp->reordering != dst_metric(dst, RTAX_REORDERING)) {
tp->sack_ok &= ~2; tp->sack_ok &= ~2;
tp->reordering = dst->reordering; tp->reordering = dst_metric(dst, RTAX_REORDERING);
} }
if (dst->rtt == 0) if (dst_metric(dst, RTAX_RTT) == 0)
goto reset; goto reset;
if (!tp->srtt && dst->rtt < (TCP_TIMEOUT_INIT << 3)) if (!tp->srtt && dst_metric(dst, RTAX_RTT) < (TCP_TIMEOUT_INIT << 3))
goto reset; goto reset;
/* Initial rtt is determined from SYN,SYN-ACK. /* Initial rtt is determined from SYN,SYN-ACK.
...@@ -662,10 +664,10 @@ static void tcp_init_metrics(struct sock *sk) ...@@ -662,10 +664,10 @@ static void tcp_init_metrics(struct sock *sk)
* to low value, and then abruptly stops to do it and starts to delay * to low value, and then abruptly stops to do it and starts to delay
* ACKs, wait for troubles. * ACKs, wait for troubles.
*/ */
if (dst->rtt > tp->srtt) if (dst_metric(dst, RTAX_RTT) > tp->srtt)
tp->srtt = dst->rtt; tp->srtt = dst_metric(dst, RTAX_RTT);
if (dst->rttvar > tp->mdev) { if (dst_metric(dst, RTAX_RTTVAR) > tp->mdev) {
tp->mdev = dst->rttvar; tp->mdev = dst_metric(dst, RTAX_RTTVAR);
tp->mdev_max = tp->rttvar = max(tp->mdev, TCP_RTO_MIN); tp->mdev_max = tp->rttvar = max(tp->mdev, TCP_RTO_MIN);
} }
tcp_set_rto(tp); tcp_set_rto(tp);
......
...@@ -933,7 +933,7 @@ static void tcp_v4_synq_add(struct sock *sk, struct open_request *req) ...@@ -933,7 +933,7 @@ static void tcp_v4_synq_add(struct sock *sk, struct open_request *req)
* This routine does path mtu discovery as defined in RFC1191. * This routine does path mtu discovery as defined in RFC1191.
*/ */
static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *iph, static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *iph,
unsigned mtu) u32 mtu)
{ {
struct dst_entry *dst; struct dst_entry *dst;
struct inet_opt *inet = inet_sk(sk); struct inet_opt *inet = inet_sk(sk);
...@@ -955,17 +955,19 @@ static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *iph, ...@@ -955,17 +955,19 @@ static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *iph,
if ((dst = __sk_dst_check(sk, 0)) == NULL) if ((dst = __sk_dst_check(sk, 0)) == NULL)
return; return;
ip_rt_update_pmtu(dst, mtu); dst->ops->update_pmtu(dst, mtu);
/* Something is about to be wrong... Remember soft error /* Something is about to be wrong... Remember soft error
* for the case, if this connection will not able to recover. * for the case, if this connection will not able to recover.
*/ */
if (mtu < dst->pmtu && ip_dont_fragment(sk, dst)) if (mtu < dst_pmtu(dst) && ip_dont_fragment(sk, dst))
sk->err_soft = EMSGSIZE; sk->err_soft = EMSGSIZE;
mtu = dst_pmtu(dst);
if (inet->pmtudisc != IP_PMTUDISC_DONT && if (inet->pmtudisc != IP_PMTUDISC_DONT &&
tp->pmtu_cookie > dst->pmtu) { tp->pmtu_cookie > mtu) {
tcp_sync_mss(sk, dst->pmtu); tcp_sync_mss(sk, mtu);
/* Resend the TCP packet because it's /* Resend the TCP packet because it's
* clear that the old packet has been * clear that the old packet has been
...@@ -1523,7 +1525,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) ...@@ -1523,7 +1525,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
(sysctl_max_syn_backlog - tcp_synq_len(sk) < (sysctl_max_syn_backlog - tcp_synq_len(sk) <
(sysctl_max_syn_backlog >> 2)) && (sysctl_max_syn_backlog >> 2)) &&
(!peer || !peer->tcp_ts_stamp) && (!peer || !peer->tcp_ts_stamp) &&
(!dst || !dst->rtt)) { (!dst || !dst_metric(dst, RTAX_RTT))) {
/* Without syncookies last quarter of /* Without syncookies last quarter of
* backlog is filled with destinations, * backlog is filled with destinations,
* proven to be alive. * proven to be alive.
...@@ -1603,8 +1605,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -1603,8 +1605,8 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newtp->ext_header_len += dst->header_len; newtp->ext_header_len += dst->header_len;
newinet->id = newtp->write_seq ^ jiffies; newinet->id = newtp->write_seq ^ jiffies;
tcp_sync_mss(newsk, dst->pmtu); tcp_sync_mss(newsk, dst_pmtu(dst));
newtp->advmss = dst->advmss; newtp->advmss = dst_metric(dst, RTAX_ADVMSS);;
tcp_initialize_rcv_mss(newsk); tcp_initialize_rcv_mss(newsk);
__tcp_v4_hash(newsk, 0); __tcp_v4_hash(newsk, 0);
......
...@@ -89,8 +89,8 @@ static __u16 tcp_advertise_mss(struct sock *sk) ...@@ -89,8 +89,8 @@ static __u16 tcp_advertise_mss(struct sock *sk)
struct dst_entry *dst = __sk_dst_get(sk); struct dst_entry *dst = __sk_dst_get(sk);
int mss = tp->advmss; int mss = tp->advmss;
if (dst && dst->advmss < mss) { if (dst && dst_metric(dst, RTAX_ADVMSS) < mss) {
mss = dst->advmss; mss = dst_metric(dst, RTAX_ADVMSS);
tp->advmss = mss; tp->advmss = mss;
} }
...@@ -554,13 +554,17 @@ static int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) ...@@ -554,13 +554,17 @@ static int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
int tcp_sync_mss(struct sock *sk, u32 pmtu) int tcp_sync_mss(struct sock *sk, u32 pmtu)
{ {
struct tcp_opt *tp = tcp_sk(sk); struct tcp_opt *tp = tcp_sk(sk);
struct dst_entry *dst = __sk_dst_get(sk);
int mss_now; int mss_now;
if (dst && dst->ops->get_mss)
pmtu = dst->ops->get_mss(dst, pmtu);
/* Calculate base mss without TCP options: /* Calculate base mss without TCP options:
It is MMS_S - sizeof(tcphdr) of rfc1122 It is MMS_S - sizeof(tcphdr) of rfc1122
*/ */
mss_now = pmtu - tp->af_specific->net_header_len - sizeof(struct tcphdr); mss_now = pmtu - tp->af_specific->net_header_len - sizeof(struct tcphdr);
/* Clamp it (mss_clamp does not include tcp options) */ /* Clamp it (mss_clamp does not include tcp options) */
if (mss_now > tp->mss_clamp) if (mss_now > tp->mss_clamp)
mss_now = tp->mss_clamp; mss_now = tp->mss_clamp;
...@@ -1211,10 +1215,10 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, ...@@ -1211,10 +1215,10 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */ if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
__u8 rcv_wscale; __u8 rcv_wscale;
/* Set this up on the first call only */ /* Set this up on the first call only */
req->window_clamp = tp->window_clamp ? : dst->window; req->window_clamp = tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW);
/* tcp_full_space because it is guaranteed to be the first packet */ /* tcp_full_space because it is guaranteed to be the first packet */
tcp_select_initial_window(tcp_full_space(sk), tcp_select_initial_window(tcp_full_space(sk),
dst->advmss - (req->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0), dst_metric(dst, RTAX_ADVMSS) - (req->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0),
&req->rcv_wnd, &req->rcv_wnd,
&req->window_clamp, &req->window_clamp,
req->wscale_ok, req->wscale_ok,
...@@ -1226,7 +1230,7 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, ...@@ -1226,7 +1230,7 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
th->window = htons(req->rcv_wnd); th->window = htons(req->rcv_wnd);
TCP_SKB_CB(skb)->when = tcp_time_stamp; TCP_SKB_CB(skb)->when = tcp_time_stamp;
tcp_syn_build_options((__u32 *)(th + 1), dst->advmss, req->tstamp_ok, tcp_syn_build_options((__u32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), req->tstamp_ok,
req->sack_ok, req->wscale_ok, req->rcv_wscale, req->sack_ok, req->wscale_ok, req->rcv_wscale,
TCP_SKB_CB(skb)->when, TCP_SKB_CB(skb)->when,
req->ts_recent); req->ts_recent);
...@@ -1255,11 +1259,11 @@ static inline void tcp_connect_init(struct sock *sk) ...@@ -1255,11 +1259,11 @@ static inline void tcp_connect_init(struct sock *sk)
if (tp->user_mss) if (tp->user_mss)
tp->mss_clamp = tp->user_mss; tp->mss_clamp = tp->user_mss;
tp->max_window = 0; tp->max_window = 0;
tcp_sync_mss(sk, dst->pmtu); tcp_sync_mss(sk, dst_pmtu(dst));
if (!tp->window_clamp) if (!tp->window_clamp)
tp->window_clamp = dst->window; tp->window_clamp = dst_metric(dst, RTAX_WINDOW);
tp->advmss = dst->advmss; tp->advmss = dst_metric(dst, RTAX_ADVMSS);
tcp_initialize_rcv_mss(sk); tcp_initialize_rcv_mss(sk);
tcp_select_initial_window(tcp_full_space(sk), tcp_select_initial_window(tcp_full_space(sk),
......
...@@ -191,6 +191,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, ...@@ -191,6 +191,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
u8 proto = fl->proto; u8 proto = fl->proto;
int seg_len = skb->len; int seg_len = skb->len;
int hlimit; int hlimit;
u32 mtu;
if (opt) { if (opt) {
int head_room; int head_room;
...@@ -237,14 +238,15 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, ...@@ -237,14 +238,15 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr); ipv6_addr_copy(&hdr->saddr, fl->nl_u.ip6_u.saddr);
ipv6_addr_copy(&hdr->daddr, first_hop); ipv6_addr_copy(&hdr->daddr, first_hop);
if (skb->len <= dst->pmtu) { mtu = dst_pmtu(dst);
if (skb->len <= mtu) {
IP6_INC_STATS(Ip6OutRequests); IP6_INC_STATS(Ip6OutRequests);
return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute); return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
} }
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n");
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
kfree_skb(skb); kfree_skb(skb);
return -EMSGSIZE; return -EMSGSIZE;
} }
...@@ -600,7 +602,7 @@ int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data, ...@@ -600,7 +602,7 @@ int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
} }
} }
mtu = dst->pmtu; mtu = dst_pmtu(dst);
if (np->frag_size < mtu) { if (np->frag_size < mtu) {
if (np->frag_size) if (np->frag_size)
mtu = np->frag_size; mtu = np->frag_size;
...@@ -796,10 +798,10 @@ int ip6_forward(struct sk_buff *skb) ...@@ -796,10 +798,10 @@ int ip6_forward(struct sk_buff *skb)
goto error; goto error;
} }
if (skb->len > dst->pmtu) { if (skb->len > dst_pmtu(dst)) {
/* Again, force OUTPUT device used as source address */ /* Again, force OUTPUT device used as source address */
skb->dev = dst->dev; skb->dev = dst->dev;
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_pmtu(dst), skb->dev);
IP6_INC_STATS_BH(Ip6InTooBigErrors); IP6_INC_STATS_BH(Ip6InTooBigErrors);
kfree_skb(skb); kfree_skb(skb);
return -EMSGSIZE; return -EMSGSIZE;
......
...@@ -474,7 +474,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval, ...@@ -474,7 +474,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval,
lock_sock(sk); lock_sock(sk);
dst = sk_dst_get(sk); dst = sk_dst_get(sk);
if (dst) { if (dst) {
val = dst->pmtu; val = dst_pmtu(dst) - dst->header_len;
dst_release(dst); dst_release(dst);
} }
release_sock(sk); release_sock(sk);
......
...@@ -759,7 +759,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) ...@@ -759,7 +759,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
in6_dev->cnf.mtu6 = mtu; in6_dev->cnf.mtu6 = mtu;
if (rt) if (rt)
rt->u.dst.pmtu = mtu; rt->u.dst.metrics[RTAX_MTU-1] = mtu;
rt6_mtu_change(skb->dev, mtu); rt6_mtu_change(skb->dev, mtu);
} }
......
...@@ -83,18 +83,18 @@ static int ip6_dst_gc(void); ...@@ -83,18 +83,18 @@ static int ip6_dst_gc(void);
static int ip6_pkt_discard(struct sk_buff *skb); static int ip6_pkt_discard(struct sk_buff *skb);
static void ip6_link_failure(struct sk_buff *skb); static void ip6_link_failure(struct sk_buff *skb);
static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
static struct dst_ops ip6_dst_ops = { static struct dst_ops ip6_dst_ops = {
AF_INET6, .family = AF_INET6,
__constant_htons(ETH_P_IPV6), .protocol = __constant_htons(ETH_P_IPV6),
1024, .gc = ip6_dst_gc,
.gc_thresh = 1024,
ip6_dst_gc, .check = ip6_dst_check,
ip6_dst_check, .negative_advice = ip6_negative_advice,
NULL, .link_failure = ip6_link_failure,
ip6_negative_advice, .update_pmtu = ip6_rt_update_pmtu,
ip6_link_failure, .entry_size = sizeof(struct rt6_info),
sizeof(struct rt6_info),
}; };
struct rt6_info ip6_null_entry = { struct rt6_info ip6_null_entry = {
...@@ -536,6 +536,16 @@ static void ip6_link_failure(struct sk_buff *skb) ...@@ -536,6 +536,16 @@ static void ip6_link_failure(struct sk_buff *skb)
} }
} }
static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
{
struct rt6_info *rt6 = (struct rt6_info*)dst;
if (mtu < dst_pmtu(dst) && rt6->rt6i_dst.plen == 128) {
rt6->rt6i_flags |= RTF_MODIFIED;
dst->metrics[RTAX_MTU-1] = mtu;
}
}
static int ip6_dst_gc() static int ip6_dst_gc()
{ {
static unsigned expire = 30*HZ; static unsigned expire = 30*HZ;
...@@ -742,14 +752,14 @@ int ip6_route_add(struct in6_rtmsg *rtmsg) ...@@ -742,14 +752,14 @@ int ip6_route_add(struct in6_rtmsg *rtmsg)
rt->rt6i_flags = rtmsg->rtmsg_flags; rt->rt6i_flags = rtmsg->rtmsg_flags;
install_route: install_route:
rt->u.dst.pmtu = ipv6_get_mtu(dev); rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
rt->u.dst.advmss = max_t(unsigned int, rt->u.dst.pmtu - 60, ip6_rt_min_advmss); rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, dst_pmtu(&rt->u.dst) - 60, ip6_rt_min_advmss);
/* Maximal non-jumbo IPv6 payload is 65535 and corresponding /* Maximal non-jumbo IPv6 payload is 65535 and corresponding
MSS is 65535 - tcp_header_size. 65535 is also valid and MSS is 65535 - tcp_header_size. 65535 is also valid and
means: "any MSS, rely only on pmtu discovery" means: "any MSS, rely only on pmtu discovery"
*/ */
if (rt->u.dst.advmss > 65535-20) if (dst_metric(&rt->u.dst, RTAX_ADVMSS) > 65535-20)
rt->u.dst.advmss = 65535; rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535;
rt->u.dst.dev = dev; rt->u.dst.dev = dev;
return rt6_ins(rt); return rt6_ins(rt);
...@@ -901,10 +911,10 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, ...@@ -901,10 +911,10 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);
nrt->rt6i_nexthop = neigh_clone(neigh); nrt->rt6i_nexthop = neigh_clone(neigh);
/* Reset pmtu, it may be better */ /* Reset pmtu, it may be better */
nrt->u.dst.pmtu = ipv6_get_mtu(neigh->dev); nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);
nrt->u.dst.advmss = max_t(unsigned int, nrt->u.dst.pmtu - 60, ip6_rt_min_advmss); nrt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, dst_pmtu(&nrt->u.dst) - 60, ip6_rt_min_advmss);
if (rt->u.dst.advmss > 65535-20) if (nrt->u.dst.metrics[RTAX_ADVMSS-1] > 65535-20)
rt->u.dst.advmss = 65535; nrt->u.dst.metrics[RTAX_ADVMSS-1] = 65535;
nrt->rt6i_hoplimit = ipv6_get_hoplimit(neigh->dev); nrt->rt6i_hoplimit = ipv6_get_hoplimit(neigh->dev);
if (rt6_ins(nrt)) if (rt6_ins(nrt))
...@@ -942,7 +952,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, ...@@ -942,7 +952,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
if (rt == NULL) if (rt == NULL)
return; return;
if (pmtu >= rt->u.dst.pmtu) if (pmtu >= dst_pmtu(&rt->u.dst))
goto out; goto out;
/* New mtu received -> path was valid. /* New mtu received -> path was valid.
...@@ -957,7 +967,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, ...@@ -957,7 +967,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
would return automatically. would return automatically.
*/ */
if (rt->rt6i_flags & RTF_CACHE) { if (rt->rt6i_flags & RTF_CACHE) {
rt->u.dst.pmtu = pmtu; rt->u.dst.metrics[RTAX_MTU-1] = pmtu;
dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires); dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES; rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;
goto out; goto out;
...@@ -971,7 +981,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, ...@@ -971,7 +981,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
nrt = rt6_cow(rt, daddr, saddr); nrt = rt6_cow(rt, daddr, saddr);
if (!nrt->u.dst.error) { if (!nrt->u.dst.error) {
nrt->u.dst.pmtu = pmtu; nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires); dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
dst_release(&nrt->u.dst); dst_release(&nrt->u.dst);
...@@ -986,7 +996,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, ...@@ -986,7 +996,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop); nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop);
dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires); dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);
nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES; nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
nrt->u.dst.pmtu = pmtu; nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
rt6_ins(nrt); rt6_ins(nrt);
} }
...@@ -1008,7 +1018,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) ...@@ -1008,7 +1018,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
rt->u.dst.input = ort->u.dst.input; rt->u.dst.input = ort->u.dst.input;
rt->u.dst.output = ort->u.dst.output; rt->u.dst.output = ort->u.dst.output;
memcpy(&rt->u.dst.mxlock, &ort->u.dst.mxlock, RTAX_MAX*sizeof(unsigned)); memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
rt->u.dst.dev = ort->u.dst.dev; rt->u.dst.dev = ort->u.dst.dev;
if (rt->u.dst.dev) if (rt->u.dst.dev)
dev_hold(rt->u.dst.dev); dev_hold(rt->u.dst.dev);
...@@ -1156,10 +1166,10 @@ int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev) ...@@ -1156,10 +1166,10 @@ int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev)
rt->u.dst.input = ip6_input; rt->u.dst.input = ip6_input;
rt->u.dst.output = ip6_output; rt->u.dst.output = ip6_output;
rt->rt6i_dev = dev_get_by_name("lo"); rt->rt6i_dev = dev_get_by_name("lo");
rt->u.dst.pmtu = ipv6_get_mtu(rt->rt6i_dev); rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
rt->u.dst.advmss = max_t(unsigned int, rt->u.dst.pmtu - 60, ip6_rt_min_advmss); rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, dst_pmtu(&rt->u.dst) - 60, ip6_rt_min_advmss);
if (rt->u.dst.advmss > 65535-20) if (rt->u.dst.metrics[RTAX_ADVMSS-1] > 65535-20)
rt->u.dst.advmss = 65535; rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535;
rt->rt6i_hoplimit = ipv6_get_hoplimit(rt->rt6i_dev); rt->rt6i_hoplimit = ipv6_get_hoplimit(rt->rt6i_dev);
rt->u.dst.obsolete = -1; rt->u.dst.obsolete = -1;
...@@ -1230,12 +1240,12 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) ...@@ -1230,12 +1240,12 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
caused by addrconf/ndisc. caused by addrconf/ndisc.
*/ */
if (rt->rt6i_dev == arg->dev && if (rt->rt6i_dev == arg->dev &&
rt->u.dst.pmtu > arg->mtu && rt->u.dst.metrics[RTAX_MTU-1] > arg->mtu &&
!(rt->u.dst.mxlock&(1<<RTAX_MTU))) !dst_metric_locked(&rt->u.dst, RTAX_MTU))
rt->u.dst.pmtu = arg->mtu; rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu;
rt->u.dst.advmss = max_t(unsigned int, arg->mtu - 60, ip6_rt_min_advmss); rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, arg->mtu - 60, ip6_rt_min_advmss);
if (rt->u.dst.advmss > 65535-20) if (rt->u.dst.metrics[RTAX_ADVMSS-1] > 65535-20)
rt->u.dst.advmss = 65535; rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535;
return 0; return 0;
} }
...@@ -1372,7 +1382,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, ...@@ -1372,7 +1382,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0)
RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); RTA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
} }
if (rtnetlink_put_metrics(skb, &rt->u.dst.mxlock) < 0) if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
goto rtattr_failure; goto rtattr_failure;
if (rt->u.dst.neighbour) if (rt->u.dst.neighbour)
RTA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key); RTA_PUT(skb, RTA_GATEWAY, 16, &rt->u.dst.neighbour->primary_key);
......
...@@ -519,9 +519,9 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -519,9 +519,9 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
} }
if (tiph->frag_off) if (tiph->frag_off)
mtu = rt->u.dst.pmtu - sizeof(struct iphdr); mtu = dst_pmtu(&rt->u.dst) - sizeof(struct iphdr);
else else
mtu = skb->dst ? skb->dst->pmtu : dev->mtu; mtu = skb->dst ? dst_pmtu(skb->dst) : dev->mtu;
if (mtu < 68) { if (mtu < 68) {
tunnel->stat.collisions++; tunnel->stat.collisions++;
...@@ -530,15 +530,9 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -530,15 +530,9 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
} }
if (mtu < IPV6_MIN_MTU) if (mtu < IPV6_MIN_MTU)
mtu = IPV6_MIN_MTU; mtu = IPV6_MIN_MTU;
if (skb->dst && mtu < skb->dst->pmtu) { if (tunnel->parms.iph.daddr && skb->dst)
struct rt6_info *rt6 = (struct rt6_info*)skb->dst; skb->dst->ops->update_pmtu(skb->dst, mtu);
if (mtu < rt6->u.dst.pmtu) {
if (tunnel->parms.iph.daddr || rt6->rt6i_dst.plen == 128) {
rt6->rt6i_flags |= RTF_MODIFIED;
rt6->u.dst.pmtu = mtu;
}
}
}
if (skb->len > mtu) { if (skb->len > mtu) {
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
ip_rt_put(rt); ip_rt_put(rt);
......
...@@ -805,8 +805,8 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -805,8 +805,8 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (dst->error) { if (dst->error) {
sk->err_soft = -dst->error; sk->err_soft = -dst->error;
} else if (tp->pmtu_cookie > dst->pmtu) { } else if (tp->pmtu_cookie > dst_pmtu(dst)) {
tcp_sync_mss(sk, dst->pmtu); tcp_sync_mss(sk, dst_pmtu(dst));
tcp_simple_retransmit(sk); tcp_simple_retransmit(sk);
} /* else let the usual retransmit timer handle it */ } /* else let the usual retransmit timer handle it */
dst_release(dst); dst_release(dst);
...@@ -1416,8 +1416,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, ...@@ -1416,8 +1416,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newtp->ext_header_len = newnp->opt->opt_nflen + newtp->ext_header_len = newnp->opt->opt_nflen +
newnp->opt->opt_flen; newnp->opt->opt_flen;
tcp_sync_mss(newsk, dst->pmtu); tcp_sync_mss(newsk, dst_pmtu(dst));
newtp->advmss = dst->advmss; newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
tcp_initialize_rcv_mss(newsk); tcp_initialize_rcv_mss(newsk);
newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6; newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6;
......
...@@ -175,7 +175,7 @@ int sctp_v6_get_dst_mtu(const sockaddr_storage_t *address) ...@@ -175,7 +175,7 @@ int sctp_v6_get_dst_mtu(const sockaddr_storage_t *address)
dst = ip6_route_output(NULL, &fl); dst = ip6_route_output(NULL, &fl);
if (dst) { if (dst) {
dst_mtu = dst->pmtu; dst_mtu = dst_pmtu(dst);
SCTP_DEBUG_PRINTK("sctp_v6_get_dst_mtu: " SCTP_DEBUG_PRINTK("sctp_v6_get_dst_mtu: "
"ip6_route_output: dev:%s pmtu:%d\n", "ip6_route_output: dev:%s pmtu:%d\n",
dst->dev->name, dst_mtu); dst->dev->name, dst_mtu);
......
...@@ -268,7 +268,7 @@ int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address) ...@@ -268,7 +268,7 @@ int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address)
" failed, returning %d as dst_mtu\n", " failed, returning %d as dst_mtu\n",
dst_mtu); dst_mtu);
} else { } else {
dst_mtu = rt->u.dst.pmtu; dst_mtu = dst_pmtu(&rt->u.dst);
SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu: " SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu: "
"ip_route_output_key: dev:%s pmtu:%d\n", "ip_route_output_key: dev:%s pmtu:%d\n",
rt->u.dst.dev->name, dst_mtu); rt->u.dst.dev->name, dst_mtu);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment