黄a在线观看-黄a在线-黄a大片-黄色片在线看-黄色毛片免费-黄色大片网站

您的位置:首頁技術文章
文章詳情頁

深入理解Linux網絡之內核是如何發送網絡包的

瀏覽:217日期:2023-09-14 20:49:07
目錄一、相關實際問題二、網絡包發送過程總覽三、網卡啟動準備四、數據從用戶進程到網卡的詳細過程1)系統調用實現2)傳輸層處理3)網絡層發送處理4)鄰居子系統5)網絡設備子系統6)軟中斷調度7)igb網卡驅動發送五、RingBuffer內存回收六、問題解答一、相關實際問題查看內核發送數據消耗的CPU時應該看sy還是si在服務器上查看/proc/softirqs,為什么NET_RX要比NET_TX大得多發送網絡數據的時候都涉及那些內存拷貝操作零拷貝到底是怎么回事為什么Kafka的網絡性能很突出二、網絡包發送過程總覽

調用系統調用send發送內存拷貝協議處理進入驅動RingBuffer實際發送中斷通知發送完成清理RingBuffer三、網卡啟動準備

現在的服務器上的網卡一般都是支持多隊列的。每一個隊列都是由一個RingBuffer表示的,開啟了多隊列以后的網卡就會有多個RingBuffer。

網卡啟動時最重要的任務就是分配和初始化RingBuffer,在網卡啟動的時候會調用到__igb_open函數,RingBuffer就是在這里分配的。

static int __igb_open(struct net_device *netdev, bool resuming){ // 分配傳輸描述符數組 err = igb_setup_all_tx_resources(adpater); // 分配接收描述符數組 err = igb_setup_all_rx_resources(adpater); // 注冊中斷處理函數 err = igb_request_irq(adapter); if(err)goto err_req_irq; // 啟用NAPI for(i = 0; i < adapter->num_q_vectors; i++)napi_enable(&(adapter->q_vector[i]->napi)); ......}static int igb_setup_all_tx_resources(struct igb_adapter *adapter){ // 有幾個隊列就構造幾個RingBuffer for(int i = 0; i < adapter->num_tx_queues; i++) { igb_setup_tx_resources(adapter->tx_ring[i]); }}

igb_setup_tx_resources內部也是申請了兩個數組,igb_tx_buffer數組和e1000_adv_tx_desc數組,一個供內核使用,一個供網卡硬件使用。

在這個時候它們之間還沒什么關系,將來在發送數據的時候這兩個數組的指針都指向同一個skb,這樣內核和硬件就能共同訪問同樣的數據了。

內核往skb寫數據,網卡硬件負責發送。

硬中斷的處理函數igb_msix_ring也是在__igb_open函數中注冊的。

四、數據從用戶進程到網卡的詳細過程1)系統調用實現

send系統調用內部真正使用的是sendto系統調用,主要做了兩件事:

在內核中把真正的socket找出來構造struct msghdr對象, 把用戶傳入的數據,比如buffer地址(用戶待發送數據的指針)、數據長度、發送標志都裝進去SYS_CALL_DEFINE6(sendto, ......){ sock = sockfd_lookup_light(fd, &err, &fput_needed); struct msghdr msg; struct iovec iov; iov.iov_base = buff; iov.iov_len = len; msg.msg_iovlen = &iov; msg.msg_iov = &iov; msg.msg_flags = flags; ...... sock_sendmsg(sock, &msg, len);}

sock_sendmsg經過一系列調用,最終來到__sock_sendmsg_nosec中調用sock->ops->sendmsg

對于AF_INET協議族的socket,sendmsg的實現統一為inet_sendmsg

2)傳輸層處理

1. 傳輸層拷貝

在進入協議棧inet_sendmsg以后,內核接著會找到sock中具體的協議處理函數,對于TCP協議而言,sk_prot操作函數集實例為tcp_prot,其中.sendmsg的實現為tcp_sendmsg(對于UDP而言中的為udp_sendmsg)。

int inet_sendmsg(......){ ...... return sk->sk_prot->sendmsg(iocb, sk, msg, size);}int tcp_sendmsg(......){ ...... // 獲取用戶傳遞過來的數據和標志 iov = msg->msg_iov; // 用戶數據地址 iovlen = msg->msg_iovlen; // 數據塊數為1 flags = msg->msg_flags; // 各種標志 copied = 0; // 已拷貝到發送隊列的字節數 // 遍歷用戶層的數據塊 while(--iovlen >= 0) {// 待發送數據塊的長度size_t seglen = iov->len; // 待發送數據塊的地址unsigned char __user *from = iov->iov_base;// 指向下一個數據塊iovlen++; ...... while(seglen > 0) { int copy = 0; int max = size_goal; // 單個skb最大的數據長度 skb = tcp_write_queue_tail(sk); // 獲取發送隊列最后一個skb // 用于返回發送隊列第一個數據包,如果不是NULL說明還有未發送的數據 if(tcp_send_head(sk)) { ...copy = max - skb->len; // 該skb還可以存放的字節數 } // 需要申請新的skb if(copy <= 0) {// 發送隊列的總大小大于等于發送緩存的上限,或尚發送緩存中未發送的數據量超過了用戶的設置值,進入等待if(!sk_stream_memory_free(sk)) { goto wait_for_sndbuf;}// 申請一個skbskb = sk_stream_alloc_skb(sk, select_size(sk, sg), sk->sk_allocation);...// 把skb添加到sock的發送隊列尾部skb_entail(sk, skb); } if(copy > seglen)copy = seglen; // skb的線性數據區中有足夠的空間 if(skb_availroom(skb)) > 0) {copy = min_t(int, copy, skb_availroom(skb));// 將用戶空間的數據拷貝到內核空間,同時計算校驗和err = skb_add_data_nocache(sk, skb, from, copy);if(err) goto do_fault; } // 線性數據區用完,使用分頁區 else{... }

這個函數的實現邏輯比較復雜,代碼總只顯示了skb拷貝的相關部分,總體邏輯如下:

如果使用了TCP Fast Open,則會在發送SYN包的同時帶上數據

如果連接尚未建好,不處于ESTABLISHED或者CLOSE_WAIT狀態則進程進入睡眠,等待三次握手的完成

獲取當前的MSS(最大報文長度)和size_goal(一個理想的TCP數據包大小,受MTU、MSS、TCP窗口大小影響)

如果網卡支持GSO(利用網卡分片),size_goal會是MSS的整數倍

遍歷用戶層的數據塊數組

獲取發送隊列的最后一個skb,如果是尚未發送的,且長度未到達size_goal,那么向這個skb繼續追加數據

否則申請一個新的skb來裝載數據

如果發送隊列的總大小大于等于發送緩存的上限,或者發送緩存中尚未發送的數據量超過了用戶的設置值:設置發送時發送緩存不夠的標志,進入等待申請一個skb,其線性區的大小為通過select_size()得到的線性數據區中TCP負荷的大小和最大的協議頭長度,申請失敗則等待可用內存前兩步成功則更新skb的TCP控制塊字段,把skb加入發送隊列隊尾,增加發送隊列的大小,減少預分配緩存的大小

將數據拷貝至skb中

如果skb的線性數據區還有剩余,就復制到線性數據區同時計算校驗和

如果已經用完則使用分頁區

檢查分頁區是否有可用空間,沒有則申請新的page,申請失敗則說明內存不足,之后會設置TCP內存壓力標志,減小發送緩沖區的上限,睡眠等待內存判斷能否往最后一個分頁追加數據,不能追加時,檢查分頁數是否已經達到了上限或網卡是否不支持分散聚合,如果是的話就將skb設置為PSH標志,然后回到4.2中重新申請一個skb來繼續填裝數據從系統層面判斷此次分頁發送緩存的申請是否合法拷貝用戶空間的數據到skb的分頁中,同時計算校驗和。更新skb的長度字段,更新sock的發送隊列大小和預分配緩存如果把數據追加到最后一個分頁了,更新最后一個分頁的數據大小。否則初始化新的分頁

拷貝成功后更新:發送隊列的最后一個序號、skb的結束序號、已經拷貝到發送隊列的數據量

發送數據

如果所有數據都拷貝好了就退出循環進行發送如果skb還可以繼續裝填數據或者發送的是帶外數據那么就繼續拷貝數據先不發送如果為發送的數據已經超過最大窗口的一半則設置PUSH標志后盡可能地將發送隊列中的skb發送出去如果當前skb就是發送隊列中唯一一個skb,則將這一個skb發送出去如果上述過程中出現緩存不足,且已經有數據拷貝到發送隊列了也直接發送

這里的發送數據只是指調用tcp_push或者tcp_push_one(情況4)或者__tcp_push_pending_frames(情況3)嘗試發送,并不一定真的發送到網絡(tcp_sendmsg主要任務只是將應用程序的數據封裝成網絡數據包放到發送隊列)。

數據何時實際被發送到網絡,取決于許多因素,包括但不限于:

TCP的擁塞控制算法:TCP使用了復雜的擁塞控制算法來防止網絡過載。如果TCP判斷網絡可能出現擁塞,它可能會延遲發送數據。發送窗口的大小:TCP使用發送窗口和接收窗口來控制數據的發送和接收。如果發送窗口已滿(即已發送但未被確認的數據量達到了發送窗口的大小),那么TCP必須等待接收到確認信息后才能發送更多的數據。網絡設備(如網卡)的狀態:如果網絡設備繁忙或出現錯誤,數據可能會被暫時掛起而無法立即發送。

struct sk_buff(常簡稱為skb)在Linux網絡棧中表示一個網絡包。它有兩個主要的數據區用來存儲數據,分別是線性數據區(linear data area)和分頁區(paged data area)。

線性數據區(linear data area): 這個區域連續存儲數據,并且能夠容納一個完整的網絡包的所有協議頭,比如MAC頭、IP頭和TCP/UDP頭等。除了協議頭部,線性數據區還可以包含一部分或全部的數據負載。每個skb都有一個線性數據區。分頁區(paged data area): 一些情況下,為了優化內存使用和提高性能,skb的數據負載部分可以存儲在一個或多個內存頁中,而非線性數據區。分頁區的數據通常只包含數據負載部分,不包含協議頭部。如果一個skb的數據全部放入了線性數據區,那么這個skb就沒有分頁區。

這種設計的好處是,對于大的數據包,可以將其數據負載部分存儲在分頁區,避免對大塊連續內存的分配,從而提高內存使用效率,減少內存碎片。另外,這種設計也可以更好地支持零拷貝技術。例如,當網絡棧接收到一個大數據包時,可以直接將數據包的數據負載部分留在原始的接收緩沖區(即分頁區),而無需將其拷貝到線性數據區,從而節省了內存拷貝的開銷。

2. 傳輸層發送

上面的發送數據步驟,不論是調用__tcp_push_pending_frames還是tcp_push_one,最終都會執行到tcp_write_xmit(在網絡協議中學到滑動窗口、擁塞控制就是在這個函數中完成的),函數的主要邏輯如下:

如果要發送多個數據段則先發送一個路徑mtu探測檢測擁塞窗口的大小,如果窗口已滿(通過窗口大小-正在網絡上傳輸的包數目判斷)則不發送檢測當前報文是否完全在發送窗口內,如果不是則不發送判斷是否需要延時發送(取決于擁塞窗口和發送窗口)根據需要對數據包進行分段(取決于擁塞窗口和發送窗口)tcp_transmit_skb發送數據包如果push_one則結束循環,否則繼續遍歷隊列發送結束循環后如果本次有數據發送,則對TCP擁塞窗口進行檢查確認

這里我們只關注發送的主過程,其他部分不過多展開,即來到tcp_transmit_skb函數

static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, gfp_t gfp_mask){ // 1.克隆新的skb出來 if(likely(clone_it)) { skb = skb_clone(skb, gfp_mask);...... } // 2.封裝TCP頭 th = tcp_hdr(skb); th->source = inet->inet_sport; th->dest = inet->inet_dport; th->window = ...; th->urg = ...; ...... // 3.調用網絡層發送接口 err = icsk->icsk_af_ops->xmit(skb, &inet->cort.fl);}

第一件事就是先克隆一個新的skb,因為skb后續在調用網絡層,最后到達網卡發送完成的時候,這個skb會被釋放掉。而TCP協議是支持丟失重傳的,在收到對方的ACK之前,這個skb不能被刪除掉。所以內核的做法就是每次調用網卡發送的時候,實際上傳遞出去的是skb的一個拷貝。等收到ACK再真正刪除。

第二件事是修改skb的TCP頭,根據實際情況把TCP頭設置好。實際上skb內部包含了網絡協議中所有的頭,在設置TCP頭的時候,只是把指針指向skb合適的位置。后面設置IP頭的時候,再把指針挪動一下即可,避免了頻繁的內存申請和拷貝,提高效率。

tcp_transmit_skb是發送數據位于傳輸層的最后一步,調用了網絡層提供的發送接口icsk->icsk_Af_ops->queue_xmit()之后就可以進入網絡層進行下一層的操作了。

3)網絡層發送處理

在tcp_ipv4中,queue_xmit指向的是ip_queue_xmit,具體實現如下:

int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl){ // 檢查socket中是否有緩存的路由表 rt = (struct rtable*)__sk_dst_check(sk, 0); ...... if(rt == null) { // 沒有緩存則展開查找路由項并緩存到socket中rt = ip_route_output_ports(...); sk_setup_caps(sk, &rt->dst); } // 為skb設置路由表 skb_dst_set_noref(skb, &rt->dst); // 設置IP頭 iph = ip_hdr(skb); ip->protocol = sk->sk_protocol; iph->ttl = ip_select_ttl(inet, &rt->dst); ip->frag_off = ...; ip_copy_addr(iph, f14); ...... // 發送 ip_local_out(skb);}

這個函數主要做的就是找到該把這個包發往哪,并構造好IP包頭。它會去查詢socket中是否有緩存的路由表,如果有則直接構造包頭,如果沒有就去查詢并緩存到sokect,然后為skb設置路由表,最后封裝ip頭,發往ip_local_out函數。

ip_local_out中主要會經過__ip_local_out => nf_hook 的過程進行netfilter的過濾。如果使用iptables配置了一些規則,那么這里將檢測到是否命中規則,然后進行相應的操作,如網絡地址轉換、數據包內容修改、數據包過濾等。如果設置了非常復雜的netfilter規則,則在這個函數會導致進程CPU的開銷大增。經過netfilter處理之后,(忽略其他部分)調用dst_output(skb)函數。

dst_output會去調用skb_dst(skb)->output(skb),即找到skb的路由表(dst條目),然后調用路由表的output方法。這里是個函數指針,指向的是ip_output方法。

在ip_output方法中首先會進行一些簡單的統計工作,隨后再次執行netfilter過濾。過濾通過之后回調ip_finish_output。

在ip_finish_output中,會校驗數據包的長度,如果大于MTU,就會執行分片。MTU的大小是通過MTU發現機制確定,在以太網中為1500字節。分片會帶來兩個問題:

需要進行額外的處理,會有性能開銷只要一個分片丟失,整個包都要重傳

如果不需要分片則調用ip_finish_output2函數,根據下一跳的IP地址查找鄰居項,找不到就創建一個,然后發給下一層——鄰居子系統。

總體過程如下:

ip_queue_xmit

查找并設置路由項設置IP頭

ip_local_out:netfilter過濾

ip_output

統計工作再次netfilter過濾

ip_finish_output

大于MTU的話進行分片調用ip_finish_output24)鄰居子系統

鄰居子系統是位于網絡層和數據鏈路層中間的一個系統,其作用是為網絡層提供一個下層的封裝,讓網絡層不用關心下層的地址信息,讓下層來決定發送到哪個MAC地址。

鄰居子系統不位于協議棧net/ipv4/目錄內,而是位于net/core/neighbour.c,因為無論對于ipv4還是ipv6都需要使用該模塊

在鄰居子系統中主要查找或者創建鄰居項,在創建鄰居項時有可能會發出實際的arp請求。然后封裝MAC頭,將發生過程再傳遞給更下層的網絡設備子系統。

ip_finish_output2的實現邏輯大致流程如下:

rt_nexthop:獲取路由下一跳的IP信息

__ipv4_neigh_lookup_noref:根據下一條IP信息在arp緩存中查找鄰居項

__neigh_create:創建一個鄰居項,并加入鄰居哈希表

dst_neight_output => neighbour->output(實際指向neigh_resolve_output):

封裝MAC頭(可能會先觸發arp請求)調用dev_queue_xmit發送到下層5)網絡設備子系統

鄰居子系統通過dev_queue_xmit進入網絡設備子系統,dev_queue_xmit的工作邏輯如下

選擇發送隊列獲取排隊規則存在隊列則調用__dev_xmit_skb繼續處理

在前面講過,網卡是有多個發送隊列的,所以首先需要選擇一個隊列進行發送。隊列的選擇首先是通過獲取用戶的XPS配置(為隊列綁核),如果沒有配置則調用skb_tx_hash去計算出選擇的隊列。接著會根據與此隊列關聯的qdisc得到該隊列的排隊規則。

最后會根據是否存在隊列(如果是發給回環設備或者隧道設備則沒有隊列)來決定后續數據包流向。對于存在隊列的設備會進入__dev_xmit_skb函數。

在Linux網絡子系統中,qdisc(Queueing Discipline,隊列規則)是一個用于管理網絡包排隊和發送的核心組件。它決定了網絡包在發送隊列中的排列順序,以及何時從隊列中取出包進行發送。qdisc還可以應用于網絡流量控制,包括流量整形(traffic shaping)、流量調度(traffic scheduling)、流量多工(traffic multiplexing)等。

Linux提供了許多預定義的qdisc類型,包括:

pfifo_fast:這是默認的qdisc類型,提供了基本的先入先出(FIFO)隊列行為。mq:多隊列時的默認類型,本身并不進行任何數據包的排隊或調度,而是為網絡設備的每個發送隊列創建和管理一個子 qdisc。tbf (Token Bucket Filter):提供了基本的流量整形功能,可以限制網絡流量的速率。htb (Hierarchical Token Bucket):一個更復雜的流量整形qdisc,可以支持多級隊列和不同的流量類別。sfq (Stochastic Fairness Queueing):提供了公平隊列調度,可以防止某一流量占用過多的帶寬。

每個網絡設備(如eth0、eth1等)都有一個關聯的qdisc,用于管理這個設備的發送隊列。用戶可以通過tc(traffic control)工具來配置和管理qdisc。

對于支持多隊列的網卡,Linux內核為發送和接收隊列分別分配一個qdisc。每個qdisc獨立管理其對應的隊列,包括決定隊列中的數據包發送順序,應用流量控制策略等。這樣,可以實現每個隊列的獨立調度和流量控制,提高整體網絡性能。

我們可以說,對于支持多隊列的網卡,內核中的每個發送隊列都對應一個硬件的發送隊列(也就是 Ring Buffer)。選擇哪個內核發送隊列發送數據包,也就決定了數據包將被放入哪個 Ring Buffer。數據包從 qdisc 的發送隊列出隊后,會被放入 Ring Buffer,然后由硬件發送到網絡線路上。所以,Ring Buffer 在發送路徑上位于發送隊列之后。

將struct sock的發送隊列和網卡的Ring Buffer之間設置一個由qdisc(隊列規則)管理的發送隊列,可以提供更靈活的網絡流量控制和調度策略,以適應不同的網絡環境和需求。

下面是一些具體的原因:

流量整形和控制:qdisc可以實現各種復雜的排隊規則,用于控制數據包的發送順序和時間。這可以用于實現流量整形(比如限制數據的發送速率以避免網絡擁塞)和流量調度(比如按照優先級或服務質量(QoS)要求來調度不同的數據包)。對抗網絡擁塞:qdisc可以通過管理發送隊列,使得在網絡擁塞時可以控制數據的發送,而不是簡單地將所有數據立即發送出去,這可以避免網絡擁塞的加劇。公平性:在多個網絡連接共享同一個網絡設備的情況下,qdisc可以確保每個連接得到公平的網絡帶寬,而不會因為某個連接的數據過多而餓死其他的連接。性能優化:qdisc可以根據網絡設備的特性(例如,對于支持多隊列(Multi-Queue)的網卡)和當前的網絡條件來優化數據包的發送,以提高網絡的吞吐量和性能。

__dev_xmit_skb分為三種情況:

qdisc停用:釋放數據并返回代碼設置為NET_XMIT_DROP

qdisc允許繞過排隊系統&&沒有其他包要發送&&qdisc沒有運行:繞過排隊系統,調用sch_direct_xmit發送數據

其他情況:正常排隊

調用q->enqueue入隊調用__qdisc_run開始發送void __qdisc_run(struct Qdisc *q){ int quota = weight_p; // 循環從隊列取出一個skb并發送 while(qdisc_restart(q)) {// 如果quota耗盡或其他進程需要CPU則延后處理if(--quota <= 0 || need_resched) { // 將觸發一次NET_TX_SOFTIRQ類型的softirq __netif_shcedule(q); break;} }}

從上述代碼中可以看到,while循環不斷地從隊列中取出skb并進行發送,這個時候其實占用的都是用戶進程系統態時間sy,只有當quota用盡或者其他進程需要CPU的時候才觸發軟中斷進行發送。

這就是為什么服務器上查看/proc/softirqs,一般NET_RX要比NET_TX大得多的原因。對于接收來說,都要經過NET_RX軟中斷,而對于發送來說,只有系統配額用盡才讓軟中斷上。

這里我們聚焦于qdisc_restart函數上,這個函數用于從qdisc隊列中取包并發給網絡驅動

static inline int qdisc_restart(struct Qdisc *q){ struct sk_buff *skb = dequeue_skb(q); if (!skb)return 0; ...... return sch_direct_xmit(skb, q, dev, txq, root_lock);}

首先調用 dequeue_skb() 從 qdisc 中取出要發送的 skb。如果隊列為空,返回 0, 這將導致上層的 qdisc_restart() 返回 false,繼而退出 while 循環。

如果拿到了skb則調用sch_direct_xmit繼續發送,該函數會調用dev_hard_start_xmit,進入驅動程序發包,如果無法發送則重新入隊。

即整個__qdisc_run的整體邏輯為:while 循環調用 qdisc_restart(),后者取出一個 skb,然后嘗試通過 sch_direct_xmit() 來發送;sch_direct_xmit 調用 dev_hard_start_xmit 來向驅動程序進行實際發送。任何無法發送的 skb 都重新入隊,將在 NET_TX softirq 中進行發送。

6)軟中斷調度

上一部分中如果發送網絡包的時候CPU耗盡了,會調用進入__netif_schedule,該函數會進入__netif_reschedule,將發送隊列設置到softnet_data上,并最終發出一個NET_TX_SOFTIRQ類型的軟中斷。軟中斷是由內核進程運行的,該進程會進入net_tx_action函數,在該函數中能獲得發送隊列,并最終也調用到驅動程序的入口函數dev_hard_start_xmit。

從觸發軟中斷開始以后發送數據消耗的CPU就都顯示在si中,而不會消耗用戶進程的系統時間

static void net_tx_action(struct softirq_action *h){ struct softnet_data *sd = &__get_cpu_var(softnet_data); // 如果softnet_data設置了發送隊列 if(sd->output_queue) { // 將head指向第一個qdisc head = sd->output_queue;// 遍歷所有發送隊列 while(head) { struct Qdisc *q = head; head = head->next_sched; // 處理數據 qdisc_run(q);} }}static inline void qdisc_run(struct Qdisc *q){ if(qdisc_run_begin(q)) __qdisc_run(q);}

可以看到軟中斷的處理中,最后和前面一樣都是調用了__qdisc_run。也就是說不管是在qdisc_restart中直接處理,還是軟中斷來處理,最終實際都會來到dev_hard_start_xmit(__qdisc_run => qdisc_restart => dev_hard_start_xmit)。

7)igb網卡驅動發送

通過前面的介紹可知,無論對于用戶進程的內核態,還是對于軟中斷上下文,都會調用網絡設備子系統的dev_hard_start_xmit函數,在這個函數中,會調用驅動里的發送函數igb_xmit_frame。在驅動函數里,會將skb掛到RingBuffer上,驅動調用完畢,數據包真正從網卡發送出去。

int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq){ // 獲取設備的回調函數ops const struct net_device_ops * ops = dev->netdev_ops; // 獲取設備支持的功能列表 features = netif_skb_features(skb); // 調用驅動的ops里的發送回調函數ndo_start_xmit將數據包傳給網卡設備 skb_len = skb->len; rc = ops->ndo_start_xmit(skb, dev);}

這里ndo_start_xmit是網卡驅動要實現的函數,igb網卡驅動中的實現是igb_xmit_frame(在網卡驅動程序初始化的時候賦值的)。igb_xmit_frame主要會去調用igb_xmit_frame_ring函數

netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb, struct igb_ring *tx_ring){ // 獲取TX queue中下一個可用緩沖區的信息 first = &tx_ring->tx_buffer_info[tx_ring->next_to_use]; first->skb = skb; first->bytecount = skb->len; first->gso_segs = 1; // 準備給設備發送的數據 igb_tx_map(tx_ring, first, hdr_len);}static void igb_tx_map(struct igb_ring *tx_ring, struct igb_tx_buffer *first, const u8 hdr_len){ // 獲取下一個可用的描述符指針 tx_desc = IGB_TX_DESC(tx_ring, i); // 為skb->data構造內存映射,以允許設備通過DMA從RAM中讀取數據 dma = dma_map_single(tx_ring->dev, skb->data, size, DMA_TO_DEVICE); // 遍歷該數據包的所有分片,為skb的每個分片生成有效映射 for(frag = &skb_shinfo(skb)->frags[0]; ; flag++){tx_desc->read.buffer_addr = cpu_to_le64(dma); tx_desc->read.cmd_type_len = ...; tx_desc->read.olinfo_status = 0; } // 設置最后一個descriptor cmd_type |= size | IGB_TXD_DCMD; tx_desc->read.cmd_type_len = cpu_to_le32(cmd_type);}

在這里從網卡的發送隊列的RingBuffer上取下來一個元素,并將skb掛到元素上。然后使用igb_tx_map函數將skb數據映射到網卡可訪問的內存DMA區域。

這里可以理解為&tx_ring->tx_buffer_info[tx_ring->next_to_use]拿到了RingBuffer發送隊列中指針數組(前文提到的igb_tx_buffer,網卡啟動的時候創建的供內核使用的數組)的下一個可用的元素,然后為其填充skb、byte_count等數據。

填充完成之后,獲取描述符數組(前文提到的e1000_adv_tx_desc,網卡啟動的時候創建的供網卡使用的數組)的下一個可用元素。

調用dma_map_single函數創建內存和設備之間的DMA映射,tx_ring->dev是設備的硬件描述符,即網卡,skb->data是要映射的地址,size是映射的數據的大小,即數據包的大小,DMA_TO_DEVICE是指映射的方向,這里是數據將從內存傳輸到設備,返回的調用結果是一個DMA地址,存儲在dma變量中,設備可以直接通過這個地址訪問到skb的數據。

最后就是為前面拿到的描述符填充信息,將dma賦值給buffer_addr,網卡使用的時候就是從這里拿到數據包的地址。

當所有需要的描述符都建好,且skb的所有數據都映射到DMA地址后,驅動就會進入到它的最后一步,觸發真實的發送。

到目前為止我們可以這么理解:

應用程序將數據發送到 socket,這些數據會被放入與 sock 中的發送隊列。然后,網絡協議棧(例如 TCP 或 UDP)將這些數據從 socket 的發送隊列中取出,往下層封裝,然后將這些數據包放入由 qdisc 管理的設備發送隊列中。最后,這些數據包將從設備發送隊列出隊,放置到RingBuffer的指針數組中,通過dma將數據包的地址映射到可供網卡訪問的內存DMA區域,由硬件讀取后發送到網絡上。

五、RingBuffer內存回收

當數據發送完以后,其實工作并沒有結束,因為內存還沒有清理。當發送完成的時候,網卡設備會觸發一個硬中斷(硬中斷會去觸發軟中斷)來釋放內存。

這里需要注意的就是,雖然是數據發送完成通知,但是硬中斷觸發的軟中斷是NET_RX_SOFTIRQ,這也就是為什么軟中斷統計中RX要高于TX的另一個原因。

硬中斷中會向softnet_data添加poll_list,軟中斷中輪詢后調用其poll回調函數,具體實現是igb_poll,其會在q_vector->tx.ring存在時去調用igb_clean_tx_irq。

static bool igb_clean_tx_irq(struct igb_q_vector *q_vector){ // 釋放skb dev_kfree_skb_any(tx_buffer->skb); // 清除tx_buffer數據 tx_buffer->skb = NULL; // 將tx_buffer指定的DMA緩沖區的長度設置為0 dma_unmap_len_set(tx_buffer, len 0); // 清除最后的DMA位置,解除映射 while(tx_desc != eop_desc) { }}

其實邏輯無非就是清理了skb(其中data保存的數據包沒有釋放),解決了DMA映射等,到了這一步傳輸才算基本完成。

當然因為傳輸層需要保證可靠性,所以數據包還沒有刪除,此時還有前面的拷貝過的skb指向它,它得等到收到對方的ACK之后才會真正刪除。

六、問題解答

查看內核發送數據消耗的CPU時應該看sy還是si

在網絡包發送過程中,用戶進程(在內核態)完成了絕大部分的工作,甚至連調用驅動的工作都干了。只有當內核態進程被切走前才會發起軟中斷。發送過程中百分之九十以上的開銷都是在用戶進程內核態消耗掉的,只有一少部分情況才會觸發軟中斷,有軟中斷ksoftirqd內核線程來發送。所以在監控網絡IO對服務器造成的CPU開銷的時候,不能近看si,而是應該把si、sy(內核占用CPU時間比例)都考慮進來。

在服務器上查看/proc/softirqs,為什么NET_RX要比NET_TX大得多

對于讀來說,都是要經過NET_RX軟中斷的,都走ksoftirqd內核線程。而對于發送來說,絕大部份工作都是在用戶進程內核態處理了,只有系統態配額用盡才會發出NET_TX,讓軟中斷處理。當數據發送完以后,通過硬中斷的方式來通知驅動發送完畢。但是硬中斷無論是有數據接收還是發送完畢,觸發的軟中斷都是NET_RX_SOFTIRQ而不是NET_TX_SOFTIRQ。

發送網絡數據的時候都涉及那些內存拷貝操作

這里只指內存拷貝內核申請完skb之后,將用戶傳遞進來的buffer里的數據拷貝到skb。如果數據量大,這個拷貝操作還是開銷不小的。從傳輸層進入網絡層時。每個skb都會被克隆出一個新的副本,目的是保存原始的skb,當網絡對方沒有發揮ACK的時候還可以重新發送,易實現TCP中要求的可靠傳輸。不過這次只是淺拷貝,只拷貝skb描述符本身,所指向的數據還是復用的。第三次拷貝不是必須的,只有當IP層發現skb大于MTU時才需要進行,此時會再申請額外的skb,并將原來的skb拷貝成多個小的skb。

零拷貝到底是怎么回事

如果想把本機的一個文件通過網絡發送出去,需要先調用read將文件讀到內存,之后再調用send將文件發送出去假設數據之前沒有讀去過,那么read系統調用需要兩次拷貝才能到用戶進程的內存。第一次是從硬盤DMA到Page Cache。第二次是從Page Cache拷貝到內存。send系統調用也同理,先CPU拷貝到socket發送隊列,之后網卡進行DMA拷貝。如果要發送的數據量較大,那么就需要花費不少的時間在數據拷貝上。而sendfile就是內核提供的一個可用來減少發送文件時拷貝開銷的一個技術方案。在sendfile系統調用里,數據不需要拷貝到用戶空間,在內核態就能完成發送處理,減少了拷貝的次數。

為什么Kafka的網絡性能很突出

Kafka高性能的原因有很多,其中重要的原因之一就是采用了sendfile系統調用來發送網絡數據包,減少了內核態和用戶態之間的頻繁數據拷貝。

以上就是深入理解Linux網絡之內核是如何發送網絡包的的詳細內容,更多關于Linux 內核發送網絡包的資料請關注好吧啦網其它相關文章!

標簽: Linux
主站蜘蛛池模板: 亚洲欧美另类久久久精品 | 18成禁人视频免费 | 国产精品女同 | 亚洲一区二区三区四区五区乱码 | 免费成人视屏 | 越南a级片 | av中出 | 韩国主播青草55部完整 | 91久久久久久亚洲精品禁果 | 色偷偷导航 | 噜噜噜视频 | 大陆熟妇丰满多毛xxxx | 一级片毛片| 网友自拍区视频精品 | 欧美福利视频一区二区 | 欧洲亚洲激情 | 一个色的综合 | 中文娱乐综合网777 中文在线第一页 | 国产白嫩护士被弄高潮 | 日韩a在线 | 国产精品色片 | 国产一级淫片免费放大片 | 日韩综合色 | 97婷婷狠狠成为人免费视频 | 一本到加勒比系列在线 | 全部免费的毛片在线播放 | 日本黄色不卡视频 | 久久久激情视频 | 国产免费不卡 | 色久在线| xnxnxnxnxn18美女| 久久精品成人免费观看 | 久久99日韩国产精品久久99 | 亚洲视频一区二区在线 | 激情内射亚洲一区二区三区爱妻 | 久久网站视频 | 成人国内精品久久久久影院vr | 92看片淫黄大片看国产片图片 | 青青草娱乐在线 | 国产成人精品一区二区色戒 | 91麻豆精产国品一二三产区区 | 午夜影院视频 | 国内精品久久久久久久日韩 | 国产美女在线观看免费 | 九九精品免费视频 | 久久亚洲欧美国产精品 | 久久人人爽人人爽人人av东京热 | 国产精品丝袜在线 | 四虎影院在线 | 波多野结衣视频免费看 | 97精品久久久 | 午夜三级av | 免费一级特黄特色的毛片 | 就要爱爱tv| 午夜无码大尺度福利视频 | 成人网页在线观看 | 婷婷开心激情综合五月天 | www视频在线观看网站 | 男女做爰猛烈叫床爽爽免费网站 | 2020久久香蕉国产线看观看 | 国产精品网站在线观看免费传媒 | 国产成人三级 | 一区二区三区久久 | 明日叶三叶 | 91香蕉视频在线 | 日本高清视频在线播放 | 国产精品欧美亚洲韩国日本久久 | 亚洲欧美日韩精品色xxx | 精品女同一区二区三区在线播放 | 欧美日韩一区二区三区在线 | 麻豆网站免费观看 | 农村少妇一区二区三区四区五区 | 亚洲成a人片在线观看天堂无码 | 国产欧美精品在线 | 日本精品一区二区三区在线观看 | 国产不卡视频一区二区三区 | 欧美大胸大乳人奶波霸 | 亚洲国产日韩在线 | 欧美性猛交xx | 国产清纯白嫩美女正无套播放 | 中文字幕不卡二区 | 噜噜噜在线观看免费视频日本 | 日本不卡在线 | 国产精品理论在线观看 | 国产精品成人片在线观看 | 麻豆精品国产精华精华液好用吗 | 国产精品久久久天天影视 | 成年女人18级毛片毛片免费 | 国产三级精品三级在专区 | 欧美一区免费观看 | 天堂中文最新版在线官网在线 | 亚洲男人的天堂在线播放 | 国产99在线 | 欧美 | 日韩天堂在线 | 天天弄天天操 | 亚洲精品久久久久 | 一本色道久久综合亚洲精品酒店 | 日本另类αv欧美另类aⅴ | 亚洲人成无码网站18禁10 | 久久久亚洲欧洲日产国码αv | 国产特级毛片aaaaaa毛片 | 天堂中文官网在线 | 午夜偷拍福利 | h在线网站 | 女人下边被添全过视频的网址 | 欧美乱妇高清无乱码在线观看 | 熟女俱乐部五十路六十路 | www久久爱白液流出h | 四虎影视网 | 国产美女极度色诱视频www | 日韩第2页| 国四虎影2020 | 亚洲人做受 | 377p日本欧洲亚洲大胆张筱雨 | 亚洲老女人av | 久久久99日产 | 国产精品国产三级国产普通话蜜臀 | 久久99热这里只有精品 | 日本国产视频 | 久久午夜场 | 国产一二视频 | 久久久综合 | 成人在线高清视频 | 四虎4545www国产精品 | 成人性生交天码免费看 | 亚洲自拍在线观看 | 国产在线一卡二卡 | 情五月| 熟女俱乐部五十路六十路av | 成品片a免人视频 | 亚洲18禁私人影院 | 国产无遮挡又黄又爽免费软件 | 国产欧美熟妇另类久久久 | www人人草| 一级一级一级毛片 | 在线v | 99久久精品午夜一区二区 | 亚洲国产精品肉丝袜久久 | 高h猛烈做哭你尿进去了网站 | 日本福利视频一区 | 午夜精品久久久久久久久久久久 | 蜜桃视频韩日免费播放 | 538在线精品 | 中文字幕无码不卡免费视频 | 中文字幕乱码无码人妻系列蜜桃 | 性视频网址 | 国产女主播在线 | 日本黄色片网址 | 中文天堂在线观看 | 北条麻妃99精品青青久久 | 黄色av网站在线看 | 久久精品亚洲精品国产欧美kt∨ | 欧美老肥熟 | 国产jizz视频全部免费软件 | 日本免费黄色小视频 | 一级黄色大片在线观看 | 饥渴的熟妇张开腿呻吟视频 | 日本在线 | 中文 | 免费人成视频x8x8 | 亚欧在线观看视频 | 国产igao为爱做激情在线 | 午夜免费激情视频 | 欧美日本韩国亚洲 | 欧美最猛黑人xxxxx猛交 | 国产精品少妇 | 国产专区av | 亚洲熟女乱色一区二区三区 | 妩媚尤物娇喘无力呻吟在线视频 | 亚洲乱码国产乱码精品精乡村 | 国产动漫av | 台湾女老板性三级 | 欧美级毛片 | 91第一页| 国产剧情演绎av | 成人性生交大片免费看96 | 久久综合成人 | 中文区中文字幕免费看 | 一本无码人妻在中文字幕免费 | 强开小嫩苞一区二区三区网站 | 青草视频免费在线观看 | 国产小视频在线播放 | 性a视频| 777久久久精品一区二区三区 | 五月天婷婷综合网 | 性户外野战hd | 国产福利精品视频 | 国产精品美女久久久久久久久 | 亚洲成aⅴ人在线观看 | 性色欲情网站iwww九文堂 | 日韩av线观看| 在线国产视频一区 | 国产69精品久久久久777 | 亚洲综合av一区二区三区 | 精品久久久噜噜噜久久久 | 色视频在线观看视频 | 成人免费视频网址 | 天堂精品久久 | 三个熟睡少妇的按摩中文字幕 | 欧美成人免费全部 | www视频免费在线观看 | 91福利在线播放 | 午夜影院操 | 国产精品久久久久久爽爽爽 | 国产成人精品一二三区 | 亚洲欧美国产精品久久 | 波多野结衣黄色 | 欧美黑人极品猛少妇色xxxxx | 久久久久久亚洲精品杨幂圣光 | 国产精品女同一区二区软件 | 亚洲v在线 | 在线免费观看小视频 | 少妇小芸h系列小说 | 麻豆av毛片| 男人添女人下部高潮全视频 | 中文字幕久久熟女蜜桃 | 天天摸天天舔 | 婷婷色婷婷 | 人妻无码久久精品人妻 | 亚洲国产精品综合久久网各 | 少妇挑战三个黑人惨叫4p国语 | av青青草原| 猫咪www免费人成人入口 | 欧洲乱码伦视频免费 | 夜夜爱夜夜做夜夜爽 | 波多野结衣视频网站 | 欧美日韩中文在线观看 | 国产偷亚洲偷欧美偷精品 | 国产精品久久久久久无人区 | 无码专区人妻系列日韩精品少妇 | 少妇做爰α片免费视频网站 | 国产人妖ts重口系列网站观看 | 欧美精品日韩在线 | 好爽好大久久久级淫片毛片小说 | 欧美色视频在线 | 国产成人免费观看视频 | 性做久久久久久 | 波多野吉衣av无码 | 亚洲精品久久 | 三级三级18女男 | 91视频免费看 | 免费网站av| 狠狠狠色丁香婷婷综合久久88 | 亚洲狼人天堂 | 久久精品一区视频 | 欧美日韩精品在线视频 | 日韩国产精品一区二区三区 | 精品国产黑色丝袜高跟鞋 | 亚洲精品一区二区冲田杏梨 | 成人无码视频免费播放 | 狠狠色综合欧美激情 | 国产精品高潮呻吟av久久 | 久久人人爱 | 亚洲欧美日韩高清 | 久91| 麻豆久久久9性大片 | 久久综合给合久久狠狠狠97色 | 国产精品国产三级国产a | 亚洲精品丝袜久久久久久 | 色吧久久 | 人妻精品久久久久中文字幕69 | 日韩精品一区二区中文字幕 | 欧美激情一区二区三级高清视频 | 欧美少妇b | 国产精品永久久久久 | jizz性欧美23 | 俄罗斯丰满熟妇hd | 午夜伦视频 | 在线观看的网站 | www.欧美日韩| 波多野结衣中文字幕一区二区三区 | 热久久中文 | 亚洲春色av无码专区在线播放 | 日本伦理一区二区三区 | 81国产精品久久久久久久久久 | 欧美片网站免费 | 一级片免费视频 | 中文字幕免费 | 国产又粗又大又长 | 裸体户外露出调教play | 国产精品久久久久久亚洲伦 | 拔插拔插海外华人永久免费 | 在线日韩精品视频 | 国产md视频一区二区三区 | 丁香五月网久久综合 | 中文字幕在线观看一区二区三区 | 国产在线视频www色 日韩精品av一区二区三区 | 少妇特黄a一区二区三区 | 日本午夜影院 | 一区二区在线观看免费 | 久久久久成人精品 | 亚洲va无码va在线va天堂 | 99热只有精| 亚洲精品国产a久久久久久 51国偷自产一区二区三区 | 免费国产在线观看 | 色哟色哟色精品 | 午夜资源站 | 欧美乱大交xxxxx潮喷l头像 | 怡红院av一区二区三区 | 男人的天堂日韩 | 深夜免费在线视频 | 91看片一区二区三区 | 婷婷四房综合激情五月 | 国产综合在线观看视频 | 最新黄色av网址 | jizz越南zz女人18| 成人在线免费网站 | 色呦呦免费观看 | 成人欧美一区二区三区动漫 | av永久免费在线观看 | 在线一区二区三区 | 亚洲自拍第三页 | 欧美日本韩国亚洲 | 亚洲综合视频网 | 播播网色播播 | 久草香蕉视频 | 欧美综合视频在线观看 | 亚洲熟妇自偷自拍另类 | 成年人免费看毛片 | 国产乱人乱精一区二视频 | 免费日本特黄 | 日本大人吃奶视频xxxx | 亚洲一区二区乱码 | 国产一区二区av在线 | 蜜臀av夜夜澡人人爽人人 | 久久99婷婷国产精品免费 | 一区二区三区日本久久九 | 国产福利小视频在线观看 | 美女航空毛片在线播放 | 中文字幕伊人 | 国产一级视频在线播放 | 无码伊人久久大杳蕉中文无码 | 天堂网ww | yy77777丰满少妇影院 | 亚洲精品一区久久久久久 | 国内激情 | 婷婷成人亚洲综合国产xv88 | 18性夜影院午夜寂寞影院免费 | 国产免费毛卡片 | 毛片你懂的 | 久热免费在线视频 | 国产精品无码久久久久久 | 国产两女互慰高潮视频在线观看 | 啪在线视频 | 男人天堂新地址 | 91成人看片免费版 | 亚洲精品av天天看1080p | 国产品无码一区二区三区在线 | 天天操夜夜操视频 | 与黑人做爰的日本人 | 老头与老头性ⅹxx视频 | 国产毛a片啊久久久久久保和丸 | 把腿张开老子臊烂你多p视频 | 男人综合网 | 中文字幕日产无线码一区 | 亚洲免费av一区 | 长春chinese少妇 | 九九综合久久 | youjizzcom欧美 | 色偷偷免费视频 | 勾搭情趣店女老板av | 樱桃成人精品视频在线播放 | 韩国bj大尺度vip福利网站 | 狠狠躁18三区二区一区张津瑜 | 任我撸在线视频 | 成人午夜视频在线 | 日韩在线观看一区二区 | 国产成人av在线播放 | 亚洲欧美视频在线 | 国产片网址 | 欧美一级性生活视频 | 成年人在线免费观看 | 免费av一区 | 99国产超薄丝袜足j在线播放 | 黑人做爰xxxⅹ性少妇69 | 丁香六月色 | 无码av天堂一区二区三区 | 在线观看午夜福利院视频 | 国内精品久久久久影院一蜜桃 | 邻居少妇张开腿让我爽了在线观看 | 欧美顶级metart裸体全部自慰 | 特级西西444ww大胆视频 | 亚洲精品国偷拍自产在线观看蜜臀 | 欧美xxxx888| 国产中文区4幕区2022 | 少妇影院yy111111 | 99热日韩| 成人免费高清 | 国产乱子伦精品视频 | 日日橹狠狠爱欧美二区免费视频 | 99爱视频在线观看 | 永久免费未满视频 | 少妇大叫太大太粗太爽了 | 香蕉依人 | 国产中文字幕在线视频 | 九色伊人| yjizz视频| 国产日本在线播放 | 免费爱爱视频 | 能免费看av的网站 | 久久精品国产亚洲5555 | 亚洲精品乱码久久久久久蜜桃不卡 | 教师夫妇交换刺激做爰小说 | 日韩精品一卡2卡3卡4卡乱码的功能 | 中韩乱幕日产无线码一区 | 国产ts人妖系列张思妮在线观看 | 免费黄色国产 | 亚洲精品一区二区三区丝袜 | 久久久久高潮毛片免费全部播放 | 欧美日韩色图片 | 国产精品久久 | 日本免费高清视频 | 无码专区aaaaaa免费视频 | 日本亚洲网站 | 精品动漫卡一卡2卡三卡四卡 | 对白刺激国语子与伦 | 日本久久黄色 | 国产啊v在线观看 | 国产第三页 | 日韩视频在线一区二区 | 中文字幕亚洲国产 | 久久综合九色综合欧美狠狠 | 久久精品一区二区三区av | 日本中文字幕在线免费观看 | 国产区免费 | 久久无吗视频 | 青青草97国产精品免费观看 | 夫の目の前侵犯中文字 | 久久久久久国产精品三区 | 777亚洲熟妇自拍无码区 | 成人av男人的天堂 | 国产精品a成v人在线播放 | 成熟了的熟妇毛茸茸 | 日韩av无码一区二区三区不卡 | 日一本二本三本在线2021 | 国产浮力第一页草草影院 | 日日日人人人 | 99久久免费视频在线观看 | 国产伦精品一区二区三区免费迷 | 午夜精品久久久久久久喷水 | 中文字幕大香视频蕉免费 | 91社区在线观看高清 | 四十如虎的丰满熟妇啪啪 | 精品www久久久久久奶水 | av午夜在线 | 美女裸奶100%无遮挡免费网站 | 开心黄色网| 亚洲精品国产综合久久久久紧 | 顶级少妇做爰视频在线观看 | 中文字幕日韩亚洲 | 天天色天天色天天色 | 免费va人成视频网站全 | 9l蝌蚪porny中文自拍 | 国产精品女主播一区二区三区 | 久久中文字幕视频 | 亚洲综合色在线 | 久久久久久国产精品免费播放 | 伊人精品久久久大香线蕉 | 永久免费看成品人影视 | 欧美性猛片xxxxx免费中国 | 中文字幕一区二区三区不卡 | 日韩久久久久久久久 | 一级毛片基地 | 国产在线精品成人免费怡红院 | 午夜涩涩 | 免费a在线观看 | 人人超人人超碰超国产97超碰 | 国产91丝袜在线播放 | 国产成人主播 | 亚洲大色| 久久精品免费国产 | 麻豆91精品 | 日韩在线国产 | 国产另类重口一 | 国产自产在线视频一区 | 日本不卡123 | 国产情侣在线播放 | 影音先锋激情 | 51区成人一码二码三码是什么 | 国产97色在线 | 国产 | 福利一区三区 | 中文字幕高清在线观看 | 777精品视频 | 亚洲第十页 | 日韩欧美在线观看 | 浪潮av网站 | 四川骚妇无套内射舔了更爽 | 国产精品专区在线 | 亚洲精品久久久久午夜福禁果tⅴ | 精品久久久久久无码中文野结衣 | 豆花av在线 | 97久久精品人人做人人爽 | 热re99久久精品国产99热 | 精品国产大片大片大片 | 在线毛片网站 | 国产69久久久欧美一级 | 99久久综合精品五月天 | 富婆找两个黑人3p在线视频 | 狠狠色丁香婷婷综合尤物 | 一区二区亚洲精品国产精华液 | 久久精品久久久久久噜噜老黄 | 国产日产欧美 | 四虎库| 成人性做爰av片免费看 | 亚洲在线| 日本 在线 | 欧美肥臀大乳一区二区免费视频 | 五月天精品一区二区三区 | 久久久久99精品 | 艹逼国产 | 国产成人精品一区二区仙踪林 | 伊人网视频在线 | 精品人妻大屁股白浆无码 | 天天舔天天操天天干 | 亚洲 自拍 另类 欧美 丝袜 | 勾搭足浴女技师国产在线 | 午夜精品一区二区三区免费视频 | 人妻体内射精一区二区三四 | 国产色播| 四虎国产精品永久在线 | 中国少妇内射xxxhd免费 | 欧美精品影院 | 在线观看亚洲网站 | 五月婷婷六月丁香综合 | 人妻中出无码中字在线 | 亚洲春色www| 久久澡| 天堂av中文在线 | 日本午夜精华 | 久热这里只有精品视频6 | 日韩avcom| 双乳奶水饱满少妇呻吟 | 亚洲女同在线观看 | 美女上床网站 | 天天夜夜骑| 无码人妻丰满熟妇啪啪网站 | 久久99热狠狠色精品一区 | 91精品国产中文字幕 | 最新av片| 丰满少妇一级 | 中文字幕精品亚洲 | 乳女教师の诱惑julia | 一区二区三区内射美女毛片 | 永久看看免费大片 | 艹逼国产| 精品久久久久久成人av | 好吊色网站 | 国产乱码精品一区二区三区爽爽爽 | 夜夜操夜夜爱 | 亚洲综合资源 | 国内精品久久久久久久久 | 久草资源在线 | 韩国乱码片免费看 | 一个人看的www视频在线播放 | 欧美黑人大战白嫩在线 | 天天做天天爱 | 国产激情久久久久 | 国产三级视频在线 | 欧美久草| 国产a视频精品免费观看 | 蜜臀av无码人妻精品 | 色偷偷一区二区无码视频 | 国产成人精品一区二三区 | 欧美精品国产动漫 | 欧美精品亚洲精品日韩传电影 | 国产精品久久久网站 | 91快射 | 日本美女日b视频 | 国产不卡视频在线 | 2019天天干夜夜操 | 国产精品主播在线 | 污污内射在线观看一区二区少妇 | 欧美两根一起进3p做受视频 | 亚洲国产精品18久久久久久 | 青青伊人精品 | 情欲按摩院同性3 | 2019天天操 | 无码国内精品人妻少妇蜜桃视频 | 性色av无码一区二区三区人妻 | 黄网站在线观看视频 | 成人在线观看免费高清 | 日韩avcom| 久操视频免费看 | 久久久久人妻精品区一 | 国产成人免费在线观看 | 中文在线а天堂中文在线新版 | 中文字幕日本人妻久久久免费 | 最新无码a∨在线观看 | 在线亚洲免费 | 久久视频这里只有精品 | 区二三区四区精华日产一线二线三 | 91视频网页 | 淫综合网 | 91久久精品日日躁夜夜欧美 | 一区精品在线观看 | 日韩av网站在线观看 | 九色自拍视频 | 熟女人妻少妇精品视频 | 日韩av激情在线观看 | 波多野结衣一本一道 | 久久婷婷婷 | 一区二区三区四区中文字幕 | 欧美一乱一交一性ed2k | 国产精品com | 乳霸冲田杏梨中文字幕担心学生的 | 亚洲日韩成人无码 | 男人靠女人免费视频网站 | 亚洲成人在线视频播放 | 美国成人免费视频 | 情侣呻吟对白精品av | 中文字幕无码人妻少妇免费 | 色一情一乱一伦一视频免费看 | jizz黄| 中文字幕综合 | 美女午夜激情 | aaa黄色|