cat org.conf | sed 's/#.*$//g' | sed '/^$/d' > new.conf
2012/09/04
過濾 # 開頭及空白行
通常範例用的 .conf 都會有一堆註解,而我們只需要裡面幾行真正有用的,所以最好的方法就是把 org.conf 改成 new.conf.org 然後用指令把註解跟空白行刪掉。指令:
cat org.conf | sed 's/#.*$//g' | sed '/^$/d' > new.conf
cat org.conf | sed 's/#.*$//g' | sed '/^$/d' > new.conf
2012/08/06
網卡收到封包到網路應用程式的過程
網卡收到封包到應用程式的過程 (rtl819x, ipv4, TCP/IP)
解析網卡驅動程式
module_init(re865x_probe);
.ndo_open = re865x_open,
rc = request_irq(dev->irq, interrupt_isr, IRQF_DISABLED, dev->name, dev);
/* rtl819x 採用中斷,呼叫 interrupt_isr() */
rtl_rx_interrupt_process(status, cp); /* 呼叫 rx 中斷處理 */
interrupt_dsr_rx((unsigned long)cp);
rtl_processRxFrame(&info);
rtl_processRxToProtcolStack(skb, cp_this);
netif_receive_skb(skb); /* net/core/dev.c */
rtl865x_ipMulticastFastFwd(skb)
rtl_netif_receive_skb_hooks(skb)
vlan_hwaccel_do_receive(skb)
deliver_skb(skb, pt_prev, orig_dev); /* list_for_each_entry_rcu() 找對應的 protocol。
RCU 參考 */ pt_prev->func(skb, skb->dev, pt_prev, orig_dev); /* 傳到第三層 */
/* 以 ip 封包當解析對象繼續 Trace */
ip_rcv(skb, skb->dev, pt_prev, orig_dev)
ip_rcv_finish(skb);
ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev); /* /net/ipv4/route.c */
ip_route_input_slow(skb, daddr, saddr, tos, dev); /* 要看封包怎樣送到 socket,所以追蹤 local_input */
rth->u.dst.input= ip_local_deliver; /* 後面的 rt_intern_hash() 會呼叫 rth->u.dst.input */
rt_intern_hash(hash, rth, &skb->rtable); /* ip_local_deliver 在 /net/ipv4/ip_input.c */
ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER) /* 片段重組 /net/ipv4/ip_fragment.c */
ip_local_deliver_finish(skb);
ipprot = rcu_dereference(inet_protos[hash]); /* 又是 RCU
/* 這次要找 /net/ipv4/af_inet.c 的 inet_init() 裡面 tcp 的部分 */
/* inet_add_protocol(&tcp_protocol, IPPROTO_TCP) */
/* struct net_protocol tcp_protocol = { .handler =tcp_v4_rcv, } */
ret = ipprot->handler(skb); /* ipprot->handler 就是 tcp_v4_rcv 在 /net/ipv4/tcp_ipv4.c */
/* 轉到第四層的 tcp 封包處理 */
tcp_v4_rcv(skb)
sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest); /* 找到對應的 socket */
/* 在 /net/ipv4/inet_hashtables.c 的 __inet_lookup_listener() */
ret = tcp_v4_do_rcv(sk, skb);
tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len) /* /net/ipv4/tcp_input.c */
__skb_queue_tail(&sk->sk_async_wait_queue, skb);
sk->sk_data_ready(sk, 0); /* /include/net/sock.h */
L3 Protocol RCU
第三層通訊協定程式會在 init 階段呼叫 dev_add_pack() 將自己加入 RCU 裡面。才能在 list_for_each_entry_rcu() 找到配對。
例如 net/ipv4/arp.c
void __init arp_init(void){} 裡面呼叫 dev_add_pack(&arp_packet_type);
static struct packet_type arp_packet_type __read_mostly = {
.type =cpu_to_be16(ETH_P_ARP), /* type 編號,ETH_P_??? 定義在 include/linux/if_ether.h */
.func =arp_rcv, /* 第三層應用程式呼叫的 function */
}
很大部分的封包會是 ETH_P_IP 0x0800
net/ipv4/af_inet.c
.type = cpu_to_be16(ETH_P_IP),
.func = ip_rcv, /* 在 net/ipv4/ip_input.c */
Socket 應用程式 send() 到驅動程式發出封包的過程
從應用程式到驅動程式 (使用 ipv4, TCP/IP)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | /* application 呼叫 send */ send(clientfd, buffer, sizeof(buffer), 0); /* send 會先在 family 處理完後呼叫 sock_sendmsg */ /* socket 處置 */ sock_sendmsg() /* 設置好 iocb 之後就送交 __sock_sendmsg */ __sock_sendmsg(&iocb, sock, msg, size); /* 將 iocb 再稍做處理後呼叫 sock->ops->sendmsg */ sock->ops->sendmsg(iocb, sock, msg, size); /* sock->ops->sendmsg 要從 net/socket.c 的 __sock_create() 開始看 */ /* pf = rcu_dereference(net_families[family]); 又是 RCU,這次看的是 inet */ /* pf->create(net, sock, protocol); 所以 pf->create 會指向 inet_create */ /* 看到 net/ipv4/af_inet.c 裡面的 inet_create() 從 list_for_each_entry_rcu(answer, &inetsw[sock->type], list) */ /* 會在 list 找到 inetsw[sock->type] 對應的內容(這次看的還是 tcp),設定到 answer,*/ /* sock->ops = answer->ops; 指向 inet_stream_ops 在 /net/ipv4/af_inet.c 定義 .sendmsg = tcp_sendmsg */ /* 所以 sock->ops->sendmsg 最終指向 tcp_sendmsg() */ /* TCP/IP 處置 */ tcp_sendmsg() /* net/ipv4/tcp.c */ tcp_push_one(sk, mss_now); /* net/ipv4/tcp_output.c */ tcp_write_xmit(sk, mss_now, TCP_NAGLE_PUSH, 1, sk->sk_allocation); /* */ tcp_transmit_skb(sk, skb, 1, gfp) /* */ icsk->icsk_af_ops->queue_xmit(skb, 0); /* */ /* struct inet_connection_sock 在 include/net/inet_connection_sock.h */ /* 跟 socket 那段搜尋 sock->ops->sendmsg 方法一樣 */ /* 在 net/net/ipv4/tcp_ipv4.c 的 struct inet_connection_sock_af_ops ipv4_specific = { */ /* .queue_xmit = ip_queue_xmit, */ ip_queue_xmit() /* /net/ipv4/ip_ouput.c */ /* ip_route_output_flow() 在 net/ipv4/route.c */ /* __ip_route_output_key() */ /* ip_route_output_slow() */ /* ip_mkroute_input() */ /* __mkroute_output() { rth->u.dst.output=ip_output; } */ ip_local_out(skb); __ip_local_out(skb); nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); /* 會去執行 dst_output,要回到 ip_queue_xmit() 的 ip_route_output_flow 開始找 */ /* 最後得知 dst_output = ip_output */ ip_output() /* net/ipv4/ip_output.c */ ip_finish_output() ip_finish_output2() neigh_hh_output(dst->hh, skb); /* include/net/neighbour.h */ hh->hh_output(skb); /* 沒有頭緒,全文搜索結果指向 dev_queue_xmit */ /* 裝置處理 */ dev_queue_xmit() /* net/core/dev.c */ dev_hard_start_xmit(skb, dev, txq) ops->ndo_start_xmit(skb, dev); /* 指向 driver/net/rtl819x/rtl_nic.c 的 re865x_start_xmit */ |
訂閱:
文章 (Atom)