PAWS:Protect against wrapped sequence numbers

2011年12月25日 14点33分 阅读次数: 236 没有评论

很多地方要比较两个值大小,比如两个时间戳谁前谁后,两个序列号也类似 如果序列号是64位的,那不会有什么问题,直接做减法就可以了,但是如果是32或者更小,或者该值不是从0开始,那就需要注意了: /* * These inlines deal with timer wrapping correctly. You are * strongly encouraged to use them * 1. Because people otherwise forget * 2. Because if the timer wrap changes in future you won’t have to * alter your driver code. * * time_after(a,b) returns true if the time a is after [...]

分类: TCP协议 标签:

sk_stream_write_space函数

2011年12月22日 19点10分 阅读次数: 210 没有评论

select/poll函数用于多路查询fd是否就绪,当服务器并发量太大,而每次查询一组(比如1024)fd都有数据就绪时,本质上select/poll就退化为轮询了,这种情况暂且不管。 因为一旦就绪,select/poll返回之后内核就跟这两函数无关了。 使用epoll将有本质的改善。 当应用层因为调用太块而网络太慢时,tcp的队列很快将塞满,通常这时候会调用poll函数来等待有一定的空间可用。 对于有队列的情况(SOCK_USE_WRITE_QUEUE),比如tcp考虑重传就需要,将在写队列有空间可用的时候(比如被ack了的数据包就可以删除)调用空间可用函数sk_write_space。 对于没有队列的情况,将在数据包被释放的时候由destructor函数sock_wfree调用相应的sk->sk_write_space函数通知空间可用。 sk->sk_write_space函数对tcp来说就是sk_stream_write_space: void sk_stream_write_space(struct sock *sk) {         struct socket *sock = sk->sk_socket;         struct socket_wq *wq;           if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock) {                 clear_bit(SOCK_NOSPACE, sock->flags);                   rcu_read_lock();                 wq = rcu_dereference(sk->sk_wq);                 if (wq_has_sleeper(wq))                         wake_up_interruptible_poll(&wq->wait, POLLOUT |                                                 POLLWRNORM | POLLWRBAND);                 if (wq [...]

分类: TCP协议, 网络 标签: ,

RTM_F_NOTIFY标志

2011年12月19日 22点12分 阅读次数: 174 没有评论

In the manual page is written that “RTM_F_NOTIFY if the route changes, notify the user via rtnetlink”. Can you give me some information about how this ‘notifying’ works? How can I be notified? Will I be notified about one certain route change or only generaly about that route table changed? I was looking for in [...]

分类: 网络, 路由 标签: ,

路由子系统user/kernel空间交互: netlink接口实例

2011年12月18日 18点23分 阅读次数: 226 没有评论

netlink接口   当用ip命令和内核交互时, 使用AF_NETLINK协议族的NETLINK_ROUTE协议 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); (NETLINK_FIB_LOOKUP用于查询某个条件会使用那个路由表,iproute2并未使用) 系统启动时,rtnetlink_net_init函数用于初始化NETLINK_ROUTE协议处理函数 static int __net_init rtnetlink_net_init(struct net *net) { struct sock *sk; sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX, rtnetlink_rcv, &rtnl_mutex, THIS_MODULE); if (!sk) return -ENOMEM; net->rtnl = sk; return 0; } AF_NETLINK协议族的各个协议基本都是类似的方法通过netlink_kernel_create函数注册相应的协议处理函数,其它的功能有流量控制和netfilter等。 当用户太使用AF_NETLINK协议族请求时,AF_NETLINK负责把请求内容发送到目标(由netlink协议头struct nlmsghdr nlh的字段nlmsg_pid指定)时,内核负责调用相应的处理函数,跟内核通信: nlmsg_pid = 0; 对于ip命令它的处理函数为rtnetlink_rcv,其它的命令比如iptables,tc等接口是类似的,当然了,在netlink_kernel_create调用之前netlink协议族本身必须初始化过了,在net/netlink/af_netlink.c中实现。 各个不同的协议在一般在相应模块的代码初始化时调用netlink_kernel_create,它们的初始化过程比netlink晚。 协议处理函数 static void rtnetlink_rcv(struct sk_buff *skb) { [...]

分类: 网络 标签:

TCP thin-stream支持

2011年12月12日 22点32分 阅读次数: 195 没有评论

最新的内核支持: Documentation/networing/tcp-thin.txt 主要是避免在某些需要避免延迟的时候仅仅因为重传定时器超时就进入慢启动 支持sysctl全局选项和每个连接的选项 在超时的时候(tcp_retransmit_timer),对thin-stream设置超时时不进行指数递增(每次double) out_reset_timer: /* If stream is thin, use linear timeouts. Since ‘icsk_backoff’ is * used to reset timer, set to 0. Recalculate ‘icsk_rto’ as this * might be increased if the stream oscillates between thin and thick, * thus the old value might already be too high compared to the value [...]

分类: TCP协议 标签:

syn_ack_recalc笔记

2011年12月12日 21点00分 阅读次数: 100 没有评论

这个函数主要判断是否要重传syn-ack,如果没有数据来了之后accept的选项 #define TCP_DEFER_ACCEPT 9 /* Wake up listener only when data arrive */ 直接根据重传次数判断 /* Decide when to expire the request and when to resend SYN-ACK */   static inline void syn_ack_recalc(struct request_sock *req, const int thresh, const int max_retries, const u8 rskq_defer_accept, int *expire, int *resend) { if (!rskq_defer_accept) { *expire = req->retrans >= [...]

分类: TCP协议 标签:

tcp_fast_path_on: 开启快速接收路径

2011年12月10日 20点36分 阅读次数: 93 没有评论

snd_wnd 表示对端窗口大小,snd_wl1记录了该窗口的左端 static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd) { //(wordlen = len/4) << 24 tp->pred_flags = htonl((tp->tcp_header_len << 26) | ntohl(TCP_FLAG_ACK) | snd_wnd); }   static inline void tcp_fast_path_on(struct tcp_sock *tp) { __tcp_fast_path_on(tp, tp->snd_wnd >> tp->rx_opt.snd_wscale); } 虽然TCP是双向(全双工)的,但是跟打电话类似,大多数时候一边说一段,这时候窗口也是可以期待的,因为通常一端如果是发那么说明它的接收缓冲区是空的,窗口大小一般也不会变化。

分类: TCP协议 标签:

tcp_sequence函数检查序列号是否合法

2011年12月10日 11点30分 阅读次数: 122 没有评论

rcv_nxt rcv_nxt表示本端期待的对方的下一个seq是什么,如果收了字节1、2,那么rcv_nxt等于3,这个值和是否已经确认前面收到的字节无关。 每当需要发送(可能没有数据,仅仅是ack)的时候会对当前已经在接收缓存中的数据进行ack,即ack_seq = rcv_nxt;发送ack的时机很多,发送的时候会对窗口进行更新(tcp_select_window),因为接收缓存中很有可能有数据导致了窗口变小。 rcv_wup rcv_wup字段表示刚刚的ack_seq,rcv_wup = ack_seq = rcv_nxt。即:rcv_wup之前的都已经ack过了(尽管对方可能还没收到,但那属于重传范畴)。 一旦rcv_wup字段更新了,那么新收到的包seq至seq+data_len=end_seq如果在rcv_wup之前的话将被认为是过期的,比如很可能是重传的包,因为本端都已经确认收到过了。 序列号太小说明过期,序列号超出滑动窗口显然也是不能信任的,任何一时刻,rcv_nxt总表示本端期待下一个数据的seq是什么,rcv_wup一开始和rcv_nxt相等:期待的正是本端发送的ack_seq。然而,一段时间后,本端收到一个包,数据为m..n,这时候rcv_wup还等于m,rcv_nxt更新为n;为什么rcv_wup不更新呢,因为字节m..n还没确认。为什么不确认,好多原因,比如最基本的是延迟的ack。超出窗口就等于说是m..n中的m > (rcv_wup + 当时计算出的窗口rcv_wnd)。 当然了, 由于在更新了rcv_wup+rcv_wnd之后以及收m..n之前曾经收到过包f..g, rcv_nxt = rcv_wup + g-f; rcv_wnd也比实际的窗口大,因为它没有考虑到f..g这段数据,还没确认呢。 m > rcv_wup + rcv_wnd m > rcv_nxt – (g-f) + rcv_wnd m > rcv_nxt + 当前真实的window(tcp_receive_window) static inline int tcp_sequence(const struct tcp_sock *tp, u32 seq, u32 end_seq) { return [...]

分类: TCP协议 标签:

nohdr字段的含义

2011年12月4日 22点07分 阅读次数: 130 没有评论

skb里面的nohdr是个flag,如果设置上,表明对skb的数据的header部分(data–>tail)进行操作时可以直接操作,而不需要复制。 nohdr只有一个地方会设置: /** * skb_header_release – release reference to header * @skb: buffer to operate on * * Drop a reference to the header part of the buffer. This is done * by acquiring a payload reference. You must not read from the header * part of skb->data after this. */ static inline void skb_header_release(struct [...]

分类: 网络 标签:

谁给解惑一下tcp_checksum_complete_user

2011年12月3日 21点54分 阅读次数: 153 1 条评论

static __sum16 __tcp_checksum_complete_user(struct sock *sk, struct sk_buff *skb) { __sum16 result; if (sock_owned_by_user(sk)) { local_bh_enable(); result = __tcp_checksum_complete(skb); local_bh_disable(); } else { result = __tcp_checksum_complete(skb); } return result; } 该函数应该是在bh上下文执行,怎么还能local_bh_enable? 即使能,为什么需要这么做?

分类: TCP协议 标签: