컴퓨터/Linux

Linux Network Device Driver

빵케잌 2020. 6. 14. 22:49

NIC(Network Interface Card)
  - Network Adapter라고도 불린다.(= Hardware)
  - 실제 하드웨어이고, 커널에서 표현하는 data structure가 struct net_device라고 한다.
  - 하드웨어를 sw적으로 구동해주기 위해 Network Device Drivers가 있다.

 

1. NIC

* Network Adapter
  - data-signal conversion을 한다. (wireless, token-ring 등에 맞게 신호를 만들어 준다.) -> 전기 신호
  - shared media의 경우 처리를 할 수 있다.(Ethernet 헤더의 preamble : 두 개의 호스트가 동시에 보낼 때 충돌인지를 판단하는 시간 : 하나의 호스트가 보내면 preamble 시간 이후에 다른 호스트가 보내야 함) -> H/W적으로 처리.

* Network Devices (= Device layer)
 - 제어하기 위한 Abstraction, interface(data structure)

* Device Driver 
 - H/W마다 다 다르다.

 

2. Network Adapter

* low-level address(Ethernet의 경우 MAC)을 가지고 패킷을 판단하는 시스템

* 동의어 : Network Interface Controller, Network Interface Card, NIC, LAN adapter, LAN card

 

3. Network Adapter Interconnection

* motherboard로의 연결
 - chipset에 포함되어 있고, PCI, PCIE bus(I/O버스에 해당)를 통해 연결되어 있다.

 

4. Network Devices

* 정의 : protocol(SW) 과 network adapter(HW) 사이의 interface
           asynchronous input and output

* file system으로 abstract이 안 된다.
  다른 디바이스들과 달리 read-write operation으로 될 수 없다.

 

5. net_device structure

* 디바이스(어댑터 자체)를 나타내는 구조체. (network stack까지 내려올 때는 sk_buff 구조체를 기반으로 패킷 처리)
  어댑터를 제어하기 위한 함수도 가지고 있다.

 

6. Network Device Driver

* Implements vendor specific packet processing : 드라이버는 표준화할 수 없다. net_device가 표준화되어있고 벤더별로 처리하기 위한 드라이버의 함수들은 H/W dependent하다. 커널의 입장에서는 함수를 hook해서 사용.

* Included in the drivers/net directory

* Network Devices(dev.c와 net_device) : adapter-independent
  그 아래에 Device Driver(driver.c) : adapter-specific 에서 실제적인 H/W를 동작시킨다.

 

7. Driver<-> Network Adapter Interface

* Drivers -> device
 - memory-mapped control status registers에 명령어를 write한다.
 - NIC은 그 값에 따라 동작하도록 H/W적으로 설계되어있다.
 - 송신/수신을 위해 만들어진 buffer를 set한다. (buffer descriptor ring으로 만들어졌다)
 - sk_buff에서 쓰는 큐와 driver가 패킷을 보내기 위한 ring은 별도로 관리된다. (전자는 protocol layer에서 후자는 디바이스 드라이버에서 관리)

* Device -> driver
 - control status register에 값을 쓴다.
 - buffer에서 패킷 처리는 DMA로 동작(디바이스는 CPU와 별도로 동작)
 - DMA가 끝나면 generate interrupt
 - descriptor ring에 상태를 업데이트(커널 layer로 패킷이 올라갔으므로 ring에서 빠짐)

 

8. NIC IRQ

* NIC은 interrupt와 밀접한 관련이 있다. packet을 송신/수신 시 interrupt를 발생시키기 때문이다.

* 디바이스 초기화 시 인터럽트 핸들러를 irq에 등록한다.(request_irq)
 - frame 도착 시 인터럽트 핸들러가 불린다.
 - transmission complete, transmission error 등의 다른 이유들로 동일한 핸들러가 불린다.
 - 해제 함수(free_irq)

 

9. Packet Descriptor Rings

* main 메모리와 DMA 엔진 간의 패킷 통신에 쓰인다.

* physical location, length of the data, extra control and status information

 

 

Network Process Contexts from/to Devices

* 크게 두 가지로 쪼개었다.
 - Top half : 짧고 간단하게, 인터럽트에 해당하는 sw 인터럽트를 스케줄한다. 받는 패킷이 들어간 링버퍼를 soft irq에 넘겨준다. -> ISR(Interrupt Service Routine)
 - Bottom half :Top half에서 받은 것으로 실제적인 operation을 처리한다. -> softirqs, tasklets, workqueues

 

1. Interrupt Handling Philosophy in Kernel

* interrupt handler에서 최소의 동작. non-critical한 것들은 나중으로 미루자. -> 패킷하나당 인터럽트가 생기므로 handler가 길어지면 패킷드랍이 발생할 수도 있다.

 

2. Top Half

* Perform minimal, common functions
- unmask interrupt, flag reset 등 간단한 세팅만 한다. soft inturrupt를 schedule(interrupt가 schedule 가능하다는 것은 바로 실행 안되도 된다는 것) 
- It preempts other tasks ( S/W interrupt도 preempt 하기 때문에 Top Half 가 많아지면 dos가 늘어난다)

 

3. Bottom Half

* Mechanisms to defer work later
 - softirqs
 - tasklets (built on top of softirqs)
 - work queues

* All can be interrupted
 - H/W interrupt가 들어올 수가 있음.

* Network transmission and reception is dealt with softirq

* SoftIRQs
 - Statically allocated (at kernel compile time)
 - Can be executed simultaneously on multiple CPUs
 - 먼저 스케줄

* Tasklets
 - 여러 IRQ의 인스턴스를 묶는 것

* Work queue
 - 낮은 priority

4. Softirq
 - code must be re-entrant(시작할 때 stateless, local variable로만 동작

* statically allocated
 - priority가 높은 것이 preempt 한다.
 - 대부분 시스템이 HI > timer > net tx > net rx > block devices 순임. cf) HI는 전원 버튼 같은 것

5. When do softirqs run

* Run at various points by the kernel
 - After interrupts (top halves/IRQs)
 - When the scheduler runs ksoftirqd
   softirq has high priority than user context
 - 

6. Why SoftIRQ

* 인터럽트가 없다면 device lock(net_device 구조체 데이터를 얻는 것)을 얻는 시간이 걸린다.
* DMA buffer -> Kernel buffer -> Protocol stack을 거쳐 -> Socket으로 보내지는 것은 Interrupt Handler에서 일어난다.

7. Multi-queue NIC

* NIC에서 CPU에 할당된 RX Queue로 나뉘어 들어간다.
* RSS(receive side scaling) : 패킷을 H/W 적으로 Hash function을 이용해 나눠줌.

8. LSO & LRO
 Large Receive Offload :
 Large Segment Offload : 

Network Stack에서 쪼개지말고 NIC에서 H/W적으로 쪼갠다. (성능을 높이기 위해서) 받을 때는 패킷을 뭉쳐서 위로 올려준다. encapsulation, decapsulation에 대한 overload가 줄어든다.

9. Checksum Offloading, Promiscuous mode
Checksum Offloading : checksum 계산을 NIC에서 H/W적으로 하자. Network stack의 overload 감소
Promiscuous mode : 나한테 오는 패킷뿐만아니라 모든 패킷을 받자. packet sniffing을 위해 사용된다.