반응형

개요

17.7 네트워크 인터페이스에 대해서 요악한 정보임.

 

네트워크 인터페이스의 주요 특징

- 네트워크 인터페이스는 문자 또는 블록 디바이스 드라이버와 달리, 디바이스 파일을 사용하지 않음.

 

리눅스의 네트워크 구조

 

- 리눅스의 네트워크 구조는 하드웨어 장치를 제어하는 네트워크 디바이스 드라이버가 있고,

그 위에는 TCP/UDP 등의 IP 기반의 프로토콜이 구현된다.

 

struct sk_buff {
	struct sk_buff *next; /* 다음 소켓 버퍼 리스트 */
	struct sk_buff *prev; /* 이전 소켓 버퍼 리스트 */
	.....
	struct net_device *dev; /* 디바이스 구조체 */
	.....
	unsigned int len; /* 데이터 길이 */
	.....
	unsigned char *head; /* 버퍼의 헤드 포인터 */
	unsigned char *data; /* 유효 데이터 시작 포인터 */
	unsigned char *tail; /* 유효 데이터 마지막 포인터 */
	unsigned char *end; /* 버퍼의 마지막 포인터 */
	.....
}

 

- 네트워크 애플리케이션은, 커널 영역과, 데이터 및 각종 제어 정보를 교환하기 위해,

(1) 소켓과 함께 (2) 네트워크 시스템 콜 함수를 사용함.

 

네트워크 디바이스 드라이버가 가져야할 것

1) 디바이스를 검색해서 커널에 등록하고 하드웨어를 초기화하는 함수.

2) 네트워크 디바이스를 활성화하는 open함수.

3) 네트워크 디바이스를 비활성화하는 stop함수.

4) 패킷을 전송하는 함수.

5) 패킷을 수신하는 함수.

 

네트워크 디바이스 자료 구조.

 네트워크 디바이스는 <linux/netdevice.h> 파일에 선언되어 있는 net_device 구조체를 사용하여,

디바이스 드라이버커널 사이의 인터페이스를 처리한다. (net_device 구조체)

 

 네트워크 디바이스 구조체

1) 디바이스 이름

2) 하드웨어 장치의 주소

3) 사용되는 인터럽트 번호

4) 네트워크 디바이스 동작

5) MTU값

6) 하드웨어 주소

등의 정보로 구성

 

네트워크 디바이스 동작

 네트워크 디바이스 동작은, 문자 디바이스나, 블록 디바이스와 마찬가지로,

커널의 네트워크 계층인터페이스를 제공함.

struct net_device_ops {
        int                     (*ndo_init)(struct net_device *dev);
        void                    (*ndo_uninit)(struct net_device *dev);
        int                     (*ndo_open)(struct net_device *dev);
        int                     (*ndo_stop)(struct net_device *dev);
        netdev_tx_t             (*ndo_start_xmit) (struct sk_buff *skb, struct net_device *dev);
        u16                     (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb);
        void                    (*ndo_change_rx_flags)(struct net_device *dev, int flags);
        void                    (*ndo_set_rx_mode)(struct net_device *dev);
        void                    (*ndo_set_multicast_list)(struct net_device *dev);
        int                     (*ndo_set_mac_address)(struct net_device *dev, void *addr);
        int                     (*ndo_validate_addr)(struct net_device *dev);
        int                     (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
        int                     (*ndo_set_config)(struct net_device *dev, struct ifmap *map);
        int                     (*ndo_change_mtu)(struct net_device *dev, int new_mtu);
        int                     (*ndo_neigh_setup)(struct net_device *dev, struct neigh_parms *);
        void                    (*ndo_tx_timeout) (struct net_device *dev);

        struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev, struct rtnl_link_stats64 *storage);
        struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);

        void                    (*ndo_vlan_rx_register)(struct net_device *dev, struct vlan_group *grp);
        void                    (*ndo_vlan_rx_add_vid)(struct net_device *dev, unsigned short vid);
        void                    (*ndo_vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid);
        /* Several lines omitted */
};

 

 네트워크 디바이스 동작을 모두 구현할 필요는 없다.

하지만, ndo_init, ndo_open, ndo_stop, ndo_start_xmit 등 일부 동작은 반드시 구현해야함.

 

주요 네트워크 디바이스 동작의 함수에 대한 설명.

동작 주요 기능
ndo_init 네트워크 디바이스를 초기화하는 동작으로, 네트워크 디바이스 드라이버가 등록될 때 한번 호출됨.
ndo_uninit 네트워크 디바이스의 등록을 해제할 때 호출됨.
ndo_open 네트워크 디바이스의 동작이 시작될 때, 호출되는 동작으로, ifcnofg 명령으로 네트워크 인터페이스를 시작할 때 호출됨.
ndo_stop 네트워크 디바이스의 동작이 중지될 때, 호출되는 동작으로, ifconfig 명령으로 네트워크 인터페이스를 중지할 때 호출됨.
ndo_start_xmit 패킷 전송이 필요한 경우에, 상위 네트워크 계층에서 호출됨.
ndo_do_ioctl 사용자 영역에서 ifconfig 명령에 의해 ioctl이 호출되면 이 동작이 호출됨.
ndo_tx_timeout 데이터 전송이 안 되어 타임아웃이 발생하는 경우에 호출됨.

 

 또한, 네트워크 장치 드라이버는 소켓 버퍼(socket buffer)라는 특수한 버퍼를 사용함.

소켓 버퍼 네트워크 인터페이스를 통해, 전달되는 데이터를 관리하는 구조체로 <linux/skbuff.h>에 선언됨.

 

 

 

 중요한 것은,

사실상, 네트워크 인터페이스 드라이버를 구현하는데 있어서, 모든 데이터는 위에서 설명한 소켓 버퍼로 처리됨.

따라서, 네트워크 인터페이스 드라이버를 구현하려면, 소켓 버퍼를 사용하는 다양한 방법들에 대한 이해가 필요함.

 

 

패킷의 전송과 수신

 네트워크 인터페이스에서 전송은,

네트워크 계층에서 전달된 데이터네트워크 드라이버의 ndo_start_xmit에 지정된 함수로,

하드웨어 장치에 기록하여, 다른 호스트에 전달하는 동작이다.

 

 수신은, 외부 호스트에서 하드웨어로 입력된 데이터를, 네트워크 계층에 전달하는 동작임.

 

수신 외부 호스트 -> 나의 네트워크 계층
송신 나의 네트워크 계층 -> 외부 호스트

 

 일부 전송 데이터는, 대부분 애플리케이션에서 만들어진다. (커널의 네트워크 계층에서 생성되기도 한다)

수신 데이터 역시, 일부는 커널의 네트워크 계층에서 사용되지만, 대부분은 애플리케이션에 전달된다.

 

 따라서, 애플리케이션커널의 네트워크 계층,

그리고 디바이스 드라이버 사이의 데이터를 일관성 있게 교환하려면, 특별한 관리가 필요함.

 리눅스는, 이와 같이 네트워크 인터페이스를 통해, 전달되는 데이터를 관리하는 데에

sk_buff 구조체를 사용함. (Application <-> Kernel Network layer)

 

 데이터 패킷의 전송은

1) [애플리케이션] 에서, 소켓 API를 사용하여 특정 프로토콜에 맞게 데이터를 만들어, [커널 네트워크 계층] 에 전달함.

2) [커널 네트워크 계층]에서는, 프로토콜의 구조와 맞게, 데이터를 캡슐화함.

그리고, 소켓 버퍼를 할당 (alloc_skb)받아, 데이터 및 데이터의 길이를 포함해, 전송에 필요한 정보를 설정함.

그 후, 원하는 목적지로 전송할 디바이스 드라이버전송 함수(ndo_start_xmit)을 호출함.

3) 디바이스 드라이버 전송 함수에서는, 입력되는 소켓 버퍼의 정보를 이용해,

하드웨어 장치에 데이터를 기록해, 데이터가 전달되도록 함. 

4) 데이터 전달 후에는 사용된 소켓 버퍼를 해제(dev_kfree_skb)함.

 

 

 

 

공부한 책이름

ARM으로 배우는 임베디드 리눅스 시스템 (저자 안효복)

반응형