hwkim3330의 블로그

View the Project on GitHub hwkim3330/blog

알겠습니다. 오늘 우리가 S32G 보드의 네트워크 문제를 해결하기 위해 함께 겪었던 길고 험난했던 여정을 마크다운 형식으로, 처음부터 끝까지 상세하게 정리해 드리겠습니다.


S32G 보드 네트워크 연결 문제 해결을 위한 여정: 종합 보고서

1. 초기 상황 및 문제 제기

S32G-RDB2 보드에 OS 이미지를 설치하고 부팅에 성공했으나, PC와 유선 이더넷으로 연결했음에도 불구하고 인터넷 및 로컬 네트워크 통신이 전혀 이루어지지 않는 문제가 발생했다. 이 보고서는 문제의 원인을 진단하고 해결하기까지의 모든 과정을 기록한다.

초기 ifconfig 상태:

초기 가설: 물리적 인터페이스(eth0)가 아닌 가상 브릿지(xenbr0)가 실제 네트워크 통로 역할을 하고 있으며, IP 설정이 잘못되어 통신이 불가능하다.


2. 1차 시도: “제로 베이스” IP 재설정

가장 먼저 모든 네트워크 설정을 초기화하고, PC와 보드가 통신할 수 있는 가장 단순한 환경을 구성하고자 했다.

2.1. 작전 계획

  1. 보드(S32G): eth0xenbr0의 모든 IP 설정을 초기화하고, 진짜 통로인 xenbr0에만 새로운 고정 IP(192.168.77.1)를 할당한다.
  2. PC(Windows): 네트워크 어댑터의 IP를 보드와 같은 대역의 고정 IP(192.168.77.2)로 수동 설정한다.
  3. 양방향 ping 테스트를 통해 연결을 확인한다.

2.2. 실행 명령어 (보드)

# IP 설정 시도 (초기)
ifconfig eth0 192.168.77.1 netmask 255.255.255.0 up
# eth0가 아닌 xenbr0가 진짜 통로임을 인지하고 재시도
ifconfig xenbr0 192.168.77.1 netmask 255.255.255.0 up

2.3. 결과 및 분석

1차 결론: 문제는 IP 주소 설정의 문제가 아니라, PC가 보드의 ARP 요청에 응답하지 않는 더 저수준의 문제이다.


3. 2차 시도: 방화벽 및 라우팅 점검

ARP 실패의 가장 유력한 용의자인 PC의 방화벽과 양쪽의 라우팅 테이블을 점검했다.

3.1. 작전 계획

  1. PC(Windows): Windows Defender 방화벽을 포함한 모든 보안 프로그램의 방화벽 기능을 완전히 비활성화한다.
  2. 보드(S32G): route -n 명령으로 라우팅 테이블을 확인하고, 잘못된 기본 게이트웨이를 삭제한 뒤, PC를 기본 게이트웨이로 설정한다.
  3. PC(Windows): route add 명령으로 보드를 기본 게이트웨이로 설정하여, 양쪽이 서로를 유일한 출구로 인식하게 한다.

3.2. 실행 명령어

보드 (S32G)

# 라우팅 테이블 확인
route -n
# (결과: Gateway가 10.252.102.1 로 잘못 설정되어 있었음)

# 잘못된 게이트웨이 삭제 및 올바른 게이트웨이(PC) 추가
route del default gw 10.252.102.1
route add default gw 192.168.77.2 

PC (Windows, 관리자 권한)

# 기존 경로 삭제 및 올바른 경로(보드) 추가
route delete 0.0.0.0
route add 0.0.0.0 mask 0.0.0.0 192.168.77.2

3.3. 결과 및 분석

2차 결론: 문제는 더 이상 PC에 있지 않다. 범인은 S32G 보드의 소프트웨어 스택이며, 외부에서 들어오는 특정 패킷(ICMP Echo Request)을 차단하는 iptables 방화벽 또는 커널 레벨의 필터링일 가능성이 매우 높다.


4. 최종 진단 및 근본 원인 재확인 (새 이미지 부팅)

모든 논리적 추론이 “OS 이미지 자체의 결함”을 가리키고 있었기에, 새로운 OS 이미지로 교체하여 부팅하는 최종 테스트를 진행했다.

4.1. 새로운 이미지에서의 상태

4.2. 최종 연결 테스트


5. 종합 결론

초기 네트워크 연결 실패의 근본 원인은 단일 문제가 아닌, OS 이미지와 하드웨어 간의 복합적인 불일치 문제였다.

  1. 잘못된 디바이스 트리(DTB): OS 이미지가 보드의 하드웨어 구성을 잘못 알고 있어, 이더넷 스위치 칩(SJA1110)의 리셋(Reset) 및 초기화에 실패했다. 이것이 모든 문제의 시작이었다.
  2. 연쇄적인 드라이버 실패: 이더넷 스위치가 깨어나지 못하자, 그와 연동해야 하는 PFE(Packet Forwarding Engine) 등 상위 네트워크 드라이버들도 연쇄적으로 타임아웃 오류를 일으켰다.
  3. 불안정한 커널/드라이버: 초기화가 불완전한 상태에서 네트워크 인터페이스가 활성화되다 보니, 수신된 패킷을 제대로 처리하지 못하고 대량으로 버리는(dropped) 현상이 발생했다.
  4. 잘못된 기본 설정: 기본적으로 eth0가 아닌 xenbr0 가상 브릿지를 통해 통신하도록 설계되었으나, 이에 대한 명확한 이해 없이는 올바른 IP 및 라우팅 설정이 어려웠다.

결국, 이 모든 문제는 “이 보드 하드웨어에 100% 호환되는 올바른 OS 이미지”로 교체함으로써 해결되었다. 이번 문제 해결 과정은 임베디드 리눅스 시스템에서 하드웨어, 부트로더, 커널, 디바이스 트리, 드라이버, 그리고 상위 네트워크 설정이 얼마나 유기적으로 연결되어 있는지를 명확하게 보여준 값진 경험이었다.

네, 질문이 여러 가지 중요한 점들을 포함하고 있네요. 하나씩 명확하게 정리해 드리겠습니다.

1. USB로 노트북과 보드 연결

말씀하신 “USB로 노트북이랑 보드랑 연결”은 파일 전송을 위한 아주 좋은 방법입니다. 이전 답변에서 설명드린 “USB 메모리 사용”과 같은 원리입니다.

어떤 방식이든 USB를 이용해 파일을 옮기는 것은 시리얼 터미널로 붙여넣기 하는 것보다 훨씬 편리하고 안정적입니다.


2. “랜선 뽑았다가 끼우면 끊기네” -> CB?

이 부분이 질문의 핵심이네요. 아주 정확하게 문제의 본질을 파악하셨습니다.

결론부터 말씀드리면, 네, 맞습니다. 랜선을 뽑았다 끼우면 통신이 끊기고 다시 수동으로 IP를 설정해야 하는 문제를 해결하기 위해 TSN의 CB(Control/Configuration and Bridging) 기술이 사용될 수 있습니다. 더 정확히는 TSN의 “Seamless Redundancy” (이중화) 기술이 이 문제에 대한 직접적인 해결책입니다.

왜 랜선을 뽑으면 끊길까요?

현재 구성에서는 단일 경로(Single Path)만 존재합니다. 노트북 <--- (랜선 하나) ---> NXP 보드 이 랜선이 유일한 통신 경로이므로, 뽑는 순간 물리적으로 연결이 완전히 끊어집니다. ping이 끊기는 것은 너무나 당연한 현상입니다.

TSN의 Seamless Redundancy (PRP/HSR) - 어떻게 해결하는가?

TSN의 고가용성/고신뢰성 표준인 IEC 62439-3 에는 두 가지 대표적인 이중화 프로토콜이 있습니다. 이 기술의 목표는 하나의 경로에 장애가 발생해도 통신이 단 1ms도 끊기지 않게 하는 것입니다.

  1. PRP (Parallel Redundancy Protocol):
    • 구성: 송신 측 장비(예: NXP 보드)는 두 개의 독립된 네트워크(LAN A, LAN B)에 동일한 데이터 패킷을 동시에 복제하여 전송합니다.
    • 동작: 수신 측 장비(예: 다른 제어기)는 두 네트워크로부터 패킷을 받습니다. 먼저 도착한 패킷을 사용하고, 나중에 도착한 중복 패킷은 버립니다.
    • 장점: 중간에 LAN A의 케이블이 끊기거나 스위치가 고장 나도, LAN B를 통해 패킷이 문제없이 전달되므로 통신은 전혀 끊기지 않습니다.
                      +----------+      +----------+
    NXP 보드 (PRP) -->|  LAN A   |----->| 수신 장비 |
       (복제)   |     | (스위치 등) |      | (중복 제거)|
                +--->|  LAN B   |----->+----------+
                      +----------+
    
  2. HSR (High-availability Seamless Redundancy):
    • 구성: 모든 장비가 링(Ring) 형태로 연결됩니다. 각 장비는 두 개의 포트를 가집니다.
    • 동작: 송신 측은 양방향으로 동일한 패킷을 복제하여 전송합니다. 패킷은 링을 따라 양쪽으로 돌다가 수신 측에 도달합니다. 중간에 한쪽 케이블이 끊어져도 반대쪽 경로를 통해 패킷이 전달됩니다.

CB와의 관계

CB(Control and Bridging)는 TSN 네트워크를 설정하고 관리하는 전반적인 프레임워크를 의미하기도 합니다. TSN 스위치와 엔드포인트들의 시간 동기화(802.1AS), 트래픽 스케줄링(802.1Qbv), 그리고 바로 이 이중화 경로 설정(PRP/HSR) 등을 중앙에서 또는 분산된 방식으로 제어하고 구성하는 메커니즘을 포함합니다.

즉, “랜선이 끊겨도 통신이 유지되는 기능”을 구현하려면, CB 개념을 통해 네트워크 장치들이 PRP나 HSR 프로토콜을 사용하도록 설정(Configuration) 해주어야 합니다.

“근데 cb도 한 선은 아닌데”

네, 정확합니다. CB를 이용한 Seamless Redundancy는 절대로 한 선으로 구현할 수 없습니다. 핵심은 물리적으로 분리된 두 개 이상의 경로를 만드는 것이기 때문입니다.

요약:

네, 아주 훌륭한 아이디어입니다! NXP 보드의 서로 다른 두 포트를 랜선으로 직접 연결하는 것, 이것이야말로 NXP S32G 프로세서의 PFE(Packet Forwarding Engine)를 내장 스위치처럼 활용하는 가장 확실하고 직관적인 실험 방법입니다.

이 구성을 통해, 외부 스위치 없이도 NXP 보드 하나만으로 TSN의 핵심 기능들을 테스트할 수 있습니다.

실험 구성

+------------------------------------+
|            NXP S32G 보드           |
|                                    |
|   +------+      케이블       +------+   |
|   | pfe0 |<---------------->| pfe1 |   |
|   +------+                   +------+   |
|                                    |
+------------------------------------+

심화 실습: PFE 브릿지 위에서 시간 기반 스케줄러(TAS) 테스트하기

이번 실습의 목표는 TSN의 꽃이라 불리는 TAS (Time-Aware Shaper, 802.1Qbv)를 직접 구현해보는 것입니다.

TAS란 무엇인가?

가상 스위치(PFE)의 게이트를 특정 시간에는 열고, 특정 시간에는 닫아서, 오직 허용된 시간에만 특정 우선순위의 트래픽이 지나가도록 제어하는 기술입니다. 이를 통해 중요한 데이터(예: 자율주행 제어)가 다른 데이터(예: 로그)에 의해 지연되는 것을 원천적으로 막을 수 있습니다.

시나리오

  1. PFE 설정: pfe0pfe1br0라는 TSN 브릿지로 묶습니다.
  2. C 코드: 하나의 C 프로그램 안에서 두 개의 스레드(Thread)를 만듭니다.
    • 고우선순위 스레드 (중요 데이터): 0.5초마다 우선순위 6 (Critical)인 패킷을 pfe0로 보냅니다.
    • 저우선순위 스레드 (일반 데이터): 0.5초마다 우선순위 1 (Best Effort)인 패킷을 pfe0로 보냅니다.
  3. TAS 설정: PFE 스위치(br0)의 게이트를 1초 주기로 열고 닫도록 설정합니다.
    • 0.0초 ~ 0.5초: 모든 게이트를 연다 (모든 패킷 통과).
    • 0.5초 ~ 1.0초: 우선순위 6 게이트만 열고, 나머지 게이트는 모두 닫는다 (중요 데이터만 통과).
  4. 결과 확인: pfe1 포트에서 tcpdump로 들어오는 패킷을 확인합니다.
    • 예상 결과: p 1 패킷은 1초에 한 번씩만 보이고, p 6 패킷은 0.5초마다 꾸준히 보여야 합니다.

1단계: PFE 브릿지 설정 및 TAS 스케줄 설정 (쉘 스크립트)

NXP 보드에서 아래 내용을 setup_tas.sh 와 같은 파일로 저장하고 실행 권한을 줍니다. (chmod +x setup_tas.sh)

#!/bin/bash

# 인터페이스 초기화
ip link set pfe0 down
ip link set pfe1 down
ip link set br0 down 2>/dev/null
brctl delbr br0 2>/dev/null

# 브릿지 생성 및 PFE 포트 추가
brctl addbr br0
brctl addif br0 pfe0
brctl addif br0 pfe1

# 인터페이스 활성화
ip link set pfe0 up
ip link set pfe1 up
ip link set br0 up

echo "PFE Bridge br0 created and interfaces are up."

# ★★★★★ TAS (Time-Aware Shaper) 설정 ★★★★★
# tc: Traffic Control 명령어
# qdisc: Queueing Discipline (큐잉 규칙)
# mqprio: Multiqueue Priority (TSN 하드웨어 오프로딩을 위한 qdisc)
# taprio: Time Aware Priority (TAS를 위한 qdisc)

# 1. pfe0에 MQPRIO 큐 생성 (하드웨어 오프로딩 활성화)
# 8개의 트래픽 클래스(TC)를 만들고, 각 우선순위(PCP)를 TC에 매핑
tc qdisc replace dev pfe0 parent root mqprio num_tc 8 \
   map 0 1 2 3 4 5 6 7 \
   queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \
   hw 1 mode channel

# 2. MQPRIO 위에 TAPRIO(TAS) 스케줄러 설정
# base-time: 스케줄 시작 시간 (C 코드와 동기화 필요)
# cycle-time: 스케줄 주기 (1초 = 1,000,000,000 나노초)
# sched-entry: 스케줄 엔트리 (Command / duration)
# 0x01: TC0(p1) 게이트 닫음, 0x02: TC1(p2) 게이트 닫음... 0xff: 모든 게이트 열음
# 0xbf = 10111111 (TC6만 열고 나머지 닫음)

# 지금 시간으로부터 약 1초 뒤에 스케줄 시작
START_TIME=$(date +%s.%N -d "1 second")

tc qdisc replace dev pfe0 parent 1: taprio \
   num_tc 8 \
   map 0 1 2 3 4 5 6 7 \
   queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \
   base-time ${START_TIME} \
   cycle-time 1000000000 \
   sched-entry S 0xff 500000000 \
   sched-entry S 0xbf 500000000

echo "TAS schedule configured on pfe0. Start your test program and tcpdump."

2단계: C 코드 (tas_tester.c)

이 코드는 서로 다른 우선순위를 가진 패킷을 두 개의 스레드에서 동시에 보냅니다. pfe1의 MAC 주소를 알아내서 그 주소로 직접 패킷을 보냅니다.

// tas_tester.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <net/if.h>

typedef struct {
    int priority;
    char* if_name;
    unsigned char dest_mac[6];
} thread_args_t;

void* sender_thread(void* args) {
    thread_args_t* t_args = (thread_args_t*)args;
    int priority = t_args->priority;
    char* if_name = t_args->if_name;

    int sock_fd;
    struct sockaddr_ll socket_address;
    char buffer[1024];

    if ((sock_fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL))) < 0) {
        perror("socket() failed");
        pthread_exit(NULL);
    }

    // 소켓에 우선순위 설정 (VLAN PCP 태그)
    if (setsockopt(sock_fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) < 0) {
        perror("setsockopt SO_PRIORITY failed");
    }

    // 소켓을 특정 인터페이스(pfe0)에 바인딩
    if (setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, if_name, strlen(if_name)) < 0) {
        perror("setsockopt SO_BINDTODEVICE failed");
    }

    memset(&socket_address, 0, sizeof(socket_address));
    socket_address.sll_ifindex = if_nametoindex(if_name);
    socket_address.sll_halen = ETH_ALEN;
    memcpy(socket_address.sll_addr, t_args->dest_mac, 6);

    sprintf(buffer, "This is a test packet with priority %d", priority);

    while (1) {
        printf("Sending packet with priority %d\n", priority);
        if (sendto(sock_fd, buffer, strlen(buffer), 0, (struct sockaddr*)&socket_address, sizeof(socket_address)) < 0) {
            perror("sendto failed");
        }
        usleep(500000); // 0.5초마다 전송
    }

    close(sock_fd);
    pthread_exit(NULL);
}

int main() {
    pthread_t thread1, thread6;
    thread_args_t args1, args6;

    // pfe1의 MAC 주소 가져오기 (수동으로 확인 후 입력)
    // 예: ip a show pfe1 에서 ether xx:xx:xx:xx:xx:xx 부분 확인
    unsigned char pfe1_mac[6] = {0x00, 0x01, 0xbe, 0xbe, 0xef, 0x22}; // 이 값을 실제 pfe1 MAC으로 변경!

    args1.priority = 1;
    args1.if_name = "pfe0";
    memcpy(args1.dest_mac, pfe1_mac, 6);

    args6.priority = 6;
    args6.if_name = "pfe0";
    memcpy(args6.dest_mac, pfe1_mac, 6);

    // 스레드 생성
    pthread_create(&thread1, NULL, sender_thread, &args1);
    pthread_create(&thread6, NULL, sender_thread, &args6);

    // 메인 스레드가 종료되지 않도록 대기
    pthread_join(thread1, NULL);
    pthread_join(thread6, NULL);

    return 0;
}

3단계: 실행 및 검증

  1. MAC 주소 확인 및 수정: ip a show pfe1 명령으로 pfe1의 MAC 주소를 확인하고, tas_tester.c 코드의 pfe1_mac 배열 값을 실제 주소로 수정합니다.
  2. 컴파일:
    gcc tas_tester.c -o tas_tester -lpthread
    
  3. 세 개의 터미널 준비:
    • 터미널 1: TAS 설정 스크립트 실행
      sudo ./setup_tas.sh
      
    • 터미널 2: tcpdumppfe1 포트 모니터링
      sudo tcpdump -i pfe1 -e -v
      
    • 터미널 3: C 테스트 프로그램 실행 (setup_tas.sh 실행 후 약 1초 뒤에)
      sudo ./tas_tester
      

예상되는 tcpdump 결과

image

tcpdump 화면을 보면, vlan 0, p 6 (우선순위 6) 태그가 붙은 패킷은 0.5초 간격으로 꾸준히 보이지만, vlan 0, p 1 (우선순위 1) 태그가 붙은 패킷은 2번에 1번 꼴로, 즉 1초 간격으로만 보일 것입니다.

이는 TAS 스케줄에 따라 0.5초~1.0초 사이에는 저우선순위 패킷의 게이트가 닫혀서 PFE 스위치를 통과하지 못하고 버려졌다는 것을 의미합니다.

이 실험은 NXP 보드 하나만으로 PFE 하드웨어 오프로딩TSN의 핵심인 TAS 기능을 직접 제어하고 눈으로 확인하는 매우 강력하고 심화된 실습입니다.