
IP layer에서는 기본적으로 send, recv한 패킷들에 대해서 IP에 대한 operation을 처리한다. 또한, 내부적으로 패킷을 만들어낼 수도 있다. ex) multicast packets, fragmentation, ICMP/IGMP packets
이전에 TCP TX routine을 통해 layer 별 핵심 작동 함수들을 살펴봤다. (TCP TX routines참고)
대략적인 함수 흐름을 보면 다음과 같다.
sys_write() -> vfs_write() -> sock_write_iter() -> sock_sendmsg() -> inet_sendmsg() (여기까지 Socket Layer) ->
tcp_sendmsg() -> tcp_write_xmit() -> tcp_trasmit_skb() (여기까지 TCP layer) -> ip_queue_xmit() -> ip_local_out() -> ip_output() -> ip_finish_output() -> ip_finish_output2() (여기까지 IP layer)-> dev_queue_xmit()(여기까지 data link layer)

*강의 ppt 재구성
이 함수 chain에서 ip_queue_xmit() ~ ip_finish_output2()까지를 각각 살펴볼 것이다.
ip_queue_xmit()이 함수는 L4에서 생성된 sk_buff에 대해 두가지 역할을 수행한다.
sk_buff에 IP header이 들어갈 공간을 생성후 version, length, Tos, TTL, address, protocol등을 초기화한다.ip_local_out()이 함수의 역할은 크게 3가지이다.
ip_local_deliver()호출ip_output()호출NF_INET_LOCAL_OUTPUT)을 호출NF_INET_LOCAL_OUTPUT 호출ip_output()이 함수에 왔다는 것은, 이 패킷이 컴퓨터 밖으로 나갈 예정이라는 말이다.
크게 두 가지 역할을 수행한다.
sk_buff의 메타데이터 업데이트
어떤 장비(device)로 나가야 하는 지(e.g. eht0)에 대한 정보를 skb에 채워넣는다.(skb->dev)
또한 이 패킷이 IP로 처리되었다는 것 또한 skb에 채워넣는다. (skb->protocol) (*skb->data 에 정의된 패킷 헤더 부분 수정하는 거 아님!)
Netfilter hook(NF_INET_POST_ROUTING) 호출
ip_finish_output()이 함수에서는 fragmention이 필요한지 체크하고, 필요시 진행한다.
체크하기 위해서 min(dev->mtu, IP_MAX_MTU)를 진행한다. (device의 MTU를 넘지 않아야 함. 통상적으로 1500바이트로 설정돼있음)
fragment가 필요한 경우, ip_fragment()을 통해 쪼개고 다시 ip_finish_output() -> ip_finish_output2()
필요 없는 경우, 바로 ip_finish_output2()
cf)
overhead while fragmenting : fragment를 한다는 것은 새로운 패킷을 생성한다는 것 -> 새로운 skb 가 필요함.
해결 방법 : IP layer에서 처리하지 말고, 그대로 NIC에 보내 NIC이 처리하게 하기.
ip_finish_out2()내려보내기 전 마지막 함수이다. 두 가지 역할을 수행한다.
neigh_resolve_output() 을 통해 ARP요청을 보내고 physical address를 받는다.여기까지 모두 성공적으로 끝나면 dev_queue_xmit()을 호출해 L2로 내려보낸다.
RX routine 의 대략적인 과정은 다음과 같다.
ip_rcv() -> ip_rcv_finish() -> ip_local_deliver() -> ip_local_deliver_finish() (여기까지 ip layer) ->
tcp_v4_rcv() -> tcp_v4_do_rcv() -> tcp_rcv_established() -> if slow path, tcp_data_queue(), if fast path tcp_queue_rcv() (여기까지 tcp layer) ->
이후 user의 read()가 호출하는 tcp_recvmsg() 가 데이터 복사할 때까지 receive queue에서 기다리기

*강의 ppt 재구성
위와 같은 함수 chain 에서 IP layer에 해당하는 ip_rcv() ~ ip_local_deliver_finish()을 살펴볼 것이다.
ip_rcv()NF_INET_PRE_ROUTING) 호출ip_rcv_finish()ip_local_deliver()ip_forward()(unicast) , 또는 ip_mr_input()(multicast)ip_local_deliver()NF_INTET_LOCAL_IN) 호출ip_local_deliver_finish()tcp_v4_rcv(), UDP : udp_rcv()1. netif_receive_skb(skb) // 네트워크 장치로부터 skb 수신
2. └── __netif_receive_skb_core()
3. └── packet_type->func(skb) // 예: eth_type_trans()
4. → IP 패킷이면: ip_rcv(skb)
5. └── ip_rcv_finish(skb)
6. └── ip_local_deliver(skb)
7. └── ip_local_deliver_finish(skb)
8. └── ipprot = inet_protos[iphdr->protocol]; // iphdr->protocol == 6 (TCP)-> inet_protos[6] = &tcp_protocol
9. └── ipprot->handler(skb); // &tcp_protocol.handler = tcp_v4_rcv()
ip_forward()NF_INET_FORWARD) 존재ip_forward_finish()ip_output()실행 (TX routine)