1. UP라는 한 단어로는 네 관문을 구별할 수 없다
Zephyr의 struct net_if는 네트워크 장치와 상위 스택 사이의 접점이다. net_if_up()·net_if_down()은 애플리케이션이 관리 상태(admin state)를 바꾸는 API다. 관리상 UP이어도 장치 준비가 안 됐거나 케이블이 빠졌거나 Wi-Fi 연결이 끝나지 않았다면 운영 상태(oper state)는 UP이 아닐 수 있다. 드라이버 또는 L2가 net_if_carrier_on/off()와 net_if_dormant_on/off()로 하위 링크와 association 상태를 알린다.
왼쪽에서 오른쪽으로 조건을 더합니다. 좁은 화면에서는 가로로 이동하거나 키보드로 영역을 스크롤하세요.
net_if_up() 또는 자동 시작이 인터페이스 사용을 허용합니다.관리 명령일 뿐 물리 링크 확인은 아님NET_IF_OPER_UP가 되고 NET_IF_RUNNING이 설정됩니다.IP 주소는 아직 별도 조건초기화된 인터페이스의 carrier는 기본적으로 켜져 있고 dormant는 기본적으로 꺼져 있다. 이 초기값만 보고 실제 케이블·무선 association을 검증했다고 판단하면 안 된다. 하드웨어와 L2 구현이 변화를 정확히 보고하는지 확인해야 한다. v3.7.0 net_if.c는 관리상 UP뿐 아니라 device_is_ready(), carrier OK, dormant 해제를 살펴 NET_IF_OPER_UP으로 전환한다. Connection Manager의 monitoring을 켰다면 여기에 할당된 IP 주소와 “ignore하지 않음” 조건을 더해 ready를 판정한다.
| 관측점 | 만드는 주체·API | 말해 주는 것 | 아직 말하지 않는 것 |
|---|---|---|---|
| admin-up | 앱의 net_if_up(); 설정에 따른 자동 시작 | 인터페이스 사용 허용 | 케이블·association·주소 |
| carrier OK | 드라이버/L2의 net_if_carrier_on() | 하위 링크 상태 보고 | Wi-Fi association·IP 주소 |
| not dormant | 드라이버/L2의 net_if_dormant_off() | 대기 중인 연결 절차 해소 | IP 주소·원격 서비스 |
| oper-up | net_if가 admin·device·link 상태를 조합 | 인터페이스 운용 가능 | 주소 할당과 라우팅 성공 |
| monitor ready | Connection Manager monitoring | admin/oper-up + 주소 ≥1 + watched | DNS·게이트웨이·인터넷 왕복 |
근거: 3.7.0 Network Interface 상태 관리, v3.7.0 net_if.c의 update_operational_state(), 3.7.0 Connection Manager ready 조건.
2. 상태 이벤트는 패킷이나 소켓의 성공 응답이 아니다
net_mgmt는 네트워크 관리 요청과 이벤트를 다룬다. net_mgmt_add_event_callback()으로 등록한 리스너는 관심 이벤트의 알림을 받고, 소켓의 send()·recv()는 따로 데이터 경로를 지난다. 따라서 NET_EVENT_L4_CONNECTED를 보았다고 해서 DNS 질의나 TLS 연결이 성공했다고 기록하면 관측 범위를 넘는다.
| 이벤트 | 의미 | 확인할 다음 상태 |
|---|---|---|
NET_EVENT_IF_ADMIN_UP/DOWN | 인터페이스를 관리상 켜거나 끔 | carrier·dormant·oper 상태 |
NET_EVENT_IF_UP/DOWN | 인터페이스 운용 상태 변화 | IP 주소가 있는지 |
NET_EVENT_IPV4_ADDR_ADD/DEL | IPv4 주소 추가·삭제 | monitor가 ready로 판단했는지 |
NET_EVENT_IPV4_DHCP_BOUND | DHCPv4 바인딩 성립 | 할당된 주소·경로를 별도 확인 |
NET_EVENT_L4_CONNECTED/DISCONNECTED | 감시 대상 중 ready 인터페이스가 0↔1 이상으로 바뀜 | 어느 인터페이스·주소 계열인지 |
NET_EVENT_L4_IPV4_CONNECTED / NET_EVENT_L4_IPV6_CONNECTED | 해당 주소 계열에서 ready 경계 통과 | 필요한 계열의 실제 요청을 시험 |
3.7.0의 IPv4·IPv6별 L4 연결/해제 이벤트는 같은 릴리스에서 추가됐다. 하나의 인터페이스가 NET_EVENT_IF_UP을 보낸 뒤 주소를 얻는 경로를 흔히 보지만, 앱 로직을 모든 기술에서 고정된 이벤트 순서 하나에 묶지 말자. DHCP, 정적 주소, 자동 연결, 앱 리스너 등록 시점이 다르다. 이벤트를 받으면 실제 관심 상태를 다시 확인하고, 데이터 통신 성공은 실제 소켓 호출에서 판단한다.
근거: 3.7.0 Network Management 이벤트 정의, 3.7.0 릴리스의 주소 계열별 이벤트 추가.
3. 콜백은 실제 이벤트 코드를 확인하고 짧게 끝낸다
런타임 리스너는 net_mgmt_init_event_callback()으로 마스크와 핸들러를 묶고 net_mgmt_add_event_callback()으로 등록한다. 3.7.0의 핸들러 인수는 uint32_t event다. 마스크는 명령 부분을 비트 집합으로 다루므로 같은 layer/layer-code의 다른 이벤트에도 콜백이 호출될 수 있다. 핸들러 안에서 실제 event 값을 반드시 비교한다. L2의 인터페이스 이벤트와 L4의 연결 이벤트를 함께 보려면 두 리스너를 따로 등록해야 한다.
아래는 CONFIG_NET_MGMT·CONFIG_NET_MGMT_EVENT·CONFIG_NET_CONNECTION_MANAGER를 사용하는 구성에서, Connection Manager monitoring이 이미 초기화된 뒤 앱 초기화에서 호출하는 핵심 패턴이다. 실제 앱은 주석 자리에 작업 큐·상태 머신 통지를 넣고, 리스너 구조체 수명은 등록 기간 내내 유지해야 한다.
#include <zephyr/net/net_mgmt.h>
#include <zephyr/net/net_event.h>
#include <zephyr/net/conn_mgr_monitor.h>
static struct net_mgmt_event_callback l4_cb;
static void on_l4(struct net_mgmt_event_callback *cb,
uint32_t event, struct net_if *iface)
{
(void)cb;
(void)iface; /* 집계 이벤트를 특정 iface 성공으로 읽지 않는다. */
if (event == NET_EVENT_L4_CONNECTED) {
/* 짧은 상태 통지만 남긴다. */
} else if (event == NET_EVENT_L4_DISCONNECTED) {
/* 재시도 정책은 앱 작업 문맥에서 결정한다. */
}
}
static void register_l4_listener_after_monitor_init(void)
{
net_mgmt_init_event_callback(&l4_cb, on_l4,
NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED);
net_mgmt_add_event_callback(&l4_cb);
conn_mgr_mon_resend_status(); /* 놓친 최초 상태를 다시 요청 */
}제거할 때는 net_mgmt_del_event_callback(&l4_cb)를 호출한다. 정적 등록이 필요한 경우에는 NET_MGMT_REGISTER_EVENT_HANDLER도 있지만 핸들러 시그니처와 사용 가능한 추가 정보는 동적 콜백과 다르다. 이벤트 추가 정보는 CONFIG_NET_MGMT_EVENT_INFO가 활성화되고 생성자가 실제로 제공할 때만 사용할 수 있다. 일반 콜백에서 오래 막히는 소켓 작업을 수행하면 이벤트 처리를 지연시킬 수 있다.
| 방법 | 등록·수명 | 꼭 확인할 것 |
|---|---|---|
| 동적 콜백 | net_mgmt_init_event_callback() → net_mgmt_add_event_callback(); 필요하면 삭제 | 3.7.0 uint32_t 코드, 구조체 수명, 실제 코드 비교 |
| 정적 핸들러 | NET_MGMT_REGISTER_EVENT_HANDLER로 빌드할 때 등록 | 동적 핸들러와 다른 인수 형태, info 조건 |
| 서로 다른 층의 알림 | layer/layer-code마다 리스너 분리 | L2 IF와 L4 CONNECTED를 마스크 하나로 합치지 않기 |
| 핸들러 본문 | 상태 기록·작업 큐 통지 중심 | 긴 차단 작업과 패킷 처리 경로 혼동 피하기 |
근거: 3.7.0 콜백·false positive 경고, v3.7.0 net_mgmt.h 시그니처, 이벤트 콜백을 짧게 유지하는 이유.
4. 늦게 등록한 리스너는 최초 연결을 놓칠 수 있다
Connection Manager monitoring은 초기화 직후에도 연결 이벤트를 발생시킬 수 있다. 앱이 그 뒤에 콜백을 등록하면 이미 지나간 첫 변화가 자동으로 보관되어 전달되는 것은 아니다. 3.7.0 문서는 monitoring의 SYS_INIT APPLICATION 우선순위(CONFIG_NET_CONNECTION_MANAGER_MONITOR_PRIORITY)보다 먼저 리스너를 등록하거나, 늦게 등록했으면 conn_mgr_mon_resend_status()로 현재 상태 알림을 다시 요청하도록 안내한다.
아래 칸은 개념적 순서 예시입니다. DHCP와 드라이버의 실제 이벤트 간격을 측정한 시간표가 아닙니다.
재전송은 “발생했던 모든 과거 이벤트를 재생”하는 기능이 아니라 현재 connectivity 상태를 다시 알리는 방법이다. 주소 획득 로그, 인터페이스 상태, L4 상태를 서로 다른 관측치로 기록하고, 앱의 처리 함수는 동일 상태 알림이 다시 와도 안전하게 동작하도록 만든다. CONFIG_NET_MGMT_EVENT가 꺼져 있다면 콜백 기반 관측 자체를 사용할 수 없으므로 빌드 설정을 먼저 확인한다.
근거: 3.7.0 최초 알림 누락과 resend, v3.7.0의 실제 선언 헤더 conn_mgr_monitor.h. 3.7.0 설명 문서의 conn_mgr_monitoring.h 표기는 태그된 소스와 달라서 예시에는 실제 헤더 이름을 사용했다.
5. 여러 인터페이스에서 “연결됨”은 집계 판정이다
NET_EVENT_L4_CONNECTED는 감시 중인 ready 인터페이스가 하나 이상 있다는 뜻이다. Wi-Fi와 Ethernet이 모두 ready라면 Wi-Fi만 내려가도 전체 ready는 유지된다. 이때 aggregate NET_EVENT_L4_DISCONNECTED가 반드시 나와야 한다고 기다리면 안 된다. 반대로 감시 대상으로 보는 인터페이스가 모두 준비되지 않으면 전체 disconnected 경계를 지난다.
예시의 두 인터페이스는 모두 IP 주소가 있는 감시 대상이라고 가정합니다.
3.7.0의 family-specific NET_EVENT_L4_IPV4_CONNECTED와 NET_EVENT_L4_IPV6_CONNECTED는 주소 계열별 준비를 분리해서 본다. 이것도 특정 서버에 대한 성공 응답은 아니다. conn_mgr_ignore_iface()로 감시에서 제외한 인터페이스는 실제 admin/oper 상태가 유지되어도 monitor의 ready 판정에서는 빠진다. “인터넷이 끊긴 것처럼” 보일 때 ignore 설정도 확인할 이유다.
| 변화 | ready 개수 | 집계 L4 알림 해석 |
|---|---|---|
| 첫 인터페이스가 ready | 0 → 1 | CONNECTED 경계 |
| 두 번째도 ready | 1 → 2 | 전체 연결 상태는 계속 유지 |
| 첫 번째가 unready, 두 번째는 ready | 2 → 1 | 전체 DISCONNECTED를 기대하지 않음 |
| 남은 것도 unready 또는 ignored | 1 → 0 | DISCONNECTED 경계 |
6. “UP인데 통신 안 됨”을 좁히는 순서
먼저 net_if의 관리·동작 상태를 확인하고, 다음에 주소와 Connection Manager monitoring 상태를 확인한다. 그 후 필요한 주소 계열의 DNS, 경로, 원격 서비스 응답을 따로 시험한다. 개발 빌드에서 network shell을 켰다면 net iface로 인터페이스 상태와 주소를 살펴볼 수 있다. 앱에서는 관심 이벤트의 실제 코드와 현재 상태를 따로 기록해 비교한다.
| 보이는 현상 | 우선 확인 | 다음 실험 |
|---|---|---|
ADMIN_UP만 보임 | carrier OK, dormant, oper state | 케이블·association·드라이버 상태 보고 확인 |
IF_UP인데 L4가 없음 | 주소, ignored 여부, monitor 설정 | DHCP/정적 주소와 CONFIG_NET_CONNECTION_MANAGER 확인 |
| 주소가 있는데 첫 L4 알림 없음 | 리스너 등록 시점 | 등록 후 conn_mgr_mon_resend_status() |
| Wi-Fi 손실 후 전체 L4 해제 없음 | 다른 ready iface 존재 | 각 인터페이스와 주소 계열별 상태 확인 |
| L4 connected인데 서버 요청 실패 | DNS·라우트·방화벽·원격 서비스 | 실제 socket 오류와 패킷 경로 추적 |
구분해야 할 동사: net_if_up()은 관리상 활성화, conn_mgr_if_connect()는 이 API를 지원하도록 바인딩된 인터페이스의 네트워크 association 요청, NET_EVENT_L4_CONNECTED는 monitoring의 IP 준비 관측이다. 서로 대신 호출하거나 성공의 동의어로 쓰지 않는다.
근거: 3.7.0 connectivity control의 바인딩·connect 조건, 3.7.0 Network Shell 명령.
7. Zephyr v3.7.0에 고정한 근거
본문의 API 이름·핸들러 인수·상태 판정은 3.7.0 문서와 v3.7.0 태그를 기준으로 했다. 최신 개발 브랜치에서는 시그니처와 상태 이벤트가 달라질 수 있으므로, 실제 제품의 체크아웃 태그와 생성된 .config를 대조해야 한다. 이 글은 Zephyr 펌웨어를 실제로 빌드·실행한 결과가 아니다.