div id=post-view class=post-view pcol2 pre이야기꾼:이기천(a target=_blank class=con_link href=mailto:hetta@nownuri.net%29hetta@nownuri.net)br/a/prepre+-----------------------------------------------------------------------+br| *강좌에 앞서서.... |br| 이 글은 GFDL(GNU Free Documentation License)을 따릅니다. |br| 그러므로 필자는 이글로 인한 물질적이든 정신적이든 또한 |br| 가정의 불화든지간에 어떠한 책임도 지지 않습니다. |br| 원저자가 명시되는한 비상업적용도에 한하여 |br| 자유로운 배포,수정이가능하지만, |br| 어떠한 수단이든지간에 상업적 용도로 사용되어질수는 없습니다. |br+-----------------------------------------------------------------------+brbrbrlt;참고자료gt; br1.Linux Device Driver 2nd br - http://www.oreilly.com 에서 pdf버전 무료배포br2.Linux Network Device Driver(권수호)br - http://www.linuxdeveloper.co.krbr3.RTL8139C datasheetbr - http://www.realtek.com.tw/br4.(Linux_Kernel_Src_Path)drivers/net/8139too.cbr5.RTL8139 Programming guidebr6.Understanding the Linux Kernelbrbr*환경:kernel 2.4.9 br(다른버전의 커널에서는 조금씩 다를수있음을 유의하시기 바랍니다.)brbr오늘은 이번강의의 첫번째시간입니다.br이번시간엔 먼저 Network Driver에대한 개념을 잡기위하여brLinux Device Driver 2nd의 [chapter 15. Network Drivers]를 기반으로 br이야기를 시작하겠습니다.br언제까지 할것이라는 약속은 못드릴것같습니다.저도 인간이니까요..어쩌면 br이번강의 가 처음이자 마지막일지도 모르겠죠^^ 언제든지 네트워크 드라이버 br분석이 재미(funny)없다면 강의를 그만둘겁니다.(아마 가능성이 희박하겠지만^^)br저도 초보임을 밝히겠습니다. 실제적 device driver를 다루는것은 처음입니다.br그러므로 틀린점이 많을것같습니다...br언제든지 잘못된것은 혼자알지마시고 알려주세여 ~~~~~~~~~!br저는 제가 이해한 방향으로 강좌를 진행하겠습니다.^^br이제부터 존칭은 생략하도록 하겠습니다.^^ 타이핑치기가 힘드러서요.... :Pbr자 그럼 시작합니다. :)brbrbr모듈 올리기br^^^^^^^^^^^^br디바이스 드라이버가 커널에 로딩될때 자기가 사용할 리소스를 커널에 br요청하게 된다. 예를들어 사용할 irq번호와 I/O port를 등록해야한다.br랜카드를 잡을때 다음과 같이 잡는다. 필자의 경우도 ne2000랜카드를 잡을때,br먼저 윈도우로 가서 거기서 io와 irq번호를 알아온다음에 리눅스에서 다음과 br같이 잡았다.(물론 이렇게 잡는것은 isa방식이 대부분이었으나, pci도 이렇게 잡br아야 잡히는 경우를 경험했다.)brbrmodprobe ne.o io=0x100 irq=9brbr이것이 랜카드가 사용할 io와 irq를 명령어 라인 인수로 넘겨받게 되는것이다. br크게 디바이스 드라이버는...br불록(block),문자(character),네트웍 이렇게 3개로 나눈다. 그중에서 불록과 br문자는 주번호와 부번호라는것이 존재하여 디바이스를 제어하나, 네트웍장치는br그러한 개념이 존재하지 않는다.그대신 커널의 어느곳에서도 참조할수있는br전역(global)리스트로 새로운 디바이스장치를 넣게된다. br또한 유닉스(리눅스)에서 는 모든것이 파일이라는 말을 많이 들어보았을것이다.br하지만, 여기서 네트웍장치 는 아쉽게도 예외로서 존재한다. 다른 문자나,블록장br치는 /dev/밑에 실제적인 파일로서존재하나, 네트웍장치만은 거기에 존재하br지 않는다! 뭐.. 예외없는 법칙이 없다는말도 있으니, 잠시 봐주기로 하자..ㅎㅎbr유닉스에서 모든것은 파일이다.(단 네트웍장치만빼고^^)br(주: 네트웍 장치말고 다른것이 있다면 알려주기 바랍니다.)brbr위에서 전역리스트가 존재한다고 하였다. 그렇다면 이 전역리스트의 자료구조는br어떻게 생겼을까? br리눅스는 네트웍 장치에 대한 데이터를 struct net_device로서 관리한다.br이제, LXR로 살펴보도록하자.brlt;참고gt; -----------------------------------------------------------br모르시는 분을 위하여 간단히 쓰겠다.br웹브라우저로 http://lxr.linux.no에가서 browse the code를 누른뒤bridentifier search 를 누르고 검색란에 net_device를 적는다.br이제 net_device를 정의한 다음과 같은 검색결과가 나올것이다.br그것을 누른다.brbrinclude/linux/netdevice.h, line 230 br--------------------------------------------------------------------brbr커널소스를 처음보시는분은 벌써부터 기가 찰지도 모르겠다. 구조체가 자그마치br180라인이니 말이다. 그러나 모든것을 알필요는없다. 필요한것은 필요할때br공부한다는 맘을 갖고, 대충만 훌터보고 넘어가도록하자. 뒤에서 꼭 필요한br필드만을 설명할것이다. (사실 안봐도 이야기 진행상 큰문제는없으니br너무 겁부터 내지는 말기를 바란다.)brbr----------------------------------------------------------------------br/*br * The DEVICE structure.br * Actually, this whole structure is a big mistake. It mixes I/Obr * data with strictly high-level data, and it has to know aboutbr * almost every data structure used in the INET module.br *br * FIXME: cleanup struct net_device such that network protocol infobr * moves out.br */brbrstruct net_devicebr{brbr /*br * This is the first field of the visible part of this structurebr * (i.e. as seen by users in the Space.c file). It is the namebr * the interface.br */br char name[IFNAMSIZ];brbr /*br * I/O specific fieldsbr * FIXME: Merge these and struct ifmap into onebr */br unsigned long rmem_end; /* shmem recv end */br unsigned long rmem_start; /* shmem recv start */br unsigned long mem_end; /* shared mem end */br unsigned long mem_start; /* shared mem start */br unsigned long base_addr; /* device I/O address */br unsigned int irq; /* device IRQ number */brbr /*br * Some hardware also needs these fields, but they are notbr * part of the usual set specified in Space.c.br */brbr unsigned char if_port; /* Selectable AUI, TP,..*/br unsigned char dma; /* DMA channel */brbr unsigned long state;brbr struct net_device *next;brbr /* The device initialization function. Called only once. */br int (*init)(struct net_device *dev);brbr /* ------- Fields preinitialized in Space.c finish here ------- */brbr struct net_device *next_sched;brbr /* Interface index. Unique device identifier */br int ifindex;br int iflink;brbrbr struct net_device_stats* (*get_stats)(struct net_device *dev);br struct iw_statistics* (*get_wireless_stats)(struct net_device *dev);brbr /*br * This marks the end of the visible part of the structure. Allbr * fields hereafter are internal to the system, and may change atbr * will (read: may be cleaned up at will).br */brbr /* These may be needed for future network-power-down code. */br unsigned long trans_start; /* Time (in jiffies) of last Tx */br unsigned long last_rx; /* Time of last Rx */brbr unsigned short flags; /* interface flags (a la BSD) */br unsigned short gflags;br unsigned mtu; /* interface MTU value */br unsigned short type; /* interface hardware type */br unsigned short hard_header_len; /* hardware hdr length */br void *priv; /* pointer to private data */brbr struct net_device *master; /* Pointer to master device of a group,br * which this device is member of.br */brbr /* Interface address info. */br unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */br unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */br unsigned char addr_len; /* hardware address length */brbr struct dev_mc_list *mc_list; /* Multicast mac addresses */br int mc_count; /* Number of installed mcasts */br int promiscuity;br int allmulti;brbr int watchdog_timeo;br struct timer_list watchdog_timer;brbr /* Protocol specific pointers */brbr void *atalk_ptr; /* AppleTalk link */br void *ip_ptr; /* IPv4 specific data */br void *dn_ptr; /* DECnet specific data */br void *ip6_ptr; /* IPv6 specific data */br void *ec_ptr; /* Econet specific data */brbr struct Qdisc *qdisc;br struct Qdisc *qdisc_sleeping;br struct Qdisc *qdisc_list;br struct Qdisc *qdisc_ingress;br unsigned long tx_queue_len; /* Max frames per queue allowed */brbr /* hard_start_xmit synchronizer */br spinlock_t xmit_lock;br /* cpu id of processor entered to hard_start_xmit or -1,br if nobody entered there.br */br int xmit_lock_owner;br /* device queue lock */br spinlock_t queue_lock;br /* Number of references to this device */br atomic_t refcnt;br /* The flag marking that device is unregistered, but held by an user */br int deadbeaf;brbr /* Net device features */br int features;br#define NETIF_F_SG 1 /* Scatter/gather IO. */br#define NETIF_F_IP_CSUM 2 /* Can checksum only TCP/UDP over IPv4. */br#define NETIF_F_NO_CSUM 4 /* Does not require checksum. F.e. loopack. */br#define NETIF_F_HW_CSUM 8 /* Can checksum all the packets. */br#define NETIF_F_DYNALLOC 16 /* Self-dectructable device. */br#define NETIF_F_HIGHDMA 32 /* Can DMA to high memory. */br#define NETIF_F_FRAGLIST 64 /* Scatter/gather IO. */brbr /* Called after device is detached from network. */br void (*uninit)(struct net_device *dev);br /* Called after last user reference disappears. */br void (*destructor)(struct net_device *dev);brbr /* Pointers to interface service routines. */br int (*open)(struct net_device *dev);br int (*stop)(struct net_device *dev);br int (*hard_start_xmit) (struct sk_buff *skb,br struct net_device *dev);br int (*hard_header) (struct sk_buff *skb,br struct net_device *dev,br unsigned short type,br void *daddr,br void *saddr,br unsigned len);br int (*rebuild_header)(struct sk_buff *skb);br#define HAVE_MULTICAST br void (*set_multicast_list)(struct net_device *dev);br#define HAVE_SET_MAC_ADDR br int (*set_mac_address)(struct net_device *dev,br void *addr);br#define HAVE_PRIVATE_IOCTLbr int (*do_ioctl)(struct net_device *dev,br struct ifreq *ifr, int cmd);br#define HAVE_SET_CONFIGbr int (*set_config)(struct net_device *dev,br struct ifmap *map);br#define HAVE_HEADER_CACHEbr int (*hard_header_cache)(struct neighbour *neigh,br struct hh_cache *hh);br void (*header_cache_update)(struct hh_cache *hh,br struct net_device *dev,br unsigned char * haddr);br#define HAVE_CHANGE_MTUbr int (*change_mtu)(struct net_device *dev, int new_mtu);brbr#define HAVE_TX_TIMEOUTbr void (*tx_timeout) (struct net_device *dev);brbr int (*hard_header_parse)(struct sk_buff *skb,br unsigned char *haddr);br int (*neigh_setup)(struct net_device *dev, struct neigh_parms *);br int (*accept_fastpath)(struct net_device *, struct dst_entry*);brbr /* open/release and usage marking */br struct module *owner;brbr /* bridge stuff */br struct net_bridge_port *br_port;brbr#ifdef CONFIG_NET_FASTROUTEbr#define NETDEV_FASTROUTE_HMASK 0xFbr /* Semi-private data. Keep it at the end of device struct. */br rwlock_t fastpath_lock;br struct dst_entry *fastpath[NETDEV_FASTROUTE_HMASK+1];br#endifbr#ifdef CONFIG_NET_DIVERTbr /* this will get initialized at each interface type init routine */br struct divert_blk *divert;br#endif /* CONFIG_NET_DIVERT */br};br----------------------------------------------------------------------brbr실제적인 네트웍장치 등록은 이 net_device의 필드들에 적절한 값을 세팅한다음br다음과 같이 register_netdev()를 호출하는것이다.brbrint result ;brstruct net_device *my_net ;br// my_net그조체에 적절한 값을 채움!brresult = register_netdev( my_net );brbrbrlt;참고gt;----------------------------------------------------------------brLDD(Linux Device Driver) 15챕터에서는 snull이라는 장치를 만드는데,br이장치는 실제적인 하드웨어가 아닌 가상장치이다. 개인적으로 snull이라는br장치가 동작하는방식을 이해하는것은 별 도움이 안되었다. 그래서 br불필요한 혼동을 줄이고자 되도록이면, LDD에 나오는 snull의 설계는 제외하고,br실제적 네트웍장치를 분석하는데 도움이 되는 부분만을 설명할 것이다. br전체적인 흐름을 이해하는것이 중요할것같다.br관심있으신분은 오렐리 사이트에서 snull소스를 다운받아서 살펴보기 바란다.br-----------------------------------------------------------------------brbrbr네트웍 장치를 초기화하기br~~~~~~~~~~~~~~~~~~~~~~~~~brbr이때 snull의 경우 net_device구조체에 지정한 init함수가 초기화를 수행한다.br그함수는 snull_init이며, net_device구조체에 적절한 필드를 채운다.br예를들어 brdev-gt;open = snull_open ; //장치 열때. 아마도 ifconfig eth0 up 일듯?brdev-gt;stop = snull_release ; //장치 닫을때. 아마도 ifconfig eth0 down 일듯?brdev-gt;do_ioctl = snull_ioctl ; //ioctl시스템 콜할때brdev-gt;hard_start_xmit = snull_tx ;brdev-gt;get_stats = snull_stats ;brdev-gt;tx_timeout = snull_tx_timeout ; //Tx타임아웃발생시 호출함수brdev-gt;watchdog_timeo = timeout ; //timeout 되는 시간설정br....brSET_MODULE_OWNER(dev)br등등...bropen은 장치를 열때 실행되는것이며 , hard_start_xmit은 패킷을 전송하기전에br초기화를 하는것이며, get_stats은 장치에 관한 정보를 요청할때 정보를 제공br하는것이다. ifconfig 라는 명령어를 칠때 get_stats가 실행된다고 보면 br될것이다. brSET_MODULE_OWNER()은 net_device의 owner 필드에 이 디바이스 모듈에 대한br포인터로 초기화한다. 모듈의 usage count를 관리하기 위하여, brfile_operations구조체의 owner필드와 똑같이 커널에서 사용한다.brbr예를들자면 ifconfig eth0 up할때 snull_open이 실행되고,brifconfig eth0 down할때 snull_release가 실행된다고 보면 될것이다.brbrlt;참고gt;-----------------------------------------------------------------br하지만, 실제 8139too.c에서는 약간 다른방식을 사용하는것으로 보인다. 즉,br장치를 초기화 하는것이 net_device의 init필드를 사용하는것이 아니라,brpci_driver 의 probe를 사용한다는것이다.( rtl8139_init_one() ) br하지만 하는 작업은 비슷하다고 생각하면 될것같다. rtl8139_init_one(...)에서br결국 net_device를 채운다음 register_netdev()를 호출한다.br-----------------------------------------------------------------------brbr주의할점은 irq와 io같은 중요한 리소스는 init하는시점이 아닌 open시점에 br리소스를 확보해야한다는것이다. 왜냐하면 그렇지 않을경우 실제로 사용되지도br않는 장치에 할당된 io와 irq때문에 다른장치를 쓰지 못하는경우도 발생할수있기br때문이다.brbr또한 net_device에는 priv라는 필드가 있다. 이것은 각각의 장치가 관리하는brprivate한 자료등을 관리하게 된다. 이것은 장치를 open하는 시점이 아니라brinit할때 실행해야한다.왜냐하면 priv에는 각종통계정보에 유용한 값들이 있는데br사용자는 장치가 활성화되지 않았을때라도 그정보를 보기 원할수있기 때문이다.brbrsnull의 경우에는 다음과 같은 필드들이 있다.brbr------------------------------------------------------------------br/*br * This structure is private to each device. It is used to passbr * packets in and out, so there is place for a packetbr */brbrstruct snull_priv {br struct net_device_stats stats;br int status;br int rx_packetlen;br u8 *rx_packetdata;br int tx_packetlen;br u8 *tx_packetdata;br struct sk_buff *skb;br spinlock_t lock;br};brbr여기서 새로운 구조체가 나오는데 net_device_stats로서br말그대로 네트웍장치에대한 통계자료를 관리한다.br-----------------------------------------------------------------br/*br * Network device statistics. Akin to the 2.0 ether stats butbr * with byte counters.br */brbrstruct net_device_statsbr{br unsigned long rx_packets; /* total packets received */br unsigned long tx_packets; /* total packets transmitted */br unsigned long rx_bytes; /* total bytes received */br unsigned long tx_bytes; /* total bytes transmitted */br unsigned long rx_errors; /* bad packets received */br unsigned long tx_errors; /* packet transmit problems */br unsigned long rx_dropped; /* no space in linux buffers */br unsigned long tx_dropped; /* no space available in linux */br unsigned long multicast; /* multicast packets received */br unsigned long collisions;brbr /* detailed rx_errors: */br unsigned long rx_length_errors;br unsigned long rx_over_errors; /* receiver ring buff overflow */br unsigned long rx_crc_errors; /* recved pkt with crc error */br unsigned long rx_frame_errors; /* recv'd frame alignment error */br unsigned long rx_fifo_errors; /* recv'r fifo overrun */br unsigned long rx_missed_errors; /* receiver missed packet */brbr /* detailed tx_errors */br unsigned long tx_aborted_errors;br unsigned long tx_carrier_errors;br unsigned long tx_fifo_errors;br unsigned long tx_heartbeat_errors;br unsigned long tx_window_errors;brbr /* for cslip etc */br unsigned long rx_compressed;br unsigned long tx_compressed;br};br-----------------------------------------------------------------------brbr뭐 간단히 예를 들자면 패킷을 받다가 메모리가 꽉차서 drop되었다면 rx_droppedbr필드를 하나 증가시켜주는 그냥 이런식이다.brifconfig명령을 내리면 랜카드에대한 각종 통계치가 나오는데 이런통계자료를br바탕으로 출력되는것이다.brbreth0 Link encap:Ethernet HWaddr 00:50:FC:0C:ff:f1br ...br RX packets:894551 errors:0 dropped:0 overruns:0 frame:0br TX packets:686533 errors:0 dropped:0 overruns:0 carrier:0br collisions:0 txqueuelen:100 br Interrupt:5 Base address:0xac00 brbrbrbrbrprivate한 구조체를 관리하려면 당연히 먼저 메모리공간을 확보해야한다.br다음과 같이 한다.brbrdev-gt;priv = kmalloc(sizeof(struct snull_priv), GFP_KERNEL);brif( dev-gt;priv == NULL )br return -ENOMEM ;brmemset( dev-gt;priv, 0 sizeof(struct snull_priv));brspin_lock_init( amp;((struct snull_priv *) dev-gt;priv)-gt;lock ) ;brbr마지막에서 spin_lock_init()은 스핀락인 snull_priv의 lock을 초기화하는것이다.br일단 스핀락은 그냥 race condition을 방지하는것이라고만 이해하도록 하자.brbrbr모듈내리기 br^^^^^^^^^^^br모듈을 내리려면 다음과 같이 priv에 할당된 메모리를 해제하고 brunregister_netdev()로서 네트웍장치의 등록을 해제한다.brbrbrvoid snull_cleanup(void)br{ br int i;br br for (i=0; ilt;2; i++) {br kfree(snull_devs[i].priv);br unregister_netdev(snull_devs + i);br }br return;br}brbrbrbrbrnet_device구조체에 대해서...br~~~~~~~~~~~~~~~~~~~~~~~~~~~~br위에서 net_device에 대하여 조금 언급하였다.여기서는 조금더 깊이 들어가br보도록 하겠다.brbr이 구조체는 위에서 보았듯이 상당히 길이가 길다. 크게 두가지로 나뉘는데,br첫번째는 보이는(visible)필드과 숨겨진(hidden)필드이다.보이는 필드는 그냥brstatic구조체에 명시적으로 값을 할당할수있는 필드들로 구성된다.(the visiblebrpart of the structure is made up of the fields that can be explicitly brassigned in static net_device structure )br그냥 쉽게 말해 보이는필드는 우리가 신경써야되는부분이며, 숨겨진 필드는 br커널에서 내부적으로 사용되는것이라 생각하면 될것같다.brbr먼저 보이는필드를 살펴보자.brbrbrchar name[IFNAMSIZ];br 이것은 장치의 이름을 지칭한다. 예를들어 이더넷장치로 eth0,eth1,eth2등을br 보았을것이다. 여기에 %d를 넣으면 0부터 장치이름이 지어진다.br 즉 eth%d로 한다면 맨 첫번째 장치는 eth0가되고 그담이 eth1...이런식이다.brbrunsigned long rmem_end ;brunsigned long rmem_start;brunsigned long mem_end ;brunsigned long mem_start ;br장치가 사용하는 메모리 정보이다. 만약 패킷을 받을때 사용되는 rx와 br패킷을 보낼때 사용하는 tx에서 다른영역이 할당되었다면 rmem_ 은 rx를 의미하고brmem_은 tx를 의미한다. mem_start, mem_end는 부팅할때 명령어 라인에서br지정할수있으며, 그값은 ifconfig로서 확인할수있다. end - start함으로서br사용되는 메모리를 확인할수있다.brifconfig의 맨페이지에 다음과 같은 설명이 나온다.br mem_start addrbr Set the start address for shared memory used bybr this device. Only a few devices need this.br즉 mem_start를 이용해 ifconfig에서 값을 변경할수있다는것이다.brbrbrunsigned long base_addr ;brbr랜카드가 사용하는 I/O 주소이다.이것도 ifconfig로 확인가능하다.brbrunsigned char irq ;brbr할당된 인터럽트 번호이다. ifconfig로 확인가능하다.brbrunsigned char if_port ;br이것은 두개이상의 포트가 있는 랜카드의 경우 어느것이 사용되는가를 나타낸다.br예를들어 coaxial , twisted-pair의 두개가 있을경우이다.br(IF_PORT_10BASE2 , IF_PORT_10BASET )brbrunsigned char dma ;br장치에 할당된 dma채널이다.이것은 isa의 경우에 쓰이며 pci는 안쓰인다.brbrunsigned long state ;br장치의 상태이다.이값은 보통 직접 접근하여 수정하지 않고, 이값을 관리하는br함수가 따로 존재한다.brbrstruct net_device *next ;br앞에서 네트웍장치는 전역 리스트로 관리된다고 했다. 이것은 그 전역리스트에서br다음 장치를 지칭한다. 이것은 수정되어서는 안된다.brbrint (*init)(struct net_device *dev)br초기화 함수이다. (참고: rtl8139는 이걸 사용하지 않는다.)brbrbrbr이제 숨겨진 필드들을 살펴보도록 하자.br일반적으로 이 필드들은 드라이버를 초기화할때 할당된다.brbrunsigned mtu ;brmaximum transfer unit(MTU)이다. 이것은 network layer에서 사용되는것이다.br즉, IP layer 에서의 패킷의 크기를 제한하는데 이더넷의경우 1500이다.br그렇다면 실제적으로 네트웍라인상에 보내지는 패킷의 최대크기는 몇일까?brmtu(1500) + ethernet header(14) + pad(4) = 1536이다.brbrunsigned long tx_queue_len ;br장치의 전송큐에 넣을수있는 최대한의 프레임수이다.이값은 이더넷의경우br100으로 할당되어있으나,변경할수도있다. ifconfig로 확인가능하다.brbreth0 Link encap:Ethernet HWaddr 00:50:FC:0C:ff:ff br ...br collisions:0 txqueuelen:100 br Interrupt:5 Base address:0xac00 brbrbrbrunsigned char addr_len ;brunsigned char broadcast[MAX_ADDR_LEN];brunsigned char dev_addr[MAX_ADDR_LEN];brbraddr_len은 주소의 길이로 이더넷의경우 6 옥텟(octets)이다.brbroadcast는 6개의 옥텟이 0xff로 채워짐으로서 이뤄진다.brdev_addr 은 하드웨어 주소를 나타내는것으로 이값은 랜카드마다 고유하게 br갖고있게되며, 모듈초기화시 랜카드의 EEPROM에서 읽어오게된다.brbrlt;참고gt;---------------------------------------------------------br네트웍에서는 byte대신 octet이라는 용어가 사용된다.br그냥 똑같이 이해하면 별상관은 없을것이다.br---------------------------------------------------------------brbrbrunsigned short flags ;brbr이 플래그는 각각의 장치의 독특한 속성을 지정하게 된다.br앞에 IFF_라는 prefix가 있으며, lt;linux/if.hgt;에 모두 선언되어있다.br몇몇은 커널에의해 내부적으로 사용되고,몇몇은 초기화시 사용된다.br다음과 같은 값들이 가능하다.brbrbr----------------------------------------------------------------------br/* Standard interface flags. */br#define IFF_UP 0x1 /* interface is up */br#define IFF_BROADCAST 0x2 /* broadcast address valid */br#define IFF_DEBUG 0x4 /* turn on debugging */br#define IFF_LOOPBACK 0x8 /* is a loopback net */br#define IFF_POINTOPOINT 0x10 /* interface is has p-p link */br#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */br#define IFF_RUNNING 0x40 /* resources allocated */br#define IFF_NOARP 0x80 /* no ARP protocol */br#define IFF_PROMISC 0x100 /* receive all packets */br#define IFF_ALLMULTI 0x200 /* receive all multicast packets*/brbr#define IFF_MASTER 0x400 /* master of a load balancer */br#define IFF_SLAVE 0x800 /* slave of a load balancer */brbr#define IFF_MULTICAST 0x1000 /* Supports multicast */brbr#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_MASTER|IFF_SLAVE|IFF_RUNNING)brbr#define IFF_PORTSEL 0x2000 /* can set media type */br#define IFF_AUTOMEDIA 0x4000 /* auto media select active */br#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses*/br------------------------------------------------------------------------br다른값들은 참고만하고 IFF_PROMISC,IFF_ALLMULTI 플래그는 꼭 알아두자.br왜냐하면 우리가 분석할 8139too.c에서 사용되기 때문이다.brbrIFF_PROMISC 이것은 자기의 하드웨어 주소에 해당하는 패킷뿐아니라.br 랜에 돌아다니는 모든 패킷을 잡는 것이다. br tcpdump는 이플래그를 이용하여 패킷을 모두 잡는다.brbrIFF_MULTICAST 멀티캐스트 패킷을 보내는것을 가능하게한다. 이것은 디폴트로 br 허용이므로 만일 멀티캐스트패킷을 보내지 못하도록하려면,br 초기화시 이플래그를 꺼주어야한다.brbrIFF_ALLMULTI 모든 멀티캐스트 패킷을 받도록한다.커널은 해당 호스트가br 멀티캐스트 라우팅을 할때, IFF_MULTICAST가 켜져있는때에 한하여br 이 플래그를 세팅한다. 이값은 read-only이다.brbrbr이러한 플래그들이 수정되면 제일먼저 net_device의 set_multicase_list가br실행된다.그러므로 플래그가 변경되었을때 실행되야할 작업이 있다면brset_multicast_list에 넣도록한다.brbrbrbrbr* 이제 net_device필드들중에서 함수들을 살펴보도록하자.이미 몇가지는br 앞에서 언급했지만,다시한번 살펴보는 마음으로 살펴보도록하자.brbr블록이나 문자장치와 같이 네트웍장치도 장치를 다루는 여러가지 함수들이br존재한다. 문자나 블록장치는 file_operations구조체에 이값들을 세팅하나,br네트웍장치는 net_device구조체에 세팅한다. 이값들중 어떤값은 NULL로 세팅br할수도 있다. 그럼 하나하나 알아보도록하자.brbrint (*open)(struct net_device *dev);br ifconfig eth0 up 과 같은 명령을 했을때 실행되는 함수이다. 여기서는 br I/O ports , IRQ, DMA등의 리소스를 등록,usage count증가 등의 작업을 한다.brbrint (*stop)(struct net_device *dev);br ifconfig eth0 down과 같은 명령을 했을때 실행되며, open에서 할당받은 리소스br 들을 반납하는 작업등을 한다.brbrint (*hard_start_xmit)(struct sk_buff *skb, struct net_device *dev)br 패킷을 외부로 전송하기위한 초기화 작업을 실행한다. 외부로 보내질 br 모든데이터는 sk_buff구조체에서 관리한다.brbrbrvoid (*tx_timeout)(struct net_device *dev);br 패킷을 전송하는것에 대한 timeout이다. 즉, 설정된 시간만큼 기다렸는데,br 패킷이 전송되지 못했다면, 재전송등, 어떠한 작업을 해주어야 한다.brbrbrstruct net_device_stats *(*get_stats)(struct net_device *dev );brbr 장치에대한 정보를 요청할때 이함수가 실행된다. 예를들어...br ifconfig, netstat -i 등이 되겠다.brbrbrint (*do_ioctl)(struct net_device *dev, struct ifreg *ifr, int cmd);br ioctl명령어.사용하지 않을려면 NULL로 지정해도 상관없다.brbrbrvoid (*set_multicast_list)(struct net_device *dev);br 네트웍장치에대한 멀티캐스트 리스트(multicast list)가 변경되었거나 br 플래그가 변경되었을때 실행된다.brbrbrbr*이제 장치에대한 유용한 정보등을 포함한 잡다한 필드들을 알아보자.brbrbrunsigned long trans_start ;brunsigned long last_rx ;brbr trans_start는 전송을 전송한 시간을 jiffies값으로 갖고있고, last_rx는 br 가장 최근에 패킷을 받은 시간을 jiffies값으로 갖고있다.brbrbrint watchdog_timeo ; brbr 이값도 jiffies값으로 지정되며, 이 시간동안 전송되지 못했다면, tx_timeoutbr 함수가 실행된다.brbrbrvoid *priv ;br 장치의 private 데이터를 저장하는곳이다.brbrbrstruct dev_mc_list *mc_list ;brint mc_count ;brbr 이두개의 필드는 멀티캐스트 전송을 관리하는데 사용된다.brbrbr여기서 설명하지 않은 net_device 필드들이 많이 있지만, 그것들은 네트웍 드라이br버에 사용되지 않는다. 또한 네트웍 드라이버에 사용된다 하더라도,br우리의 목표인 8139too.c에 사용되지 않는것은 배제하였다. br필요한것은 필요한때... ^_^brbr그럼 다음시간에.... :)brbrbrbrbr brbrbr『리눅스 학당-리눅스 강좌 / 연재 (go LINUX)』 737번br 제 목:[강좌]Network Device Driver만들기 [2] br 올린이:hetta (이기천 ) 01/10/21 17:42 읽음:109 관련자료 없음br -----------------------------------------------------------------------------brbr########################################br#강좌: Network Device Driver만들기 #br# (부재: 애인만들기) #br########################################br1부: 네트워크 드라이버의 기본(2)br^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^br 이야기꾼:이기천(hetta@nownuri.net)brbrbr네트웍장치를 열기와 닫기br~~~~~~~~~~~~~~~~~~~~~~~~br이부분은 조금 중복되는내용도 있다. 정리하는기분으로 보면될것같다.brifconfig eth0 111.111.111.111 up 이런식으로 했을때 다음과 같은 두가지 사건이br발생한다.br첫째로 ioctl(SIOCSIFADDR)로 인터페이스주소를 세팅한다. 이것은 드라br이버에서 구현하는것이 아니라 커널에서 하는작업이다. br둘째로, ioctl(SIOCSIFFLAGS)를 사용하여 dev-gt;flag를 IFF_UP으로 만든다.랜카드br를 쓸수있도록 활성화시키는것이다. 그다음 net_device에서 정의한 open함수를br실행한다.brbropen은 저번시간에도 설명했듯이, 장치가 필요로하는 각종 리소스들을 할당받는br다.그밖에도 여러가지 작업이 Open에서 실행된다.br첫째,하드웨어 주소를 dev-gt;dev_addr 에 복사한다.brbr둘째, open에서는 인터페이스의 전송큐(interface's transmit queue)를 시작하기br위하여 netif_start_queue(struct net_device *dev); 를 호출하게 된다. 이작br업이 실행되어야 패킷을 외부로 전송할수가 있기때문이다.brbrifconfig eth0 down 등의 명령을 할때 close함수가 실행되고 이때는,brnetif_stop_queue()를 호출한다. 이것은 netif_start_queue()와 반대가 되는 br작업으로 패킷을 더이상 전송할수없도록 한다.brbrbr패킷전송하기br~~~~~~~~~~~~~br결국 네트웍 디바이스 드라이버는 무슨일을 할까? br잘받고, 잘보내고, 이러는것이 드라이버가 하는 일의 전부가 아닐까한다. br나머지들은 이러한 작업들을 효율적으로 하도록 도와주는 역활을 하는것이다.br패킷을 받는것보다 보내는것이 더 쉽기때문에 보내는것을 먼저 알아보자.brbr패킷을 전송할필요가 있을때마다, hard_start_transmit 함수가 호출된다.이함수br가 하는일은 나가는큐(outgoing queue)에다가 데이터를 놓는것이다.brbr소켓버퍼(socket buffer)는 struct sk_buff 구조체로 만들어진다.br즉 하나의 패킷은 sk_buff구조체로 표현된다고 할수있다. 다음과 같이 생겼다br---------------------------------------------------------------------brstruct sk_buff {br /* These two members must be first. */br struct sk_buff * next; /* Next buffer in list */br struct sk_buff * prev; /* Previous buffer in list */brbr struct sk_buff_head * list; /* List we are on */br struct sock *sk; /* Socket we are owned by */br struct timeval stamp; /* Time we arrived */br struct net_device *dev; /* Device we arrived on/are leaving bybr*/brbr /* Transport layer header */br unionbr {br struct tcphdr *th;br struct udphdr *uh;br struct icmphdr *icmph;br struct igmphdr *igmph;br struct iphdr *ipiph;br struct spxhdr *spxh;br unsigned char *raw;br } h;brbr /* Network layer header */br unionbr {br struct iphdr *iph;br struct ipv6hdr *ipv6h;br struct arphdr *arph;br struct ipxhdr *ipxh;br unsigned char *raw;br } nh;brbr /* Link layer header */br unionbr {br struct ethhdr *ethernet;br unsigned char *raw;br } mac;brbr struct dst_entry *dst;brbr /* br * This is the control buffer. It is free to use for everybr * layer. Please put your private variables there. If youbr * want to keep them across layers you have to do a skb_clone()br * first. This is owned by whoever has the skb queued ATM.br */br char cb[48];brbr unsigned int len; /* Length of actual data */br unsigned int data_len;br unsigned int csum; /* Checksum */br unsigned char __unused, /* Dead field, may be reused */br cloned, /* head may be cloned (check refcnt to be sure).br*/br pkt_type, /* Packet class */br ip_summed; /* Driver fed us an IP checksum */br __u32 priority; /* Packet queueing priority */br atomic_t users; /* User count - see datagram.c,tcp.c */br unsigned short protocol; /* Packet protocol from driver. */br unsigned short security; /* Security level of packet */br unsigned int truesize; /* Buffer size */brbr unsigned char *head; /* Head of buffer */br unsigned char *data; /* Data head pointer */br unsigned char *tail; /* Tail pointer */br unsigned char *end; /* End pointer */brbr void (*destructor)(struct sk_buff *); /* Destruct functionbr*/br#ifdef CONFIG_NETFILTERbr /* Can be used for communication between hooks. */br unsigned long nfmark;br /* Cache info */br __u32 nfcache;br /* Associated connection, if any */br struct nf_ct_info *nfct;br#ifdef CONFIG_NETFILTER_DEBUGbr unsigned int nf_debug;br#endifbr#endif /*CONFIG_NETFILTER*/brbr#if defined(CONFIG_HIPPI)br union{br __u32 ifield;br } private;br#endifbrbr#ifdef CONFIG_NET_SCHEDbr __u32 tc_index; /* traffic control index */br#endifbr};brbr--------------------------------------------------------------------------brbr물론 이런 필드들을 다 알아야만 한다는것은 아니다. sk_buff구조체는 상당히 br복잡한 구조체이므로 이것을 다루는 다양한 함수들이 제공되며 뒤에서 설명할br것이다. struct sk_buff를 참조할때 skb를 사용하겠다.brbrhard_start_xmit이 호출될때 전달되는 socket buffer는 완벽한 패킷의 형태를br갖게된다.즉, 인터페이스(랜카드)에서 어떠한 데이터 수정도 필요가 없다.br그냥 비트의 연속이라고 생각하고 전송하면 된다. skb-gt;data는 전송되어지는br패킷의 데이터를 가르킨다.skb-gt;len은 길이를 나타내며 단위는 옥텟(바이트)이다.brbrsnull에서는 snull_tx로 패킷전송을 처리한다.brsnull에 대해 세부적으로 알려고 할필요는 없다고 본다. 그러나 전체적인 흐름은br실제 드라이버와 비슷하므로 여기서 보도록 하자.brbr저번시간에 나왔듯이 초기화시 snull_init에서 다음과 같은 세팅을 한다.brbrint snull_init(struct net_device *dev)br{br ...br dev-gt;open = snull_open;br dev-gt;stop = snull_release;br dev-gt;set_config = snull_config;br dev-gt;hard_start_xmit = snull_tx;br dev-gt;do_ioctl = snull_ioctl;br ...br}brbr여기서 dev-gt;hard_start_xmit 이 snull_tx로 세팅되었음을 볼수있다.br그러므로 커널은 패킷을 전송해야할경우에 snull_tx를 호출하게 된다.brsnull_tx의 구현을 살펴보도록 하자.brbr-----------------------------------------------------------------------br/*br * Transmit a packet (called by the kernel)br */brint snull_tx(struct sk_buff *skb, struct net_device *dev)br{br int len;br char *data;br struct snull_priv *priv = (struct snull_priv *) dev-gt;priv;brbr len = skb-gt;len lt; ETH_ZLEN ? ETH_ZLEN : skb-gt;len;br data = skb-gt;data;br dev-gt;trans_start = jiffies; /* save the timestamp */brbr /* Remember the skb, so we can free it at interrupt time */br priv-gt;skb = skb;brbr /* actual deliver of data is device-specific, and not shown here */br snull_hw_tx(data, len, dev); //무시하자.brbr return 0; /* Our simple device can not fail */br}br---------------------------------------------------------------------brsnull에서는 가상장치이므로 하드웨어장치에 대한 실제적전송을 snull_hw_tx()로br표현하였다. 실제적 하드웨어 전송은 DMA등을 사용하여 전송한다.일단무시하자.brbrbrbr실제적 상황에서 발생할수있는 문제br~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~brhard_start_xmit함수는 net_device의 xmit_lock로 race condition문제를 해결함br을 저번시간에 보았다. 그러나 이전작업이 끝나면 곧바로 다시 호출된다.br메모리가 부족하거나, 다른 곳에서 그시간에 패킷이 전송중이라면 잠시 전송을br지연할필요가 있다. 이때 netif_stop_queue를 사용한다. 또한 전송이 가능해지면brnetif_wake_queue를 호출한다.brbrvoid netif_wake_queue( struct net_devic *dev);brbrnetif_wake_queue는 netif_start_queue와 비슷하나, netif_wake_queue는 다시br전송을 가능하게 해준다는것이 가능하다.br요즘나오는 하드웨어는 전송큐를 여러개 갖고있다. RTL8139에서도 4개의 전송큐br를 관리함을 확인할수있다.brbrbr전송 타임아웃br~~~~~~~~~~~~~~~br실제 네트웍상황은 예측불허이므로 여러가지 요인으로 패킷 전송을 확인하는 brack가 안올수도 있다.br이럴경우, 만약 타임아웃값을 세팅해두지 않는다면 무한정으로 패킷전송 확인br패킷을 기다리게 된다. br저번시간에도 나온내용이지만 리눅스는 타임아웃값을 세팅함으로 이것을 방지br한다. br패킷이 dev-gt;trans_start에 세팅한 값부터 dev-gt;watchdog_timeo 값에 세팅한 brjiffies값만큼기다려도 패킷전송 확인이 안될경우 brdev-gt;tx_timeout함수가 호출된다.brbrsnull의 경우는 snull_tx_timeout함수가 호출된다.br다음과 같이 구현되었으며, 대충 흐름만을 알아보도록하자.brbr------------------------------------------------------------------br/*br * Deal with a transmit timeout.br */brvoid snull_tx_timeout (struct net_device *dev)br{br struct snull_priv *priv = (struct snull_priv *) dev-gt;priv;brbr PDEBUG(Transmit timeout at %ld, latency %ld\n, jiffies,br jiffies - dev-gt;trans_start);br priv-gt;status = SNULL_TX_INTR;br snull_interrupt(0, dev, NULL);br priv-gt;stats.tx_errors++;br netif_wake_queue(dev);br return;br} br------------------------------------------------------------------brbr타임아웃이 발생하면 놓친 인터럽트를 채우기위하여 snull_interrupt를 호출br한다. 그리고 다시한번 전송을 시도하게 된다.br( when a timeout happens in snull, the driver calls snull_nterrupt brto fill in the missing interrupt and restarts the transmit queu brwith netif_wake_queue.)brbrbrbr패킷 받기br~~~~~~~~~~br이제 패킷을 어떻게 받을것인가를 알아보도록하자.패킷을 받는것은 전송하는것br보다 조금 복잡하다. 사실 실제 하드웨어에서 하는작업은 많이 틀리므로 brsnull의 것을 보는것이 별도움은 안되겠지만, 흐름만을 알아보자.br먼저 랜카드에서 받은 패킷을 저장할 sk_buff를 할당해야한다.패킷을 받는것은brinterrupt를 통해서이다. 즉, 랜카드에서 어느 일정량이상 데이터가 오면, 랜카드br가 인터럽느를 발생한다.그러면 드라이버에서 작업을 처리하는식이다. 어느 일정br량이라는것은 임으로 설정이 가능하다. br물론 polling 방식으로 패킷받기를 처리하는것도 가능하나 효율성면에서brinterrupt를 이용한 방식이 유리하다.대부분하드웨어가 interrupt를 사용한다.brbr-----------------------------------------------------------------br/*br * Receive a packet: retrieve, encapsulate and pass over to upper levelsbr */brvoid snull_rx(struct net_device *dev, int len, unsigned char *buf)br{br struct sk_buff *skb;br struct snull_priv *priv = (struct snull_priv *) dev-gt;priv;br br /* br * The packet has been retrieved from the transmissionbr * medium. Build an skb around it, so upper layers can handle itbr */br skb = dev_alloc_skb(len+2);br if (!skb) {br printk(snull rx: low on mem - packet dropped\n);br priv-gt;stats.rx_dropped++;br return;br }br skb_reserve(skb, 2); /* align IP on 16B boundary */br memcpy(skb_put(skb, len), buf, len);brbr /* Write metadata, and then pass to the receive level */br skb-gt;dev = dev;br skb-gt;protocol = eth_type_trans(skb, dev);br skb-gt;ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */br priv-gt;stats.rx_packets++;br priv-gt;stats.rx_bytes += len;br netif_rx(skb);br return;br}br-----------------------------------------------------------------br먼저 dev_alloc_skb를 사용하여 skb를 위한 공간을 마련한다. 여기서 +2는br16비트로 정렬하기 위하여 필요한 작업이다.왜냐하면 이더넷헤더는 14비트br이기때문이다. 그다음 skb_reserve로 앞에 2비트를 예비해둔다. 그다음 memcpy를br사용하여 buf의 데이터를 복사하게 된다. skb_put()은 skb의 뒤에 데이터를br붙이고자 할때 사용한다. 앞에서 2비트를 예비했으므로 그다음에 이더넷헤더br14바이트 등이 들어가서 16비트로 정렬(align)된다.br참고로, dev_alloc_skb()는 내부적으로 kmalloc를 atomic priority로 호출하므로br인터럽트 발생중일때 사용이 가능하다.brbr그다음 체크섬을 어떻게 처리할것인가를 세팅한다. snull은 가상장치라서 brCHECKSUM_UNNECESSARY을 세팅하나 신경쓰지 말기 바란다.br3가지가 존재하는데 다음과 같다.brbrCHECKSUM_HW - 하드웨어로 체크섬을 관리한다.brCHECKSUM_NONE - 소프트웨어로 체크섬을 관리한다. 디폴트 값이다. rtl8139brCHECK_UNNECESSARY - 필요없음brbr그리고 protocol은 eth_type_trans로 간단히 세팅이 가능하다.br최종적으로 netif_rx()를 호출하여서 윗단계(ex: IP layer)로 패킷을 전송한다.brbrbr인터럽트 핸들러br~~~~~~~~~~~~~~~~br패킷을 처리할때 인터럽트를 이용한다고했다. 이제 인터럽트 핸들러를 살펴보자.br네트웍장치에서 인터럽트는 패킷이 왔을때와 패킷전송이 완료되었을때 발생되며,br각각의 구분은 랜카드의 status register를 읽음으로서 알수가 있다. brsnull은 가상장치이므로 priviate데이터 영역에 이상태정보를 저장하나,이것은 br실제 필드에서 쓰는방법이 아니다.! 그냥 무시하자.brbr-------------------------------------------------------------------br/*br * The typical interrupt entry pointbr */brvoid snull_interrupt(int irq, void *dev_id, struct pt_regs *regs)br{br int statusword;br struct snull_priv *priv;br /*br * As usual, check the device pointer for shared handlers.br * Then assign struct device *devbr */br struct net_device *dev = (struct net_device *)dev_id;br /* ... and check with hw if it's really ours */brbr if (!dev /*paranoid*/ ) return;brbr /* Lock the device */br priv = (struct snull_priv *) dev-gt;priv;br spin_lock(amp;priv-gt;lock);brbr /* retrieve statusword: real netdevices use I/O instructions */br statusword = priv-gt;status;br if (statusword amp; SNULL_RX_INTR) {br /* send it to snull_rx for handling */br snull_rx(dev, priv-gt;rx_packetlen, priv-gt;rx_packetdata);br }br if (statusword amp; SNULL_TX_INTR) {br /* a transmission is over: free the skb */br priv-gt;stats.tx_packets++;br priv-gt;stats.tx_bytes += priv-gt;tx_packetlen;br dev_kfree_skb(priv-gt;skb);br }brbr /* Unlock the device and we are done */br spin_unlock(amp;priv-gt;lock);br return;br}brbr-------------------------------------------------------------------br만약 패킷을 받았다면 위에서 설명한 snull_rx를 호출해서 처리하고,br패킷전송완료 인터럽트라면 통계정보를 세팅한다음 dev_kfree_skb로 skb를 위해br할당된 메모리를 해제한다.즉, ack가 올때까지는 메모리에 패킷을 위한 메모리가br할당된채로 남아있는것이다.brbrbr링크의 상태를 변경하기br~~~~~~~~~~~~~~~~~~~~~~~br(RTL8139에서 사용되진 않는다. 참고만하자.)br인위적으로 랜상에 carrier가 존재하지 않는것처럼 할수있다는것이다.br즉, 랜선을 뽑았다면 carrier가 사라지고, 다시 꽂으면 carrier가 있게된다.br디폴트로 랜카드에 carrier가 존재한다고 가정되나,변경도 가능하다.brbrnetif_carrier_on(strut net_device *dev); // carrier on 으로!brnetif_carrier_off(strut net_device *dev); //carrier off로!brnetif_carrier_ok(strut net_device *dev); //현재상태확인.brbr내부적으로 다음과 같이 세팅되어있을뿐이다. 그냥 참고만하자.brset_bit은 atomic하게 비트를 세팅하는 함수이다.brbrinclude/linux/netdevice.h -----------------------------------------br611 static inline void netif_carrier_off(struct net_device *dev)br612 {br613 set_bit(__LINK_STATE_NOCARRIER, amp;dev-gt;state);br614 }br-------------------------------------------------------------------brbrbr소켓 버퍼(socket buffer)br~~~~~~~~~~~~~~~~~~~~~~~~~br소켓버퍼를 많이 사용하였으나 자세한설명은 지금까지 생략되었다.brsk_buff는 리눅스의 네트웍 코드에서 가장중심이 되는 구조체이다. 여러개의br필드들과 sk_buff 를 다루는 다양한 유틸리티 함수들을 알아보도록 하자.brbr 중요 필드br==========================brbr중요필드를 먼저 알아보자.brbrstruct net_device *rx_dev ; //소켓 버퍼를 받는장치brstruct net_device *dev ; //소켓버퍼를 보내는 장치brbrbr // transport layer 헤더 ex) tcp, ucp...br unionbr {br struct tcphdr *th;br struct udphdr *uh;br struct icmphdr *icmph;br struct igmphdr *igmph;br struct iphdr *ipiph;br struct spxhdr *spxh;br unsigned char *raw;br } h;brbr // Network layer 헤더 ex) ip ...br unionbr {br struct iphdr *iph;br struct ipv6hdr *ipv6h;br struct arphdr *arph;br struct ipxhdr *ipxh;br unsigned char *raw;br } nh;brbr // Link layer 헤더 ex) ethernetbr unionbr {br struct ethhdr *ethernet;br unsigned char *raw;br } mac;brbr위와같이 네트워크의 각 계층에 해당하는 헤더들이 정의되어있다.brbrlt;참고gt;---------------------------------------------------------------br예를들어서 source ip address , dest ip address 를 알고싶다고하자.br이때는 struct tcphdr을 얻어야하므로 그냥 skb-gt;h.th 를 참조하면 된다.brbrstruct tcphdr 은 include/linux/tcp.h 에서 다음과 같이 정의한다.brbrbrstruct tcphdr {br __u16 source;br __u16 dest;br __u32 seq;br __u32 ack_seq;br#if defined(__LITTLE_ENDIAN_BITFIELD)br __u16 res1:4,br doff:4,br fin:1,br syn:1,br rst:1,br psh:1,br ack:1,br urg:1,br ece:1,br cwr:1;br#elif defined(__BIG_ENDIAN_BITFIELD)br __u16 doff:4,br res1:4,br cwr:1,br ece:1,br urg:1,br ack:1,br psh:1,br rst:1,br syn:1,br fin:1;br#elsebr#error Adjust your lt;asm/byteorder.hgt; definesbr#endifbr __u16 window;br __u16 check;br __u16 urg_ptr;br};brbrbr그러므로....br source ip address를 알려면 skb-gt;h.th.source br dest ip address를 알려면 skb-gt;h.th.dest br로 하면 간단히 알수가 있다.br------------------------------------------------------------------------brbr그다음 조금 복잡한 변수들이 선언되어있다.brbrunsigned char *head ;brunsigned char *data ;brunsigned char *tail ;brunsigned char *end ;brbrbr필자도 좀 엇갈렸는데, 권수호님의 글에있는 그림을 보고 단번에 이해가 되었다.br여기에 그리기는 힘들므로 그림은 생략한다. 시간이 허락하시는분은 br꼭! 살펴보기를 바란다. 간단히 설명하면 다음과 같다.brbr위의 4개의 변수는 결국 버퍼의 주소를 저장하는 포인터 변수이다.br버퍼는 head 로부터 end 까지가 되며, 실제로 데이터가 있는곳은 data로부터brtail까지가 된다.간단히 그려보면 다음과 같다.brbr +------------------------------------------------------------------+br | | | |br | | 실제 전송할 혹은 받은 데이터 | |br +------------------------------------------------------------------+brhead data tail end brbr그러므로 사용가능한 버퍼크기는 skb-gt;end - skb-gt;head 가 되며,br현재사용되는 데이터의 크기는 skb-gt;tail - skb-gt;data 가된다.brbrbrunsigned long len ; brbr이 값은 데이터의 길이로서 skb-gt;tail - skb-gt;data 가된다.brbrbrunsigned char ip_summed ;brbr체크섬을 표시하는 정책으로서 위에서 설명하였다.brbrbrunsigned char pkt_type ;br br이것은 패킷타입으로서 PACKET_HOST , PACKET_BROADCAST , PACKET_MULTICAST,brPAKCET_OTHERHOST중의 하나를 세팅할책임이있다.그러나 실질적인 세팅은br다음과 같이 eth_type_trans()에서 세팅하므로 드라이버 개발자는 신경을 br쓰지 않아도 된다.brbr skb-gt;protocol = eth_type_trans (skb, dev);brbrbrbr소켓버퍼를 다루는 다양한 함수들br=================================br소켓버퍼를 다루는 다양한 함수들이 이미 정의되어있으므로 소켓버퍼를 쉽게 br사용할수가 있다.brbrstruct sk_buff *alloc_skb(unsigned int len, int priority );brstruct sk_buff *dev_alloc_skb(unsigned int len ) ;brbrdev_alloc_skb는 GFP_ATOMIC권한으로 alloc_skb를 실행시킨다.그리고 skb-gt;data와brskb-gt;head사이에 공간을 조금 예비해준다. 이 공간은 network layer에서 최적화에br사용되는것으로서 드라이버에서는 건들지 말아야한다. 보통 드라이버 개발에서는brdev_alloc_skb를 사용한다.brbrbrvoid kfree_skb( struct sk_buff *skb);brvoid dev_kfree_skb(struct sk_buff *skb); lt;lt;==이걸 쓰자!brbr할당받은 공간을 해제한다.드라이버 개발자는 dev_kfree_skb를 사용해야한다.brbrbrbrunsigned char * skb_put(struct sk_buff *skb, int len );brunsigned char * __skb_put(struct sk_buff *skb, int len );brbrunsigned char * skb_push(struct sk_buff *skb, int len );brunsigned char * __skb_push(struct sk_buff *skb, int len );brbrskb_put은 버퍼의 tail 뒤에 붙이는것으로,변경되는값은 tail,len 이 된다.brtail은 당연히 늘겠고, len도 늘것이다.br이것은 버퍼를 늘리기전의 주소를 리턴하므로 snull에서도 이것을 사용하여brmemcpy로 복사했다. brbrskb_push는 버퍼의 앞에다가 붙이는것으로 변경되는것은 data , len이다.brdata는 당연히 줄겠고, len은 늘것이다.br리턴값은 방금 만들어진 data값이 된다.brbr리턴값을 살펴보자면, memcpy로 복사하기 쉬운 값을 각각 리턴함을 알수있다.brbr__를 붙인것은 그냥 간단히 기능은 똑같은데 데이터를 버퍼에 복사할br때 공간이 맞는지를 체크하는 열할을 더 한다.brbrbrint skb_tailroom(struct sk_buff *skb);brint skb_headroom(strut sk_buff *skb);brbr지금 버퍼에 얼마나 공간이 남았나를 리턴하는것으로....brskb_tail은 뒷쪽공간을, skb_headroom은 앞쪽 남은 공간을 리턴한다.br하지만 실제적으로 쓸일은 없을것이다. 왜냐하면 skb_put ,skb_push를 호출할때br자동으로 체크해주기 때문이다.brbrvoid skb_reserve(struct sk_buff *skb , int len );brunsigned char *skb_pull(struct sk_buff *skb , int len );brbrskb_reserve는 앞쪽에 공간을 확보하므로 data,tail가 변한다. snull에서도 이것br을 사용하여 16비트정렬문제를 해결함을 위에서 보았다.brbrskb_pull은 패킷의 헤더로부터 데이터를 제거한다. 드라이버는 이작업이 필요가br없다. 그냥 참고만 하기 바란다. 당연히 skb-gt;len,skb-gt;data가 감소할것이다.br이것이 바로 ethernet header,ip header, tcp header, udp header 등이 br벗겨지는 원리이다.즉, 불필요한 메모리 복사가 필요없이 간단히 skb에서br몇몇 변수가 조정해주면 되는것이다.brbrbrbr이번강의를 마치며br~~~~~~~~~~~~~~~~~br이번시간까지 snull에 대해서 알아보았다. br결국 네트웍 디바이스 드라이버란 잘받고,잘보내면 된다는것을 기억했으면 한다.br그러기 위하여, 인터럽트를 사용하며, 일정량이상의 데이터가 오면 랜카드가br인터럽트를 걸어서 나좀 처리해줘.. 라고 말하며, 패킷 전송이 완료되어도br인터럽트가 발생하여서 할당된 버퍼를 해제하는등의 일을 함을 알아보았다.br또한 소켓 버퍼라는 struct skb_buff도 알아보았다.brbr실제 네트웍 디바이스 드라이버만드는 것은 이러한 이론보다는..br랜카드등의 하드웨어의 datasheet을 더많이 봐야할것이다.br하지만 여기서 설명한 내용들이 뼈대가 될것임은 분명하다. brbr이글로 인해 독자들이 또 다른 재미(funny)를 만끽할수만 있다면 br더 바랄것이 없겠다.brbr그럼 담시간에 ^_^div class=autosourcing-stubp style=margin: 11px 0pt 7px; padding: 0pt; font-size: 12px; font-family: Dotum; font-style: normal; font-weight: normal;strong style=padding: 0pt 7px 0pt 0pt;[출처]/strong a href=http://blog.naver.com/serenax/60009611226 target=_blank[펌] 네트워크 드라이버의 기본/aspan style=padding: 0pt 7px 0pt 5px;|/spanstrong style=padding: 0pt 7px 0pt 0pt;작성자/strong a href=http://blog.naver.com/serenax target=_blank지누/a/p/divbrbrbrbrbr/pre /div
크리에이티브 커먼즈 라이센스
Creative Commons License
2008/07/30 13:29 2008/07/30 13:29
받은 트랙백이 없고, 댓글이 없습니다.

댓글+트랙백 RSS :: http://blog.minzkn.com/rss/response/277

댓글+트랙백 ATOM :: http://blog.minzkn.com/atom/response/277

트랙백 주소 :: http://blog.minzkn.com/trackback/277

트랙백 RSS :: http://blog.minzkn.com/rss/trackback/277

트랙백 ATOM :: http://blog.minzkn.com/atom/trackback/277

댓글을 달아 주세요

댓글 RSS 주소 : http://blog.minzkn.com/rss/comment/277
댓글 ATOM 주소 : http://blog.minzkn.com/atom/comment/277

BR이건 군대에 있을때 내 보물 1호로 간직하고 있던 다이어리 수첩이다.BR군시절에 나름 공부해서 정리한 노트가 십여권 있었는데 그중에서 제일 작은 노트이다.BRBR그 당시 내가 휴가때마다 사가지고 들어갔던 책에 중대장께서 보안검토 sign을 해준 기억이 추억으로 남는다. 그 중에서 책한권은 아직 간직하고 있다. 아직 그 한권에는 중대장님의 sign이 고스란히 적혀있다.BRBR다이어리와 노트들은 대부분 부대에 가끔 오는 일명 황금마차에서 월급털어서 산거다. ㅋㅋ 황금마차 들어본적 있으면 아실거다. 이동식 PX다.BRBRBR
사용자
그 당시에는 내 아이디가 minzkn이 아니고 minz이었다.BR잘보면 M하고 INZ하고 한칸 띄어서 적혀있다. 물론 이것으로 MINZ의 의미를 파악하는 사람은 없을거라 믿는다. 나중에 그 의미는 공개하기로 하고....BR쭉 다시 보면 오른쪽 위에 백골부대 (3사단) 뱃지가 보인다. 별3개~BR아무리 봐도 우리 사단마크는 멋있다. (멋져부러~)BRBRBRBR
사용자
ㅋㅋ 군대있을때 나와 펜팔로 사귄 여친사진이다. 물론 개인보호차원에서 사진은 흐릿하게 찍었다. 직접 만난적은 없다. 그냥 군에서 펜팔로만 편지를 주고받았을뿐...BRBRBRBR
사용자
요건 내 후임병이 아끼던 애인이라며 준 사진이다. ㅋㅋ 이때 베이비복스가 우리소대에서는 유명했다. SES도 그랬고... 이 당시 이 사진을 구하기 힘들었는데 후임병이 선뜻 주었다. (고맙다 수웅아!)BRBR그 밖에 휴가나오면 쓸려고 끼워두었던 전화카드도 있는데 전화카드가 세월이 오래 지났는지 겉의 표지그림이 완전히 지워지고 하얗게 남았다.BRBRBR
사용자
본론으로 들어가면 위와같이 빼곡하게 많이 적혀있다. 이중에는 이제 시대가 흘러서 별로 쓸모없어진 내용도 많지만 아직 나에게 피가되고 살이 되는 기록들이 있다. 이런거 볼때마다 참 뿌듯하다. 이런 기록정리가 없었다면 내 머릿속에는 아무것도 없는 깡통이었을것이다.BR모든것은 그렇다고 생각한다. 정리하는 습관이 나중에 도움도 많이 되고 추억으로도 남을수 있다.BR디지탈 기록보다는 아날로그 방식의 기록이 참으로 멋진 추억이 된다. 흑~ 눈물난다. 그 당시 좋은 추억들때문에... BR물론 군대가 모두 그렇지만 나쁜 추억도 많다. 그래도 이런게 있어서 좋은 추억으로 남는게 아닐까?BR
크리에이티브 커먼즈 라이센스
Creative Commons License
2008/07/22 01:06 2008/07/22 01:06
TAG
받은 트랙백이 없고, 댓글 span class="cnt"하나/span가 달렸습니다.

댓글+트랙백 RSS :: http://blog.minzkn.com/rss/response/276

댓글+트랙백 ATOM :: http://blog.minzkn.com/atom/response/276

트랙백 주소 :: http://blog.minzkn.com/trackback/276

트랙백 RSS :: http://blog.minzkn.com/rss/trackback/276

트랙백 ATOM :: http://blog.minzkn.com/atom/trackback/276

댓글을 달아 주세요

댓글 RSS 주소 : http://blog.minzkn.com/rss/comment/276
댓글 ATOM 주소 : http://blog.minzkn.com/atom/comment/276
  1. Appler 2008/07/22 14:41  댓글주소  수정/삭제  댓글쓰기

    군대에서 사재 공부를 하셨군요.......

    멋져부러~ㅎㅎ

    잘보고 갑니다.

오늘 출근할때와 퇴근할때BRBR지하철에서 은근히 몰려오는 냄새가 하나 기억이 난다.BRBR퀘퀘한 냄새였다. 냄새를 딱히 비유하자면 걸레썩는냄새하고 비슷했다.BRBR약간 몸이 뚱뚱하신 분께서 땀을 많이 흘리셨는지 냄새가 좋지 않았다.BRBR근데 내 개인적인 통계학적으로 볼때는 살이 많이 찌신 분일수록 땀을 많이 흘리면 냄새가 걸레썩는냄새하고 비슷하다는 것을 느꼈다.BRBR어느덧 오늘 출/퇴근시간에 내가 잠수부처럼 숨을 고르지 않게 쉬고 있는 나를 발견했다.BR문제는 내가 한발짝 옆으로 옮겨가면 그 분은 내 옆에 다시 한발짝 다가온다. 허걱!!!!! 내 생각이 허걱이다. ㅋBRBR살찌면 과연 땀냄새가 고약해지는게 사실일까?BR아무튼 내 생각에는 그런것 같다.BRBR살찌지 말자! 건강하게 운동하자! 땀좀 흘렸다고 걸레썩는 냄새 나면 민망하쟎아.....BR운동하자! 작심 3일이라도 실천하는게 중요하다.... 하나둘~하나둘~BR여친과 운동한후에 걸레냄새 풍겨도 사랑해줄 여친이 있다면 살쪄도 좋다! ㅋㅋ
크리에이티브 커먼즈 라이센스
Creative Commons License
2008/07/22 00:11 2008/07/22 00:11
받은 트랙백이 없고, 댓글 3개가 달렸습니다.

댓글+트랙백 RSS :: http://blog.minzkn.com/rss/response/275

댓글+트랙백 ATOM :: http://blog.minzkn.com/atom/response/275

트랙백 주소 :: http://blog.minzkn.com/trackback/275

트랙백 RSS :: http://blog.minzkn.com/rss/trackback/275

트랙백 ATOM :: http://blog.minzkn.com/atom/trackback/275

댓글을 달아 주세요

댓글 RSS 주소 : http://blog.minzkn.com/rss/comment/275
댓글 ATOM 주소 : http://blog.minzkn.com/atom/comment/275
  1. yundream 2008/07/22 11:25  댓글주소  수정/삭제  댓글쓰기

    .. 드럼메냐를 해보시는건..

  2. Appler 2008/07/22 14:42  댓글주소  수정/삭제  댓글쓰기

    살찌는 사람들은 같이 운동해도 그 냄새를 사랑해 줄 사람이 없기 때문에

    살찌는게 아닐까요??;;

    뭐 신경을 안쓰다보니..살이찐다거나..;흠..ㅋ

옛날 추억의 사진들...

minzkn™ 2008/07/18 00:49 장인정신
오늘 우연히 내 책장에 있던 낡은 플라스틱 상자를 열어보게 되었다.BRBR여기에는 내가 살아오면서 겪었던 모든것이 고스란히 기록물이 되어 아날로그 기록방식으로 기록되어 있다.BRBRㅋ 다시 보니 왠지 추억이 밀려온다.BRBRBR대부분 블로그에 올릴수 없는 매우 극비스러운 추억들이 많다. 그중에서 블로그에 올려도 될만한거 몇개만 올려본다.BRBRBR
사용자
MS-DOS 5.25인치 플로피 디스크다. 원본 정품이다. 보존상태 매우 양호한 상태로 내 플라스틱 상자에서 나온 유일한 디지털 매체이다. 디지털 매체는 이거 하나뿐.BRBRBRBRBR
사용자
BR이 사진은 내가 아주 어렸을때.. 유치원 입학한지 얼마 안되었는지 가슴에 뭘 달고 있다. ㅋㅋBR이 당시 사각 블럭가지고 노는데 심취해 있었다는 기억뿐... 캬~ 이때는 내 피부가 되게 좋아보인다... 뽀샤시한 느낌이랄까? ㅋㅋBRBRBRBR
사용자
BR이 사진은 외할머니댁에 있는 우물앞에서 놀다가 나(왼쪽)와 동생(오른쪽)하고 포즈잡고 찍은거다.BR이때 잡은 포즈에 대한 컨셉은 주머니에 손넣고 최대한 보조개를 두각시키는 거였던거 같다. ㅋㅋ 연출은 우리 어머지가 직접... ㅎㅎBRBRBRBR
사용자
BR이건 내가 고등학교때 찍은 학생증용 사진이다. 이때 두발단속이 심해서 사진찍기 전날 머리깍았던 기억이 난다. 때문에 머리모양이 매우 잘 다듬어져 있다. (완전히 각잡힌 머리 ㅋㅋ)BR이때까지도 흠없는 피부였다.BRBRBRBRBR
사용자
BRㅋ 이런거 왜 가지고 있냐고 하는 친구들도 있는데 난 내 추억이다.BR백골부대 수색대 전역한 증거다.BR참고로 나는 흔히 말하는 일빵빵(1111) 주특기가 아니다. 내 주특기는 3114 부관이다.BR수색대마크(윙) 달린 모자쓰고 사진찍었어야 멋있을텐데 모자 벗으라고 하더라... 안타깝다. 윙달린 모자쓴 모습이 되게 멋있는데 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋBRBR이때 전역증 코팅해준 애들이 장난삼아서 그랬는지 모르지만 전역증 코팅을 수십겹을 해서 줬다. 사진에는 그렇게 안보이지만 전역증 두께가 장난아니다. 엄청 두껍다.BRBRBRBRBR참 볼게 많은데 기밀사항도 좀 있고 개인 프라이버시도 좀 있고 그런 것들뿐이라고 블로그에 올릴건 요게 전부다.BR아무튼 오늘 하루죙일 낡은 플라스틱상자 뒤적이면서 시간을 보냈다. BR그래도 추억을 되살리는 즐거움은 다른 사람들도 똑같을거다.BR엔돌핀 상승~
크리에이티브 커먼즈 라이센스
Creative Commons License
2008/07/18 00:49 2008/07/18 00:49
받은 트랙백이 없고, 댓글이 없습니다.

댓글+트랙백 RSS :: http://blog.minzkn.com/rss/response/274

댓글+트랙백 ATOM :: http://blog.minzkn.com/atom/response/274

트랙백 주소 :: http://blog.minzkn.com/trackback/274

트랙백 RSS :: http://blog.minzkn.com/rss/trackback/274

트랙백 ATOM :: http://blog.minzkn.com/atom/trackback/274

댓글을 달아 주세요

댓글 RSS 주소 : http://blog.minzkn.com/rss/comment/274
댓글 ATOM 주소 : http://blog.minzkn.com/atom/comment/274

재밌겠다....BR스타3도 재밌어 보였는데BRBR디아블로3 동영상 보니까 BR이거 게임때문에 게임중독이 사회 문제시 될거 같다.BRBR아무튼 재밌겠다. 나 게임중독 되는거 아닐까? 이거 나오면.... 심히 걱정된다.
크리에이티브 커먼즈 라이센스
Creative Commons License
2008/07/12 18:30 2008/07/12 18:30
받은 트랙백이 없고, 댓글 span class="cnt"하나/span가 달렸습니다.

댓글+트랙백 RSS :: http://blog.minzkn.com/rss/response/273

댓글+트랙백 ATOM :: http://blog.minzkn.com/atom/response/273

트랙백 주소 :: http://blog.minzkn.com/trackback/273

트랙백 RSS :: http://blog.minzkn.com/rss/trackback/273

트랙백 ATOM :: http://blog.minzkn.com/atom/trackback/273

댓글을 달아 주세요

댓글 RSS 주소 : http://blog.minzkn.com/rss/comment/273
댓글 ATOM 주소 : http://blog.minzkn.com/atom/comment/273
  1. hkpco 2008/07/12 23:43  댓글주소  수정/삭제  댓글쓰기

    디아블로3.. 예술인것 같습니다.ㅎㅎ

P이 내용은 설치하면서 생각나는것을 메모로 적었기 때문에 두서가 없다.BRBR오늘 그동안 우리회사에서 열심히 실행되어온 Fedora기반 개발서버가 파일시스템이 깨져버렸다.BRBR물론 재부팅하고 파일시스템 강제로 체크시도하여 복구는 되었으나BR이미 한번 맞이 간 상태는 다시 그러지 말라는 법이 없다.BRBR다시 파일시스템이 깨지는 사태를 겪을우려를 안고 있을바에는 BR이 기회에 백업할건 다 하고 새로 젠투리눅스로 설치하자는데BR팀원 모두 의견을 같이했다.BRBR물론 젠투리눅스는 나의 입김이 좀 많이 작용하기는 했지만BR대신 관리는 내가 하게 됐다. ㅡㅡ;BR젠투리눅스를 관리할수 있는 사람이 나밖에 없으니 선택의 여지는 없었다.BR그래도 젠투리눅스는 설치만 오래걸리는것이지 관리가 용이하기 때문에BR바로 백업하고 설치들어갔다.BRBR난 젠투리눅스를 왜 좋아하냐는 질문에 답변한다면 아래와 같은 답변을 한다.BRBR1. 개발환경구축에 이만한게 없다.BRnbsp; - Cross compiler 를 multislot으로 설치하기가 매우 쉽다. (Cross 개발환경 구축에 대해서는 젠투가 다른 어떤 배보판보다 월등하다고 생각한다.)BRnbsp; - 특정 라이브러리의 버젼을 선택적으로 설치가 가능하다.BRnbsp; - 특정 참고할만한 패키지의 소스를 따로 검색할 필요없이 받을수 있다. (emerge -f 패키지명)BR2. 내가 원하는 패키지 버젼을 선택할수 있다.BR3. 젠투를 사용하면 사용할수록 리눅스를 깊이있게 알아간다. (다른말로 하면 삽질을 효율적으로 한다.)BR4. 용량이 큰 설치시디는 젠투세계에서는 필요없다. 그냥 아무거나 부팅되서 프롬프트만 뜰수 있으면 시디가 아니라도 젠투를 설치가 가능하다.BR5. 설치에 관련된 문서들과 커뮤니티가 매우 활발하다. (A href=http://www.gentoo.orghttp://www.gentoo.org/A, A href=http://gentoo-wiki.comhttp://gentoo-wiki.com/A )BR6. 특정 아키텍쳐에 설치하는것이 binutils, gcc가 포팅가능한 시스템이면 거의 대부분 설치가 가능하다. (Embedded쪽 rootfs구축하는것에 매우 요긴한 방법을 제공한다.)BR7. Local portage를 지원하므로써 나 자신만의 별도 패키지를 구성하여 사용하거나 배포가 가능하다.BR8. 새로운 배포판 버젼이 나왔을때 다시 설치해야될 이유가 없다. 그만큼 업데이트 시스템의 의존성 해결능력이 굉장히 탁월하고 장기적인 유지보수면에서 다른 배포판보다 적은 비용을 유발한다. 한번 설치하면 제대로 관리만 하면 결코 재설치할 일이 발생하지 않는다. (2004 profile에서 2008 profile까지 쭉~ 업데이트 관리해온 내 PC가 그 증거다. 벌써 4년째 사용중이지만 군더더기 파일들이 거의 없다.)BRBRnbsp;BR장점이 있다면 단점도 있는법! 단점은 아래와 같이 꼽을수 있겠다.BRBR1. 설치과정이 대부분 컴파일하는 시간으로 소요되므로 다른 배포판보다 초기 설치시간이 오래걸린다.BR2. 개발자들에게는 유용한 삽질일수 있으나 일반 사용자들에게는 고문일수 있는 삽질요소들이 있다.BR3. 네트웍이 없는 시스템에서는 설치가 불가능한것은 아니지만 설치가 매우 피곤해진다.BRBRBR뭐 대충 장단점 열거해봤다.BR내가 이래서 젠투 매니아가 됐다.BR분명 일반 사용자들에게는 결코 좋은 배포판이 아니다.BR개발자들이나 전문가들을 위한 배포판으로 최고다.BRBR어찌되었건 개발서버에 이러한 이유로 젠투설치를 주장했고BR현재 열심히 2008 profile기반으로 설치중이다.BRBRBR이제 2008 profile을 설치하면서 간간히 발생한 사소한 문제점에 열거하고 추가적으로 몇가지 생각나는 팁들도 덤으로 붙여서 적어본다.BRBR1. gamin, glib 패키지는 상호 의존관계를 가지고 있다. glib에 USE flag가 fam이 걸려있는 경우에 그렇다. 이 경우 임시로 USE flag에서 fam을 제거하고 glib설치후에 다시 fam을 준후 업데이트 하면 해결이 가능해졌다.BRBR2. stage1부터 설치하는 경우 중간에 openldap 에서 빌드문제가 발생할수 있다. 이 경우 침착하게 gentoolkit을 설치후에 revdev-rebuild한번 실행해주고 다시 설치 시도하면 설치가 된다.BRBR3. 32bit 로 기존에 사용하던 젠투 profile을 이용해서 64bit 커널을 빌드하려면 우선 crossdev 패키지를 설치하고 이걸 이용하여 x86_64-pc-linux-gnu 등과 같이 cross compiler 를 설치한다. 그리고 menuconfig 할때 make ARCH=x86_64 menuconfig 와 같이 ARCH 환경을 강제하고 설정한후에 빌드할때 비슷한 맥락으로 make ARCH=x86_64 CROSS_COMPILE=x86_64-pc-linux-gnu-nbsp; clean modules modules_install bzImage install 과 같이 CROSS_COMPILE을 함께 지정하여 빌드하면 32bit 젠투 profile에서 64bit 젠투 profile로 넘어가기 위한 64bit 커널을 빌드할수 있게 된다.BRBR4. local time zone 문제로 시간이 꼬여서 파일 의존시간에 의한 경고를 볼때가 있다. 이런경우 /etc 하위 파일들을 모두 touch 로 건드려주면 된다. 하지만 꺼림직한 방법이기 때문에 애초에 설치할때부터 /etc/localtime, /etc/conf.d/clock을 자신이 원하는 시간대로 수정후에 설치하는것이 좋다. 예전 LiveCd에서는 rdate가 없어서 시간동기 맞추기 불편했는데 2008 LiveCd에는 rdate가 들어있다.BRBR5. stage3에서 emerge -e system 한후에 되도록이면 gentoolkit을 먼저 설치하고 revdev-rebuild 명령을 수행해주는것이 좋다. 그 밖에도 update 하거나 추가 패키지 설치후에는 etc-update amp;amp; env-update amp;amp; revdev-rebuild 와 같은 식으로 해주면 패키지중에 역 의존성 파일들이 깨지지 않은 상태로 유지될수 있다.BRBR6. 젠투 홈페이지 보니까 최근에 KAIST 미러만 있었는데 새로 국내 미러가 추가됐다. 전부 속도가 만족스럽다. 굳이 외국 미러쓰지 않는게 좋다. 국산을 이용하자.BRBR7. 젠투는 부팅된 자신으로부터 다시 자신과 비슷한 또 다른 rootfs을 만들어낼수 있도록 고안되어 있다. 때문에 파티션은 이렇게 나눌것을 내 개인적인 생각으로 권장한다.BRBRnbsp;nbsp; PART1과 PART2는 16Gbytes씩 나누고 PART4는 swap으로 2GBytes를 잡는다. 나머지 용량은 PART3에 할당한다.BRnbsp; nbsp;PART1은 첫 젠투 설치할때의 root 가 된다.BRnbsp; nbsp;PART2는 새롭게 젠투를 설치할때 새로운 root가 된다.BRnbsp; nbsp;PART3는 보통 /home이 된다.BRnbsp; BRnbsp; 이렇게 파티션을 나누면 원격에서 관리하는 경우에 매우 요긴하다. boot 파티션은 안하는게 nbsp; 내 경험상 더 좋다. 처음에 PART1에 root로 설치해서 잘 쓰다가 한번 확 밀어버리고 싶을때 원격에서 그냥 PART2에 설치해서 재부팅만 하면 된다는게 이 파티션 구성의 취지이다. 서버 관리할때 이런 파티션 구성이 매우 편하다.BRBR8. Embedded 개발자라면 crossdev, mtd-utils, genromfs 같은 패키지를 활용하게 될거다. 난 이 패키지들이 없었으면 젠투를 사용할 의미가 많이 상실된다. 그 정도로 내게는 매우 고마운 패키지다.BRBR9. 젠투를 처음 설치하는 사람들에게 가장 어려운 부분은 아마도 커널설치일거다. 젠투랑 담쌓고 사는 사람들은 대부분 커널설치에서 포기했던 사람이 아닐까 싶다. 하지만 좋은 방법은 없다. 그냥 커널에 대해서 잘 이해하고 설정할수 밖에 없다.BRnbsp; - 최신 Intel 보드중에 ICH어쩌구 하는 보드를 사용중이고 SATA HDD가 10MB/s이하로 나온다면 AHCI 지원을 BIOS에서 활성화하고 (아마도 SATA관련 Enhanced로 선택하면 AHCI enable 하는 옵션이 나올거다.) 커널에서도 AHCI를 활성화 해주면 쾌적한 HDD속도를 볼수 있을거다. 이게 Intel이 고집하는 ICH 때문에 좋던 싫던 ICH 최신 보드는 AHCI를 받아들여야 한다.BRnbsp; - 방화벽(iptables, ip6tabls) 을 사용하려면 커널 옵션에서 netfilter 하위 옵션들을 모두 활성화(y 또는 m) 해주면 된다.BRnbsp; - VESA frame buffer는 되도록이면 활성화해주는게 좋다.BRBRBRBR현재 개발서버에 두가지 rootfs으로 빌드중이다. 하나는 x86_64로 빌드중이고 동시에 i686용도 빌드중이다. x86_64는 PART1에 설치중이고 i686은 PART2에 설치 진행중이다. 64bit가 당연히 우선이고 개발과정에서 불가피하게 32bit환경이 필요한 경우를 대비한것이다.BRBR아직 Xwindows를 설치하지 않았다. 요게 사실 제일 오래걸리니까...BRgnome, kde등 full xwindows로 설치할 계획이다.BRBRIPv6 는 freenet6 패키지를 이용하여 커널링으로 사용가능하게 할 계획이다.BRBR/etc/sysctl.conf에서 vm.swappiness = 5 항목을 추가하여 swap을 최대한 미루도록 하여 오랜동안 잠들었다가 깨어나는 프로세스의 응답을 향상시키도록 한다.BRBRapache + php + mysql 설치는 그냥 한다. 그리고 MoniWiki로 개발관련 팀원들끼리 문서화를 주도한다. 이 3가지 피키지는 과거 젠투에서는 문제가 종종 있었으나 요즘에는 너무 깔끔해져서 왠만해서는 문제없이 잘 설치될거다. Moniwiki는 나에게 없으면 안되는 유용한 정리도우미로 소중한 위키시스템이다.BRBRbind 를 설치하고 내부 호스트 DNS서버로 사용한다.BRBRdhcp서버는 설치하지만 사용하지 않는다.BRBR로그시스템은 syslog-ng를 사용한다.BRBRcron은 atd, vixie-cron을 사용한다.BRBR시간 동기화는 ntp 를 이용한다. 일부 시스템에서는 RTC에 문제가 있는것처럼 보이는데 커널설정 잘하면 된다.BRBRQmail을 설치는 하는데 사용할지는 미지수. smtpd 와 충돌관계이므로 smtpd제거하고 qmail을 설치한다. vpopmail은 사용하지 않고 직접 mysql 에 DB잡고 설정한다. 복잡하긴 되게 복잡해서 아마도 이거 설차할때 짜증 엄청 낼거란 예상이 든다. ㅋㅋBRBRcpufreqd, cpufreq-utils 를 설치하고 SpeedStep을 적용한다. 전기절약도 되고 불필요한 서버온도상승을 막는다. HDD도 hdparm을 통해 -S120 옵션으로 10분동안 사용하지 않으면 StandBy로 전환되도록 한다.BRBRFTP 서버는 proftpd 를 사용한다. IPv6를 제대로 지원하고 다양한 설정이 가능한것이 proftpd가 사용하기 좋다. 물론 심플한 사용은 netkit-ftpd 가 있지만 이건 실험결과 아직 IPv6를 지원하지 않고 있다.BRBRstunnel 은 설치하지 않는다. 왜냐하면 최근 버젼은 데몬 종료시에 syslog를 과도하게 채우는 쓰레기 메세지를 남긴다. init script를 stop부분만 좀 바꾸면 해결할수 있지만 안쓴다.BRBRCross 개발환경은 mipsel, armel, i586, i686, x86_64, ppc, sh4 를 우선 glibc, uclinc 환경으로 설치하고 추가적으로 i586의 경우 gcc 3.3.6-r1으로도 설치한다.BRBRsubversion, cvs, rcs 설치한다. subversion은 apache와 연동하지 않는다. 그냥 websvn으로 표시만 하도록 한다. cvs는 server설정은 하지 않는다.BRBRsamba는 xinetd 방식으로 설치하고 설정한다.BRBRtftp는 netkit-tftp를 설치한다. tftp-hpa는 현재 nbsp;IPv6를 지원하지 못해서 netkit-ftp를 사용한다.BRBRtelnetd는 netkit-telnet 을 설치한다. IPv6지원한다. xinetd방식은 모두 IPv6지원을 위해서 flags = IPV6 옵션을 추가해줘야 지원이 된다.BRBRRaid 콘트롤러가 있지만 사용하지 않는다. 솔직히 디스크 하나 나가면 복구할수 있을지 모르지만 분명한건 내 경험상 복구할수 있는 경우는 거의 없었다.BR왜냐하면 디스크에 배드섹터가 나는 문제보다 파일시스템 오류로 있는 문제가 많았고 이런 경우 Raid 미러 방식은 전혀 도움이 되지 못한다.BR파일시스템이 깨지면 깨진 정보도 미러링 되버려서 아무짝에 쓸모가 없어진다. 차라리 용량을 크게 쓰고 백업을 제 3의 서버에서 rsync로 백업하는게 훨씬 안전하다.BR내 경험상 RAID는 Cache목적으로 쓰는게 더 좋다. Volume으로 잡자.BR대부분 예기치 않은 정전과 책임감 없는 사람에게 root 권한을 주는 경우, 그리고 thirdparty에서 제공하는 toolchain을 잘못 설치할때 파일시스템이 우리를 배신했었다. 디스크가 베드섹터가 나는 경우는 손에 꼽을정도로 드문것 같다./P
크리에이티브 커먼즈 라이센스
Creative Commons License
2008/07/12 01:34 2008/07/12 01:34
받은 트랙백이 없고, 댓글 span class="cnt"하나/span가 달렸습니다.

댓글+트랙백 RSS :: http://blog.minzkn.com/rss/response/272

댓글+트랙백 ATOM :: http://blog.minzkn.com/atom/response/272

트랙백 주소 :: http://blog.minzkn.com/trackback/272

트랙백 RSS :: http://blog.minzkn.com/rss/trackback/272

트랙백 ATOM :: http://blog.minzkn.com/atom/trackback/272

댓글을 달아 주세요

댓글 RSS 주소 : http://blog.minzkn.com/rss/comment/272
댓글 ATOM 주소 : http://blog.minzkn.com/atom/comment/272
  1. 우무리 2008/07/17 02:27  댓글주소  수정/삭제  댓글쓰기

    ㅎㅎ 저도 젠투를 4년간 써왔는데.. 한번 깔고 emerge로 까닥까닥 하니.. 오래가긴 오래 가더라고요.. 다만 한국에 젠투 커뮤니티가 예전보다도 활성화가 안되는거 같아서 그게 좀 아쉬워요.

의견충돌과 타협과정

minzkn™ 2008/07/10 20:12 장인정신
맨날 있는것이 의견충돌이다.BRBR오늘 뭐 먹을래?BR난 너랑 다른거 먹을거야BRBR이러한 사사로운 의견충돌부터 시작해서BR복잡하고 해결의 실마리가 보이지 않는 의견충돌도 있다.BRBR예전에 어느 영화에서 이런 총기류를 가지고 의견충돌을 해결했다.BR그 총은 A가 B를 쏘면 A의 의견과 입장을 B가 설명한다.BRBR말도 안되는 시츄에이션을 가진 총기류이지만 간혹 이런게 있으면 좋겠다는 생각이 든다.BRBR세상 모든 사람들은 아무리 천사같은 마음과 낙관적인 성격을 가졌다고 해도 BR의견충돌 한번도 겪어보지 않은 사람은 없을거다.BRBR적어도 위의 총기류 같은 발명풍이 아니라도 그 무언가 중계자 역할을 해줘서 의견타협을 이룰수 있게 해주는 중재시스템이 개발되면 좋겠다.BRBR세계의 평화를 위해서 UN군이 있듯이BRBR개인들의 의견타협을 위한 입장대변을 맏아서 하는 중개사이트 같은것은 어떨까?BRBRBR현실성이 있는 의견인지 모르겠지만 의견타협은 정말 힘들다.
크리에이티브 커먼즈 라이센스
Creative Commons License
이 저작물은 크리에이티브 커먼