# 수신 경로: 패킷을 IPv4·IPv6 처리 함수에 넘기는 순간

v6.6 / net/core/dev.c

NIC가 메모리에 받은 패킷은 드라이버와 NAPI를 거쳐 네트워크 계층으로 올라옵니다. 이때 공통 수신 처리는 VLAN·브리지·프로토콜 분류 등으로 패킷과 수신 장치를 바꿀 수도 있습니다. 아래 __netif_receive_skb_one_core 전체는 그 공통 처리를 거친 뒤 마지막 프로토콜 수신 함수에 넘기는 경계를 보여 줍니다. NAPI와 GRO의 전체 구현을 이 짧은 함수 하나로 대신하지는 않습니다.

## __netif_receive_skb_one_core

```c

static int __netif_receive_skb_one_core(struct sk_buff *skb, bool pfmemalloc)
{
	struct net_device *orig_dev = skb->dev;
	struct packet_type *pt_prev = NULL;
	int ret;

	ret = __netif_receive_skb_core(&skb, pfmemalloc, &pt_prev);
	if (pt_prev)
		ret = INDIRECT_CALL_INET(pt_prev->func, ipv6_rcv, ip_rcv, skb,
					 skb->dev, pt_prev, orig_dev);
	return ret;
}

```

### 5544행

```c

static int __netif_receive_skb_one_core(struct sk_buff *skb, bool pfmemalloc)

```

패킷 하나와 비상 메모리 할당 여부를 받아 공통 수신 처리와 마지막 프로토콜 호출을 연결합니다.

### 5546행

```c

	struct net_device *orig_dev = skb->dev;

```

수신 처리 중 skb->dev가 바뀌어도 원래 입력 장치를 기억하도록 별도로 보관합니다.

### 5547행

```c

	struct packet_type *pt_prev = NULL;

```

아직 최종 프로토콜 처리 대상을 정하지 않았다는 뜻으로 NULL을 둡니다.

### 5548행

```c

	int ret;

```

공통 처리 또는 프로토콜 함수의 반환 상태를 담습니다.

### 5550행

```c

	ret = __netif_receive_skb_core(&skb, pfmemalloc, &pt_prev);

```

skb 포인터의 주소를 전달해 공통 처리에서 포인터를 갱신할 수 있게 합니다. pfmemalloc 조건과 최종 처리 대상 pt_prev도 함께 전달합니다.

### 5551행

```c

	if (pt_prev)

```

공통 처리 뒤 실제로 호출할 프로토콜 수신 함수가 남아 있는지 확인합니다.

### 5552행

```c

		ret = INDIRECT_CALL_INET(pt_prev->func, ipv6_rcv, ip_rcv, skb,

```

IPv6·IPv4의 흔한 수신 함수에는 간접 호출 최적화를 적용하고 그 밖에는 등록된 함수를 호출합니다. 셋을 모두 실행하는 매크로가 아닙니다.

### 5553행

```c

					 skb->dev, pt_prev, orig_dev);

```

현재 장치, 선택한 packet_type과 처음 입력 장치를 최종 수신 함수에 전달합니다.

### 5554행

```c

	return ret;

```

패킷 처리 상태를 상위 수신 경로에 반환합니다. 사용자에게 파일 데이터를 반환하는 위치는 아닙니다.

