Skip to content
오늘을살자
Go back

lwIP에서 UDP send가 ERR_RTE로 실패한다: payload보다 netif 상태와 route를 먼저 보자

Edit page

lwIP에서 UDP는 단순해 보인다.
연결도 없고, ACK도 없고, 그냥 목적지로 보내면 될 것처럼 느껴진다.

그런데 bring-up 중에는 이런 로그가 자주 나온다.

이때 UDP 데이터나 체크섬부터 보면 오래 헤맨다.
ERR_RTE는 이름 그대로 보낼 경로를 못 찾았다는 쪽에 가깝다.

오늘 메모는 lwIP에서 UDP send가 ERR_RTE로 실패할 때 netif와 route를 어디서 확인해야 하는지다.

결론부터

UDP 송신 전에 lwIP는 먼저 이런 질문을 한다.

이 목적지 IP로 보낼 netif가 있는가?
그 netif가 up 상태인가?
IP 주소와 netmask/gateway가 말이 되는가?
link 상태는 송신 가능한가?

여기서 걸리면 payload는 아직 중요한 단계가 아니다.
ARP도 안 나갈 수 있다.

ERR_RTE를 보면
패킷 내용보다 netif 선택과 상태 전환을 먼저 봐야 한다.

흔한 패턴 1: DHCP 완료 전에 송신한다

부팅 직후 앱 태스크가 먼저 떠서 UDP를 보내는 구조가 많다.

netif_add()
netif_set_up()
dhcp_start()
app task starts
udp_sendto()

이 흐름에서 아직 DHCP 주소를 받지 못했다면
netif는 존재하지만 실제 송신 경로로 쓰기 애매한 상태일 수 있다.

특히 로그에 아래가 같이 보이면 의심해 볼 만하다.

이 경우 UDP 코드가 아니라
앱 시작 조건을 DHCP bound 이후로 늦추는 것이 먼저다.

관련 흐름은 lwIP에서 링크는 붙었는데 DHCP가 안 돈다: netif_set_up() / netif_set_link_up() 순서를 같이 보자에서도 같이 볼 수 있다.

흔한 패턴 2: default netif가 없다

목적지 IP가 특정 netif에 명확히 매칭되지 않으면
lwIP는 default netif를 사용해야 할 수 있다.

그런데 초기화 코드에서 netif_set_default()를 빼먹으면
송신 경로를 못 잡는 경우가 나온다.

netif_add(&g_netif, &ipaddr, &netmask, &gw, NULL, ethernetif_init, tcpip_input);
netif_set_up(&g_netif);
netif_set_link_up(&g_netif);

/* 빠지기 쉬운 부분 */
netif_set_default(&g_netif);

보드에 네트워크 인터페이스가 하나뿐이어도
default netif 설정은 명시해 두는 편이 디버깅이 쉽다.

특히 나중에 loopback, PPP, Wi-Fi 같은 다른 interface가 추가되면
“하나뿐이라 괜찮다”는 가정이 바로 깨진다.

lwIP에서 netif의 administratively up 상태와
물리 링크 상태는 같은 말이 아니다.

netif_set_up()
-> 이 interface를 사용할 준비가 됐다는 소프트웨어 상태

netif_set_link_up()
-> PHY/link가 살아 있다는 하드웨어 쪽 상태

프로젝트마다 옵션과 드라이버 구현 차이는 있지만,
두 상태를 섞으면 송신 판단이 애매해진다.

자주 보는 실수는 이렇다.

PHY link down
-> netif는 여전히 up
-> 앱은 UDP 송신 시도
-> route 또는 link 상태 문제로 실패

반대로 link는 올라왔는데 netif_set_up()이 늦게 불리면
송신 경로가 아직 닫혀 있을 수 있다.

흔한 패턴 4: 목적지 IP가 local network 밖인데 gateway가 없다

같은 subnet으로 보내는 UDP와
다른 subnet으로 보내는 UDP는 route 판단이 다르다.

예를 들어 보드 IP가 아래와 같다고 하자.

ip      = 192.168.0.10
netmask = 255.255.255.0
gateway = 0.0.0.0

이 상태에서 192.168.0.20으로 보내는 건 local network 안이다.
하지만 10.0.0.20으로 보내려면 gateway가 필요하다.

gateway가 없으면 lwIP는 어디로 내보내야 할지 모른다.
이때도 payload 크기나 UDP port는 핵심이 아니다.

ERR_RTE와 ARP 실패를 구분해야 한다

ERR_RTE와 ARP 실패는 가까워 보이지만 같은 문제는 아니다.

ERR_RTE
-> 보낼 netif/route를 고르지 못함

ARP 실패
-> 보낼 netif는 골랐지만 next-hop MAC을 못 찾음

그래서 캡처에서 ARP request 자체가 안 보이면
ARP 테이블보다 route와 netif 상태를 먼저 봐야 한다.

반대로 ARP request가 나가는데 reply가 없다면
그때는 케이블, 스위치, 상대 IP, ARP cache 쪽으로 내려가면 된다.

링크 복구 뒤 UDP만 한동안 죽는 흐름은
lwIP에서 링크 복구 후 UDP가 한동안 죽어 보인다: ARP 캐시와 netif 상태를 같이 보자와 이어진다.

구현 쪽에서 무난한 패턴

앱 송신 조건을 한 곳에 모아 두면 디버깅이 쉬워진다.

can_send_udp():
  netif exists
  netif is up
  link is up
  ip address is valid
  default netif is set or destination matches this netif
  gateway is valid when destination is off-subnet

그리고 UDP send 실패 로그에는 최소한 이 정도는 같이 남기는 편이 좋다.

err=ERR_RTE
dst=10.0.0.20:5000
netif_up=1 link_up=1
ip=192.168.0.10 mask=255.255.255.0 gw=0.0.0.0
default_netif=eth0

이 로그가 있으면
“UDP가 왜 실패하지?”보다
“이 목적지로 나갈 route가 실제로 있나?”를 바로 볼 수 있다.

빠른 체크리스트

  1. DHCP bound 또는 static IP 설정 완료 전에 UDP 송신을 시작하지 않는지 확인
  2. netif_set_default()가 초기화 흐름에 들어 있는지 확인
  3. netif_set_up()netif_set_link_up() 상태를 따로 로그에 남기는지 확인
  4. 목적지가 local subnet 밖이면 gateway가 설정되어 있는지 확인
  5. ARP request가 아예 안 나가는지, 나가는데 reply가 없는지 캡처로 구분

한 줄 요약

lwIP에서 UDP 송신이 ERR_RTE로 실패하면 payload나 ARP보다 먼저 netif up/link/default route/IP/gateway 상태를 확인하는 편이 빠르다.

추천 키워드

lwIP, UDP, ERR_RTE, netif, DHCP, embedded network


DevBJ | 오늘을살자, Log Today


Edit page
Share this post on:

Next Post
DoIP에서 NRC 0x13이 뜬다: 메시지 길이 오류를 TCP 조각 문제로 착각하지 말자