Data Link Layer in Linux

John·2025년 6월 14일

system programming

목록 보기
8/11

이번 페이지에서는 L2인 Datalink layer에서의 동작에 대해 알아보겠다.
사실 layer2 와 디바이스 동작을 완벽히 나눌 수는 없어, 동작에 있어 핵심적인 부분을 위주로 device layer와 설명할 예정.

layer2 의 데이터 단위는 frame 이다.

net_device는 각각의 NIC에 대해 구성되는 자료구조이다.

TX in Data Link Layer

TX routine

위의 그림을 보면, L3 마지막에 dev_queue_xmit()을 불러와 data link layer에 데이터를 전달한다.

위의 그림 이후에 어떤 일이 일어나는지 알아보자.

  1. dev_queue_xmit()을 통해 data link layer로 이동한 데이터는 queue 형태로 저장되어 처리를 기다린다. 이 queue는 queuing discipline(qdisc)에 의해 관리됨.

  2. Device Driver은 해당 queue에서 데이터 정보를 가져와(address&length of skb), NIC에게 처리할 패킷이 있다고 알림.

3, 이후 DMA를 통해 NIC로의 데이터 cp.

  • 이번 페이지에서는 일단 L3에서 어떻게 Device Driver로 데이터가 이동하는지에 초점을 맞춰 설명할 것이다.

dev_queue_xmit()

  • 인터페이스 (NIC)의 정보 체크. 하나의 NIC에는 여러 개의 포트(인터페이스)가 있을 수 있는데, 패킷이 사용할 인터페이스의 정보를 체크한다.
  • XDP hook이 있다면 해당 hook 실행. i.e. eBPF 프로그램 hook.

cf)
eBPF program - 추가적인 기능을 제공하는 프로그램
eBPF hook - eBPF를 실행할 포인트
XDP - L2에 있는 eBPF hook 의 한 종류.

Queuing discipline (qdisc)

  • 패킷이 나가기 전, qdisc queue를 통해 줄을 세워놓음
  • 패킷이 나가기 전에 딜레이나, 순서 확인
    이유? 하나의 인터페이스(포트)에 한번에 많은 패킷이 몰려들 수 있음 --> congestion 발생

ex) socket A, B (서로 다른 네트워크 연결임)가 있을 때
하나가 너무 빠르게 보내고 있으면, 다른 소켓의 패킷에게 기회를 줌.

구체적으로, filter, class, policy를 거쳐 NIC로 패킷을 보낸다.

filter : 패킷에 정의된 5-tuple(source IP/port + destination IP/port + protocol) 로 구성된 소켓 정보를 가지고 패킷들을 분류

class : class 간에는 priority 존재

policy : class 간 처리 순서나 딜레이를 주는 방식에 대한 정책

policy 1. pfifo_fast (default 값)

priority에 기반한 fifo.
class로는 FIFO queue로 구현된 3개의 band 사용. *priority : band 0 > band 1 > band 2
packet의 priority는 ToS(Type of Service) 필드를 확인.
0x1C : Interactive(실시간성) + high throughput + reliable -> band 0
0x00 : default -> band 1
0x0E : Cheap + high throughput + reliable -> band 2

policy 2. SFQ(Stochastic Fair Queuing)

모든 소켓(또는 flow)의 패킷이 동일하게 취급받음.
hash()값을 기반으로 enqueue. 해시 값은 5-tuple 로 계산되기 때문에, 같은 flow의 경우 같은 hash값을 가져, 같은 queue에 들어감.
round-robin 방식으로 구현.
hash 함수에 쓰이는 seed값을 randomized hash seed로 사용해, 특정 flow가 독점하지 못하게 함. ( 이름이 Stochastic 인 이유)

policy 3. TBF(Token Bucket Filter)

queue에서 나가는 속도를 조절하기 위한 방법.
일단은 패킷들이 FIFO로 queue에 들어옴.
bucket 이라는 이름의 queue가 있음. 안에는 token이 일정 주기로 채워짐. queue에서 빠져나가려면 이 토큰을 사용해야함. ex) 1byte당 토큰 1개 사용.
토큰이 없을 경우, 토큰이 채워질 때까지 기다려야 함.

나만의 policy 새로 만드는 방법 ex) 모든 패킷을 100ms 씩 늦게 전송하기

$ sudo tc qdisc add dev <your interface> root netem delay 100ms
tc : qdisc를 구성할 수 있는 user-mode tool
qdisc : 스케줄러 수정하겠다는 명령어
add : 새 규칙 생성
dev <your interface> : your interface라는 규칙 생성
root : 루트 qdisc를 설정 (egress, 즉 송신 방향)
netem : 네트워크 에뮬레이터 (지연, 손실, 패킷 재정렬 등 가짜 네트워크 조건 부여)
delay 100ms : 지연 생성

RX routine

device driver로 부터 들어온 데이터를 처음으로 처리하는 layer이다.

netif_receive_skb()

  • NIC의 device driver로 부터 패킷이 처음 네트워킹 스택으로 들어온 것이다.
  • L2 header확인 후, 적절한 L3 프로토콜 (e.g. IP)을 결정해, 알맞은 함수를 호출한다.
  • IPv4 인 경우 ip_rcv() 호출.
profile
¡Salid y Disfrutad!

0개의 댓글