뜸부기와 공작새

[Linux] 패킷 Flow 분석 - 송신 본문

Linux

[Linux] 패킷 Flow 분석 - 송신

성씨 2020. 3. 8. 16:55

리눅스 패킷 Flow 분석 송신

 

[L7 Layer]

send(), write() 함수와 같은 API를 이용하여 패킷의 정보들을 Kernel로 전달한다

해당 함수들을 호출하면 시스템 콜이 발생하여 sock_sendmsg() 함수를 호출한다

 

[L4 Layer]

시스템 콜 수행되어 sock_sendmsg() 함수에 전송할 패킷에 대한 정보가 전달된다

그다음 사용자 패킷에 mapping되는 버퍼를 읽을 수 있는지 확인하고

L7 Application에서 사용할 소켓 디스크립터를 이용해서 socket 구조체를 얻어오고
sock_sendmsg_nosec() 함수를 호출한다

 

sock_sendmsg_nosec() 함수는

얻어온 socket 구조체에 해당하는 프로토콜별 처리 함수를 호출한다

프로토콜의 명령과 설정을 담당하는 proto_ops 구조체의 sendmsg 필드에서 프로토콜을 확인하여

프로토콜에 맞는 함수를 호출하는데

TCP인 경우에는 tcp_sendmsg UDP인 경우에는 udp_sendmsg함수가 호출된다.

 

여기서는 TCP 패킷이라 가정하고 tcp_sendmsg()함수를 호출한다

 

 

sock->ops->sendmsg (tcp_sendmsg()) 함수는 아래의 동작을 수행

  • socket에서 tcp control block을 가져온다 (tcp_sock)
  • L7 Application이 전송 요청한 데이터를 send socket buffer(sk_buff)로 복사한다 (tcp_send_mss())
  • 새로운 sk_buff 생성 (sk_sream_alloc_skb())
  • send_socket_buffer 리스트에 새로 생성한 sk_buff를 추가 (sk_entail())
  • 지금 전송할 수 있는 데이터를 패킷으로 만들고 전송 (tcp_push())
  • TCP 헤더 생성 + L3 Layer로 보낼 실제 패킷을 생성 (__tcp_push_pending_frames() -> tcp_write_xmit())
  • __tcp_push_pending_frames() -> tcp_write_xmit() -> tcp_transmit_skb() -> queue_xmit()
    (ip_queue_xmit() 콜백함수) 순서로 함수를 호출
    • L3 Layer로 패킷 정보를 전달한다.

 

ip_queue_xmit() 함수는

  • IP헤더 장착, IP헤더 필드 기록(skb_push())
  • ip_local_out() 함수 호출하여 Network Layer에서 수행해야 할 작업들을 수행해준다

 

[L3 Layer]

ip_local_out() 함수는

  • IP헤더 checksum을 계산하고, netfilter 함수 호출
    (ip_local_out() -> __ip_local_out() -> ip_send_check())
  • IP fragment 필요한 경우 fragment 만들어준다.
    (ip_local_out() -> dst_output() -> ip_finish_output() -> ip_fragment())
  • L2 헤더 추가하여 패킷 완성
    (ip_local_out() -> dst_output() -> ip_finish_output() -> ip_finish_output2())
    패킷 전송을 완료하면 dev_queue_xmit() 함수를 호출한다

 

[L2 Layer]

 

dev_queue_xmit() 함수는

  • 만들어진 패킷을 실제로 L2 드라이버로 내려준다
    (__dev_xmit_skb() -> sch_direct_xmit() -> dev_hard_start_xmit() -> xmit_one())
    • NET_TX_SOFTIRQ 실행하여 해당 softirq의 핸들러인 net_tx_action() 함수 호출

net_tx_action() 함수는 아래와 같은 동작을 수행한다

  • 디바이스에서 전송해야 할 패킷을 가지고 있는지 확인 (qdisc_run())
  • 디바이스의 상태 확인 (queue_disc() -> netif_queue_stopped())
    • 디바이스가 활성화되어있다면 qdisc_restart() 호출하여 패킷 전송 시도한다
      (디바이스 락 획득하고 dev->hard_start_xmit() 함수 호출하여 진짜로 패킷을 전송한다)
      (dev->hard_start_xmit() 함수의 내부 내용은 디바이스마다 다르게 구현되어있다)

 

 

'Linux' 카테고리의 다른 글

[Linux] 패킷 Flow 분석 - 수신  (0) 2020.03.08