본문 바로가기
device driver/linux

RX 핸들러의 동작 원리와 개념

by 의지의 엘린 2025. 3. 14.

RX 핸들러의 동작 원리와 개념

1. RX 핸들러란?

RX 핸들러(Receive Handler)는 리눅스 커널에서 특정 네트워크 인터페이스로 들어오는 패킷을 가로채고 처리할 수 있는 기능입니다.
이 기능을 이용하면 패킷을 필터링하거나, 수정하거나, 다른 인터페이스로 전달하는 등의 작업을 수행할 수 있습니다.

핵심 개념:
netdev_rx_handler_register()를 사용하여 특정 net_device(예: eth0, bond0, macvlan0 등)에 RX 핸들러를 등록하면,
해당 인터페이스로 들어오는 모든 패킷이 먼저 RX 핸들러를 거치게 됨.
이후 핸들러의 반환 값(rx_handler_result_t)에 따라 패킷의 처리 방식이 결정됨.

2. RX 핸들러의 동작 원리

(1) 기본 네트워크 패킷 흐름

리눅스 커널에서 패킷이 수신될 때 기본적인 처리는 다음과 같습니다.
1. NIC(네트워크 카드)가 패킷을 수신
• 물리적인 네트워크 카드(NIC)가 외부에서 들어오는 패킷을 수신.
• 패킷은 sk_buff(소켓 버퍼) 형태로 커널 내로 전달됨.
2. 네트워크 드라이버가 패킷을 커널에 전달
• 패킷은 네트워크 드라이버에서 netif_rx()를 통해 커널의 네트워크 스택으로 전달됨.
• 이 단계에서 패킷은 인터페이스(net_device)에 매핑됨.
3. 네트워크 인터페이스에서 패킷을 처리
• 일반적으로 패킷은 네트워크 인터페이스 드라이버를 거쳐 네트워크 스택으로 전달됨(IP, TCP, UDP 등).
• 하지만 특정 net_device에 RX 핸들러가 등록되어 있으면, 패킷이 네트워크 스택으로 전달되기 전에 RX 핸들러가 먼저 실행됨.

(2) RX 핸들러가 개입하는 과정
1. 특정 네트워크 인터페이스(예: eth0)에 RX 핸들러가 등록됨.
2. NIC가 패킷을 수신하고 netif_rx()를 호출하여 커널로 전달.
3. 패킷이 net_device(예: eth0)로 들어오면, 커널은 먼저 RX 핸들러를 실행.
4. RX 핸들러의 반환 값(rx_handler_result_t)에 따라 패킷 처리 방식이 결정됨.

3. RX 핸들러의 반환 값과 동작 방식

RX 핸들러의 반환 값(rx_handler_result_t)에 따라 패킷이 처리되는 방식이 결정됩니다.

리턴 값 동작 방식
RX_HANDLER_PASS 패킷을 정상적으로 네트워크 스택(IP/TCP/UDP 등)으로 전달
RX_HANDLER_CONSUMED 패킷을 현재 RX 핸들러에서 삭제(폐기)하고 더 이상 처리하지 않음
RX_HANDLER_ANOTHER 패킷을 다른 RX 핸들러에서 처리하도록 전달

(1) RX_HANDLER_PASS (기본 패킷 처리)
• 패킷을 수정하지 않고 정상적으로 네트워크 스택(IP/TCP/UDP 등)으로 전달함.
• 예제:

return RX_HANDLER_PASS;


• 동작 방식:
• RX 핸들러가 패킷을 가로챘지만, 패킷을 수정하지 않고 커널의 기본 네트워크 경로로 계속 전달.

(2) RX_HANDLER_CONSUMED (패킷 삭제)
• RX 핸들러가 패킷을 직접 소비하고 네트워크 스택으로 전달하지 않음.
• 주로 패킷 필터링(예: 특정 프로토콜 차단)할 때 사용.
• 예제:

kfree_skb(skb);
return RX_HANDLER_CONSUMED;


• 동작 방식:
• RX 핸들러에서 패킷을 삭제하면 더 이상 커널 네트워크 스택에서 해당 패킷을 처리하지 않음.
• 예를 들어, 특정 프로토콜(ARP 패킷 등)을 필터링하여 차단 가능.

(3) RX_HANDLER_ANOTHER (다른 RX 핸들러에 전달)
• 특정 네트워크 인터페이스가 아니라 다른 RX 핸들러로 패킷을 넘기는 기능.
• 보통 여러 개의 RX 핸들러를 연속적으로 적용할 때 사용됨.
• 예제:

return RX_HANDLER_ANOTHER;


• 동작 방식:
• 패킷이 한 RX 핸들러에서 처리되지 않고, 다음 RX 핸들러에서 처리될 수 있도록 함.
• 주로 네트워크 스위칭 기능을 구현할 때 사용.

4. RX 핸들러 등록 과정

RX 핸들러는 netdev_rx_handler_register()를 사용하여 특정 네트워크 인터페이스(net_device)에 등록합니다.

(1) RX 핸들러 등록 함수

int netdev_rx_handler_register(struct net_device *dev, rx_handler_func_t *rx_handler, void *rx_handler_data);

• dev: RX 핸들러를 등록할 네트워크 인터페이스(net_device).
• rx_handler: 패킷을 처리할 RX 핸들러 함수.
• rx_handler_data: 핸들러에서 사용할 추가적인 데이터.

(2) RX 핸들러 등록 예제

다음은 eth0 인터페이스에 RX 핸들러를 등록하는 예제입니다.

static rx_handler_result_t my_rx_handler(struct sk_buff **pskb)
{
    struct sk_buff *skb = *pskb;

    if (!skb) return RX_HANDLER_PASS; // 패킷이 없으면 기본 경로로 전달

    printk(KERN_INFO "RX Handler: Packet intercepted!\n");

    // 특정 조건에서 패킷을 삭제(drop)
    if (skb->protocol == htons(ETH_P_ARP)) {
        printk(KERN_INFO "Dropping ARP packet\n");
        kfree_skb(skb);
        return RX_HANDLER_CONSUMED;  // 패킷 삭제 후 더 이상 처리 안 함
    }

    return RX_HANDLER_PASS;  // 정상적으로 네트워크 스택으로 전달
}

static int __init my_module_init(void)
{
    struct net_device *dev = dev_get_by_name(&init_net, "eth0");  // eth0 인터페이스 가져오기
    if (!dev)
        return -ENODEV;

    if (netdev_rx_handler_register(dev, my_rx_handler, NULL)) {
        printk(KERN_ERR "RX handler registration failed\n");
        return -EINVAL;
    }

    printk(KERN_INFO "RX Handler registered on eth0\n");
    return 0;
}

static void __exit my_module_exit(void)
{
    struct net_device *dev = dev_get_by_name(&init_net, "eth0");
    if (dev) {
        netdev_rx_handler_unregister(dev);
        printk(KERN_INFO "RX Handler unregistered from eth0\n");
    }
}

module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");

5. RX 핸들러 활용 사례

RX 핸들러는 다음과 같은 네트워크 기능에서 사용됩니다.
• MACVLAN: 가상 MAC 인터페이스에서 패킷을 적절한 인터페이스로 전달.
• Bonding (NIC Teaming): 여러 NIC를 묶어서 부하 분산 및 장애 조치를 수행.
• Open vSwitch (OVS): RX 핸들러를 이용하여 패킷을 브리지로 전달.

6. 정리

✅ RX 핸들러는 패킷을 가로채고, 수정하거나 삭제할 수 있는 기능
✅ netdev_rx_handler_register()를 통해 특정 인터페이스에 등록 가능
✅ 반환 값(RX_HANDLER_PASS, RX_HANDLER_CONSUMED, RX_HANDLER_ANOTHER)에 따라 패킷 처리 방식이 결정됨
✅ MACVLAN, Bonding, OVS 등의 네트워크 기능에서 RX 핸들러를 활용

추가 질문이 있으면 언제든지 알려주세요!