네트워킹과 관련하여 초기화가 어떻게 이루어지는지에 대한 장입니다. 바로 본론으로

Kernel Initialization
출처: Understanding Linux Network Internals
주목해야 할 포인트
do_initcalls() -> free_init_mem()run_init_process()가 init 프로세스를 결정
디바이스가 작동하려면? -> 커널에 인식되어야 하고 올바른 드라이버랑 연결되어야 함
3단계
struct net_device에는 커널이 디바이스 드라이버와 통신하기 위해 이용하는 function pointer들이 있음 (Chapter2 참고) 이걸 초기화하는 것은 장치의 타입(이더넷 등), 브랜드, 모델에 따라 다름. 로직은 다 비슷하므로 이 책에서는 ethernet만을 다룸.
디바이스 드라이버는 device-kernel 커뮤니케이션을 위해 다음과 같은 리소스를 할당한다.
뻔한 두 가지 방식
디바이스 드라이버는 irq를 요청한 후에 해당 irq에 인터럽트 핸들러를 등록/해제하기 위해 다음 두 함수를 사용함.
int request_irq(
    unsigned int irq,
    void (*handler)(int, void*, struct pt_regs*),
    unsigned long irqflags,
    const char * devname,
    void *dev_id
)
void free_irq(
    unsigned_int irq,
    void *dev_id
)
인터럽트를 통해 NIC가 드라이버에 알릴 수 있는 정보 예시
“Interrupt sharing”을 이용하면 하나의 IRQ에 여러 디바이스를 연결시킬 수 있음. 하지만 하나의 shared IRQ에 연결된 디바이스 드라이버가 모두 이 기능을 지원한다고 명시해야만 함.
IRQ 라인은 플랫폼에 따라 정해진 개수만큼만 있기 때문에 여러 디바이스가 하나의 IRQ를 사용하면 리소스를 절약할 수 있는 방법이 된다.
참고: IRQs - X86 Assembly/Programmable Interrupt Controller
Of the 15 usable IRQs, some are universally associated with one type of device:
IRQ 0 ‒ system timer
IRQ 1 — keyboard controller
IRQ 3 — serial port COM2
IRQ 4 — serial port COM1
IRQ 5 — line print terminal 2
IRQ 6 — floppy controller
IRQ 7 — line print terminal 1
IRQ 8 — RTC timer
IRQ 12 — mouse controller
IRQ 13 — math co-processor
IRQ 14 — ATA channel 1
IRQ 15 — ATA channel 2
따라서 디바이스 드라이버가 interrupt sharing을 지원한다는 얘기는 즉, 자신이 등록한 인터럽트 핸들러가 커널에 의해 invoke될 때 무시해도 좋은지 코드를 실행해야 하는지 판단하는 로직이 있다는 얘기임 (디바이스의 레지스트리 값을 보고 판단할 수 있게 되어있다든지)
irqaction 스트럭트로 정의됨.irq_desc가 맵핑 정보를 다 가지고 있음.request_irq()가 맵핑을 irq_desc에 등록(하는 setup_irq() 함수를 호출)irq_desc, setup_irq()는 arch 디렉토리 이하에 아키텍처에 맞게 오버라이딩되어있음.

Organization of IRQ handlers
출처: Understanding Linux Network Internals
끊고 갑시다
커널에 박혀있는 것과 모듈로 로드된 컴포넌트 모두 파라미터를 줄 수 있음. 여기에 쓰이는 두 가지 매크로가 있는데
module_param)모듈을 로드할 때 옵션을 줄 수 있게 한 매크로. 커널에 박아 넣은 컴포넌트에 대해서는 이 옵션의 값들을 부트타임에 줄 수 없음. (참고: /sys 인터페이스)
_ _setup)부트로더를 통해서 부트타임에 줄 수 있는 옵션들을 정의.
두 방식이 다 사용되기 때문에, 커널 부트타임에 정의된 옵션 이름과 모듈 로드타임에 정의된 옵션 이름이 겹칠 수도 있음. 모듈 로드 시 옵션 이름은 해당 모듈에만 적용되는 것임.
pass
커널 모듈은 파라미터를 어떻게 정의할까? -> module_param 매크로를 사용
...
module_param(multicast_filter_limit, int 0444);
module_param(max_interrupt_work, int, 0444);
module_param(debug, int, 0444);
              ^      ^    ^
//          이름  자료형 /sys 파일 퍼미션
...
Understanding Linux Networking Internals에 있는 drivers/net/sis900.c의 예
/sys/modules/[module name]/parameters 에 ls 쳐보면 나옴. 파일 퍼미션을 어떻게 줬느냐에 따라서 읽기, 쓰기가 가능한데 퍼미션을 0으로 주면 아예 /sys에 안나온다. 덮어 쓸 경우 값이 변했다는 노티를 줄 수 있는 방법이 없기 때문에, 모듈이 옵션값의 변화를 감지하는 방법을 만들거나, 중간에 값이 바뀌어도 문제가 없도록 짜야 함.
Traffic Control, per-CPU ingress queues를 포함한 중요한 초기화가 net/core/dev.c에서 일어남.
static int _ _init net_dev_init(void)
{
    ...
}
subsys_initcall(net_dev_init);
net_dev_init()에서 일어나는 일
/proc에 몇 가지 파일을 추가함/sys/class/net 디렉터리를 생성하고 그 하위에 등록된 네트워크 장치마다 subdirectory를 만듦.랜덤값은 타이머에 주어져서 타이머들이 동시에 실행되어 CPU에 부하를 주는 것을 막거나, 특정 data structure의 구조를 알아내려는 DoS 공격을 방지하는 데 쓰일 수 있음.