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 핸들러를 활용
추가 질문이 있으면 언제든지 알려주세요!
device driver/linux