Skip to content
오늘을살자
Go back

DoIP에서 NRC 0x21이 반복된다: Busy Repeat Request를 timeout처럼 다루면 꼬인다

Edit page

DoIP 디버깅하다 보면 timeout처럼 보이는데 실제로는 그렇지 않은 경우가 있다.

이때 재전송을 세게 걸면 오히려 더 오래 막힌다.

오늘 메모는 NRC 0x21 Busy Repeat Request를 timeout과 분리해서 봐야 하는 이유다.

먼저 의미부터 짧게

0x21은 보통 이런 뜻으로 읽는다.

지금 그 요청을 바로 처리하기 어렵다. 같은 요청을 조금 뒤에 다시 시도해라.

중요한 건 이거다.

0x21은 “아예 못 받았다”보다
“받았지만 지금 처리 순서가 안 맞는다”에 가깝다.

timeout처럼 다루면 왜 꼬이나

현장 코드에서 자주 보는 흐름이 이렇다.

request 전송
-> NRC 0x21 수신
-> 즉시 retry
-> 또 0x21
-> retry 횟수 초과
-> 세션 재시작 또는 재연결

이 패턴은 겉으로는 합리적으로 보인다.
그런데 실제로는 ECU가 비워질 시간을 전혀 주지 못하는 경우가 많다.

특히 아래 상황에서 자주 보인다.

0x21은 네트워크 timeout이 아니라,
ECU 쪽 작업 큐 또는 자원 점유 상태 신호로 보는 편이 맞다.

Response Pending 0x78과도 다르다

0x210x78을 같은 재시도 정책으로 묶으면 헷갈린다.

둘 다 “지금 당장 최종 응답이 아니다”라는 점은 같지만,
테스터 동작은 달라야 한다.

0x78 -> 같은 transaction 안에서 기다림
0x21 -> 새 retry transaction을 간격 두고 다시 시도

이걸 섞어 버리면,
테스터 로그에는 둘 다 timeout처럼 보이기 쉽다.

자주 터지는 구현 실수

1) 0x21을 수신 에러처럼 올린다

상위 레이어가 0x21을 받았는데도
그냥 “실패” 하나로 뭉개면 retry 정책을 세밀하게 못 짠다.

그러면 결국:

같이 너무 큰 동작으로 번진다.

2) retry 간격이 0에 가깝다

바로 다시 보내면 ECU가 비워질 시간을 못 준다.

0x21 수신 시각
-> 5ms 뒤 재전송
-> 또 0x21

이건 “재시도”라기보다 사실상 “압박”에 가깝다.

실무에서는 짧더라도 의도적인 간격을 두는 편이 낫다.
핵심은 고정 숫자보다 같은 자원 요청을 직렬화하고, 너무 빠른 재전송을 막는 것이다.

3) 멀티 서비스 요청을 동시에 날린다

예를 들어:

을 서로 독립 스레드에서 동시에 던지면,
ECU 입장에서는 같은 내부 자원을 순차 처리해야 해서 0x21이 반복될 수 있다.

이 경우 네트워크를 고치는 게 아니라
테스터 요청 큐를 정리해야 한다.

로그를 이렇게 남기면 빨라진다

0x21 이슈는 패킷만 보면 “응답은 있으니 통신은 정상” 정도로 끝나기 쉽다.
그래서 나는 아래 항목을 같이 묶어 본다.

  1. 요청 서비스 ID와 서브기능
  2. 직전 요청이 끝난 시각
  3. 0x21 수신 시각과 retry 간격
  4. 같은 ECU에 동시에 걸린 요청 개수
  5. 세션/보안 상태 전환 직후인지 여부

이 다섯 줄이 있으면,
“ECU가 바빠서 그런지”와
“테스터가 너무 빨리 다시 던지는지”가 금방 갈린다.

구현 쪽에서 안전한 패턴

가장 무난한 방향은 이렇다.

request 전송
-> final response면 종료
-> NRC 0x78이면 같은 transaction에서 대기
-> NRC 0x21이면 요청 큐에 재스케줄
-> retry 간격과 최대 횟수는 서비스별 정책 적용

그리고 같은 ECU, 같은 자원을 건드리는 요청은
가능하면 직렬화하는 편이 덜 아프다.

예를 들면:

빠른 체크리스트

  1. 0x21을 timeout과 같은 에러 코드로 뭉개고 있지 않은지 확인
  2. retry 간격이 너무 짧지 않은지 확인
  3. 같은 ECU 대상 요청을 여러 태스크가 동시에 보내고 있지 않은지 확인
  4. 0x78 대기 정책과 0x21 재시도 정책을 분리했는지 확인
  5. 재시도 실패 시 바로 재연결하지 말고 세션/큐 상태부터 보도록 했는지 확인

한 줄 요약

DoIP에서 NRC 0x21이 반복되면 네트워크 timeout보다 ECU 자원 점유와 요청 직렬화 문제일 가능성이 크므로, 0x78과 분리된 retry 간격과 큐 정책으로 다루는 편이 안전하다.

추천 키워드

DoIP, UDS, NRC, Busy Repeat Request, retry policy, timeout debugging


DevBJ | 오늘을살자, Log Today


Edit page
Share this post on:

Previous Post
lwIP에서 링크 복구 후 UDP가 한동안 죽어 보인다: ARP 캐시와 netif 상태를 같이 보자
Next Post
lwIP에서 링크는 붙었는데 DHCP가 안 돈다: netif_set_up() / netif_set_link_up() 순서를 같이 보자