본문 바로가기
Operating System

리눅스 커널의 네트워크 패킷 처리 방법

by BestUgi 2018. 1. 12.

다른 장치도 마찬 가지지만, 네트워크 인터페이스가 패킷을 수신 하였을 때 커널에게 알려 주는 방법은 크게 폴링과 인터럽트 방식이 있습니다. 


오늘은 두 가지 방식과 새로운 기술에 대해서 짚고 넘어가도록 하겠습니다.


1. Polling 방식 

  이 방식은 커널이 주기적으로 장치의 상태를 체크 하는 방식 입니다. 쉽게 말해, 장치의 레지스터를 읽어서 패킷의 수신 여부를 확인 하고, 장치가 새로운 패킷을 가지고 있을 경우 이를 처리 하는 방식 입니다. 패킷이 언제 올 줄 모르기 때문에 커널은 주기적으로(예를 들어, 0.0001초 마다) 장치가 패킷을 받았는지 검사 하는 것이지요.

  이 방식은 패킷이 없을 경우에도, 커널이 계속 해서 패킷의 수신 여부를 검사 하기 때문에 CPU 자원의 낭비를 발생 시킨다고 할 수 있습니다. 그래서 인터럽트 보다는 덜 효율 적인 방식이라고 말할 수 있습니다. 


2. Interrupt 방식

  인터럽트 방식은 커널이 패킷 수신 여부를 체크 하지 않습니다. 대신 장치(네트워크 카드 겠지요?)가 새로운 패킷을 받을 경우 하드웨어 IRQ를 사용하여 커널에게 알려 주는 방식 입니다. 커널이 IRQ를 받게 되면, 해당 IRQ를 처리 하기 위해서 미리 등록된 디바이스 드라이버의 인터럽트의 수신 패킷 처리 루틴(Interrupt Handler)을 호출 하게 됩니다. 인터럽트 핸들러(top half handler)는 수신한 패킷을 복사하고 큐에 넣은 후, softirq를 사용하여 커널이 해당 패킷을 처리 할 수 있도록 합니다. 커널의 softirq 핸들러(bottom half handler)는 해당 패킷을 네트워크 프로토콜(해당 장비의 특성(브릿지냐 라우터냐, 스위치냐 등등..)과 네트워크 레이어에 따라)에 맞게 처리 한다. 

  인터럽트 방식은 커널이 즉각 적으로 반응하여 패킷을 처리 할 수 있도록 하는 반면에, 패킷이 너무 많을 경우에 패킷 마다 인터럽트를 발생 시키기 때문에 커널 과부하의 주 원인이 될 수 있습니다. 하나의 장치가 너무 많은 인터럽트를 발생 시키면 커널이 다른 일을 할 수가 없기 때문입니다.


다시한번 짚어 볼까요~? 

  Polling 방식은 트래픽이 없는 상황에서 사용하기에 비 효율적이고, 반면에 Interrupt 방식은 트래픽이 너무 많을 경우 사용하기에 비효율 적입니다.

  그렇다면, 이 둘을 섞어서 사용하면 어떨 까요~? 그래서 나온 기술이 NAPI(New API) 입니다. NAPI에 대한 설명은 아래에서 계속 하도록 하겠습니다. 위에 설명이 잘 이해가 안 가시는 분은 없으시리라 믿고 계속 진행 하겠습니다.


3. NAPI 방식

NAPI 방식은 Polling 방식과 Intrrupt 방식을 함께 사용하고 있습니다. 현재 디바이스 드라이버(커널 측)가 바쁜 상황에서는 인터럽트를 사용하지 않고, 디바이스 드라이버에서 Polling 방식을 사용하도록 합니다. 하지만, 현재 디바이스 드라이버가 한가한 상황이라면, 즉시 인터럽트를 띄워서 새로운 패킷의 도착을 알리게 됩니다. 

그렇다면 디바이스 드라이버가 바쁜지 장치는 어떻게 알 수 있을까요~? 이는 디바이스 드라이버에서 자신이 패킷을 처리 할 때, 장치가 더 이상 인터럽트를 발생 시키지 못하도록 해당 IRQ 인터럽트를 막는 방법으로 위와 같은 효과를 볼 수 있습니다.  즉, 패킷 처리시 인터럽트를 막고, 패킷 처리가 끝 난 후 폴링 방식으로 다른 패킷이 도착 했는지 검사 하는 방식 입니다. 처리할 패킷이 더 이상 없다면 인터럽트를 허용하여, 추후에 도착한 패킷에 대해서는 인터럽트가 발생될 수 있도록 하는 것이지요.


초기에 NAPI 방식이 도입 되었을 때에는 대부분의 디바이스 드라이버들이 NAPI를 지원하지 않았지만, 현재에는 많은 디바이스 드라이버들이 NAPI 방식을 사용하고 있습니다. 

댓글