·Î±×ÀÎ | ȸ¿ø°¡ÀÔ (´º½º·¹ÅͽÅû) | SITEMAP
   
  °³¹ß   Ç÷§Æû   ½Ã½ºÅÛ   ¸Å´ÏÁö¸ÕÆ®   Àüü±â»ç  
ÀÚ¹Ù
´å³Ý
C/C++
DB
¸ðµ¨¸µ
À¥°³¹ß
±âŸ
À¯´Ð½º/¸®´ª½º
À©µµ¿ì
±âŸ
¼­¹ö
³×Æ®¿öÅ©
º¸¾È
±âŸ
BM
PM
±âŸ
 
±â»çÀúÀå
0
 
¸¶ÀÌ ½ºÅ©·¦
[¸®´ª½º Ä¿³Î 2.6ÀÇ ¼¼°è] ¨é ³×Æ®¿öÅ© ¼­ºê ½Ã½ºÅÛ
Ä¿³Î 2.6ÀÇ ³×Æ®¿öÅ© ¼­ºê ½Ã½ºÅÛ
±è³²Çü (µ¦Æ®·Ð)   2005/05/25
¿¬Àç¼ø¼­
1ȸ. Ä¿³Î ºôµå¡¤ºÎÆÃ °úÁ¤ ºÐ¼®
2ȸ. °í¼º´É Àú³Î¸µ ÆÄÀÏ ½Ã½ºÅÛ, XFS
3ȸ. Ä¿³Î 2.6ÀÇ ³×Æ®¿öÅ© ¼­ºê½Ã½ºÅÛ
[Áöµð³ÝÄÚ¸®¾Æ]³×Æ®¿öÅ© ¼­ºê ½Ã½ºÅÛÀº ¸®´ª½º°¡ Áö±Ýó·³ ³Î¸® È®»êµÇ´Âµ¥ ¸¹Àº °øÇåÀ» ÇßÀ¸¸ç, ¸®´ª½ºÀÇ ÃÖ´ë ÀåÁ¡ ÁßÀÇ Çϳª·Î Àνĵǰí ÀÖ´Â ºÐ¾ßÀÌ´Ù. ÀÌó·³ Áß¿äÇÑ À§Ä¡¸¦ Â÷ÁöÇϰí ÀÖÀ½¿¡µµ Áö±Ý²¯ ¸®´ª½º Ä¿³ÎÀÇ ³×Æ®¿öÅ© ¼­ºê ½Ã½ºÅÛÀÇ ±¸Á¶¸¦ ºÐ¼®Çϰí ÀÌÇØÇÏ·Á´Â ½Ãµµ°¡ ¸¹ÀÌ ºÎÁ·ÇÑ °ÍÀÌ »ç½ÇÀÌ´Ù.

À̹ø ±Û¿¡¼­´Â ¸®´ª½ºÀÇ ÃÖ´ë ÀåÁ¡ Áß Çϳª·Î ²ÅÈ÷´Â ³×Æ®¿öÅ· ºÎºÐ¿¡ ´ëÇÑ ±¸ÇöÀ» »ìÆìº¸°Ú´Ù. ³×Æ®¿öÅ© ÄÚµå´Â ³Ê¹«³ª ¹æ´ëÇÑ ¿µ¿ªÀ̱⠶§¹®¿¡ ÇÑ ¹ø¿¡ »ìÆìº¸´Â °ÍÀÌ ºÒ°¡´ÉÇϹǷΠ¾ÆÁÖ ´Ü¼øÇÑ ¼ÒÄÏ ÇÁ·Î±×·¥À» ¿¹Á¦·Î ÇÏ¿© ±âº»ÀûÀÎ ¼ÒÄÏÀÇ »ý¼º, ¿¬°á, µ¥ÀÌÅÍ Àü¼Û/¼ö½Å °úÁ¤¿¡ ´ëÇØ »ìÆìº¸±â·Î ÇÑ´Ù. ³×Æ®¿öÅ©´Â ¶ÇÇÑ º¸¾È¿¡ ¹Î°¨ÇÑ ¿µ¿ªÀ̱⠶§¹®¿¡ °÷°÷¿¡ º¸¾ÈÀ» À§ÇÑ ÄÚµåµéÀÌ Æ÷ÇԵǾî ÀÖÀ½À» È®ÀÎÇÒ ¼ö ÀÖÀ» °ÍÀÌ´Ù(°¡Àå ÃֽйöÀüÀÇ ¾ÈÁ¤ Ä¿³ÎÀÎ 2.6.10¿¡ ´ëÇØ »ìÆìº»´Ù).

ÀÚ·á ±¸Á¶
¼ÒÄÏ ¹öÆÛ - sk_buff ±¸Á¶Ã¼
¼ÒÄÏ ¹öÆÛ´Â ³×Æ®¿öÅ©·Î Àü¼ÛµÇ´Â ÆÐŶÀ» ³ªÅ¸³»´Â ÀÚ·á ±¸Á¶·Î¼­, ³×Æ®¿öÅ© ¼­ºê ½Ã½ºÅÛ Àü¹Ý¿¡¼­ »ç¿ëµÇ´Â Áß¿äÇÑ ±¸Á¶Ã¼ÀÌ´Ù. ¼ÒÄÏ ¹öÆÛ¸¦ Á¤ÀÇÇÑ sk_buff ±¸Á¶Ã¼´Â <include/linux/skbuff.h>¿¡ Á¤ÀǵǾî ÀÖ´Ù.

next, prev, list´Â ¼ÒÄÏ ¹öÆÛ¸¦ °ü¸®Çϱâ À§ÇÑ Æ÷ÀÎÅÍÀÌ´Ù. ¼ÒÄÏ ¹öÆÛ¸¦ ÀúÀåÇϴ ť´Â sk_buff_head ±¸Á¶Ã¼ÀÇ ÇüÅ·Π°¢ ¼ÒÄÏ ¹öÆÛ¸¦ ÀÌÁß ¿¬°á ¸®½ºÆ®·Î °ü¸®ÇÑ´Ù. sk´Â ¼ÒÄÏ ¹öÆÛ°¡ ¼ÓÇÑ ¼ÒÄÏÀ» ³ªÅ¸³»¸ç, stamp´Â ÆÐŶÀ» ¹ÞÀº ½Ã°£À» ÀúÀåÇÑ´Ù. net_device ±¸Á¶Ã¼ÀÇ dev, input_dev, real_dev Çʵå´Â ÇöÀç ÆÐŶÀ» ¹Þ°Å³ª º¸³»±â À§ÇÑ ³×Æ®¿öÅ© ÀåÄ¡¸¦ °¡¸®Å°´Â º¯¼öÀÌ´Ù. ´ÙÀ½À¸·Î ³ª¿À´Â 3°³ÀÇ union ÇʵåµéÀº °¢°¢ OSI 7 °èÃþÀÇ Àü¼Û °èÃþ(transport layer), ³×Æ®¿öÅ© °èÃþ(network layer), µ¥ÀÌÅÍ ¸µÅ© °èÃþ(data link layer)ÀÇ Çì´õ Á¤º¸¸¦ ÀúÀåÇÑ´Ù.

À̵é Çì´õ Á¤º¸µéÀº µ¥ÀÌÅÍ ¿µ¿ª ³»¿¡ ¼ø¼­´ë·Î ÀúÀåµÇ¾î ÀÖÀ¸¸ç, °¢°¢ÀÇ °èÃþÀ» Áö³ª¸é¼­ ÇØ´ç °èÃþÀÇ ÇÁ·ÎÅäÄÝ¿¡ ¸Â´Â Çì´õ Á¤º¸¸¦ ÀûÀýÈ÷ ¼³Á¤ÇÑ´Ù. dst Çʵå´Â ÆÐŶÀ» Àü¼ÛÇϱâ À§ÇÑ Á¤º¸¸¦ ÀúÀåÇÏ´Â ±¸Á¶Ã¼ÀÌ´Ù. cb´Â °¢ ÇÁ·ÎÅäÄÝ¿¡¼­ »ç¿ëµÇ´Â Á¦¾î Á¤º¸µéÀ» ÀúÀåÇÏ´Â ¿ªÇÒÀ» ÇÏ´Â ¹öÆÛÀÌ´Ù(control buffer). truesize Çʵå´Â sk_buff ±¸Á¶Ã¼ ÀÚüÀÇ Å©±â¿¡ µ¥ÀÌÅÍ ¿µ¿ªÀÇ Å©±â¸¦ ´õÇÑ ½ÇÁ¦ ¼ÒÄÏ ¹öÆÛ ±¸Á¶Ã¼ÀÇ Å©±â¸¦ ³ªÅ¸³½´Ù.

¼ÒÄÏ ¹öÆÛ ³»ÀÇ µ¥ÀÌÅÍ¿¡ Á¢±ÙÇϱâ À§ÇÑ Çʵå·Î head, data, tail, end°¡ ÀÖ´Ù. ÀÌ Áß head¿Í end´Â óÀ½¿¡ ÇÒ´çÇÑ µ¥ÀÌÅÍ ¿µ¿ªÀÇ ½ÃÀÛ°ú ³¡À» °¡¸®Å°´Â °íÁ¤µÈ ÇʵåÀÌ´Ù. data¿Í tailÀº ±× Áß¿¡¼­ ½ÇÁ¦·Î µ¥ÀÌÅͰ¡ ÀúÀåµÈ ¿µ¿ªÀÇ ½ÃÀÛ°ú ³¡À» °¡¸®Å°´Â Çʵå·Î ¼ÒÄÏ ¹öÆÛ·Î µ¥ÀÌÅͰ¡ Ãß°¡µÉ ¶§¸¶´Ù º¯°æµÈ´Ù. ¼ÒÄÏ ¹öÆÛÀÇ ³»¿ëÀº ½ÇÁ¦ µ¥ÀÌÅÍ ¾Õ¿¡ °¢ °èÃþ º°·Î Çì´õ Á¤º¸°¡ Ãß°¡µÇ´Â ÇüÅÂÀ̹ǷΠµ¥ÀÌÅÍ ¿µ¿ªÀÇ Ã³À½ºÎÅÍ »ç¿ëÇÒ ¼ö ¾ø±â ¶§¹®¿¡ ÀÌ·¯ÇÑ Çʵ带 ÀÌ¿ëÇÏ¿© ½±°Ô Á¢±ÙÇÒ ¼ö ÀÖµµ·Ï ÇÑ´Ù.

±×¸®°í ½ÇÁ¦ ±¸Á¶Ã¼¿¡´Â Æ÷ÇԵǾî ÀÖÁö ¾ÊÁö¸¸ ¼ÒÄÏ ¹öÆÛÀÇ µ¥ÀÌÅ͸¦ °ü¸®Çϱâ À§ÇØ µ¥ÀÌÅÍ ¿µ¿ªÀÇ µÞºÎºÐ¿¡ Ãß°¡ÀûÀ¸·Î struct skb_shared_info ±¸Á¶Ã¼°¡ »ç¿ëµÈ´Ù. ÀÌ ±¸Á¶Ã¼´Â µ¥ÀÌÅÍ ¿µ¿ªÀ» ÂüÁ¶Çϰí ÀÖ´Â ¼ÒÄÏ ¹öÆÛÀÇ ¼ö, fragment¸¦ ÀÌ·ç´Â ¼ÒÄÏ ¹öÆÛ Á¤º¸ µîÀ» Æ÷ÇÔÇÑ´Ù. ¼ÒÄÏ ¹öÆÛÀÇ ´ë·«ÀûÀÎ ÇüÅ´ <±×¸² 1>°ú °°ÀÌ ³ªÅ¸³¾ ¼ö ÀÖ´Ù.

<±×¸² 1> ¼ÒÄÏ ¹öÆÛ(struct sk_buff)

¼ÒÄÏ ¹öÆÛ¸¦ ´Ù·ç±â À§ÇÑ ¿©·¯ ÇÔ¼öµéÀÌ Á¸ÀçÇÑ´Ù. ¸ÕÀú ¼ÒÄÏ ¹öÆÛ¸¦ ÇÒ´çÇϱâ À§ÇØ alloc_skb ÇÔ¼ö°¡ »ç¿ëµÈ´Ù. ÀÌ ÇÔ¼ö´Â ÁÖ¾îÁø Å©±â¸¸Å­ÀÇ µ¥ÀÌÅÍ ¿µ¿ªÀ» °¡Áö´Â ¼ÒÄÏ ¹öÆÛ¸¦ »ý¼ºÇÑ´Ù. ¶ÇÇÑ µð¹ÙÀ̽º µå¶óÀ̹ö¿¡¼­ ÆÐŶÀ» ¼ö½ÅÇßÀ» ¶§ ¼ÒÄÏ ¹öÆÛ¸¦ »ý¼ºÇϱâ À§ÇØ »ç¿ëÇÏ´Â dev_alloc_skb ÇÔ¼ö°¡ ÀÖ´Ù. ÀÌ ÇÔ¼ö´Â Çì´õ Á¤º¸¸¦ Æ÷ÇÔÇϱâ À§ÇØ ÁÖ¾îÁø Å©±âº¸´Ù 16¹ÙÀÌÆ® ¸¸Å­À» ´õÇÏ¿© ¼ÒÄÏ ¹öÆÛ¸¦ »ý¼ºÇϰí, skb_reserve ÇÔ¼ö·Î 16¹ÙÀÌÆ® ¸¸Å­À» ¿¹¾àÇØ µÐ´Ù. »ý¼ºµÈ ¼ÒÄÏ ¹öÆÛ´Â kfree_skb ÇÔ¼ö¸¦ ÅëÇØ ÇØÁ¦µÈ´Ù.

¶ÇÇÑ ¼ÒÄÏ ¹öÆÛ¸¦ º¹»çÇϱâ À§ÇÑ skb_copy(µ¥ÀÌÅÍ ¿µ¿ªµµ º¹»ç), skb_clone(µ¥ÀÌÅÍ ¿µ¿ª °øÀ¯) ÇÔ¼ö¿Í µ¥ÀÌÅÍ ¿µ¿ªÀ» °¡¸®Å°´Â Æ÷ÀÎÅ͸¦ Á¶ÀÛÇϱâ À§ÇÑ skb_put, skb_push, skb_pull µîÀÇ ÇÔ¼ö°¡ ÀÖ´Ù. ±×¸®°í ¼ÒÄÏ ¹öÆÛ¸¦ Å¥¿¡ ³Ö°Å³ª »©´Â ÀÏÀ» ¼öÇàÇÏ´Â skb_queue_tail, skb_dequeue, skb_insert, skb_append, skb_unlink µîÀÇ ÇÔ¼öµµ Á¦°øÇÑ´Ù.

³×Æ®¿öÅ© ÀåÄ¡ - net_device ±¸Á¶Ã¼
net_device ±¸Á¶Ã¼´Â ¸®´ª½º Ä¿³Î ³»¿¡¼­ ³×Æ®¿öÅ© ÀåÄ¡¸¦ Ç¥ÇöÇϱâ À§ÇØ »ç¿ëÇÏ´Â ±¸Á¶Ã¼ÀÌ´Ù. ³×Æ®¿öÅ© ÀåÄ¡´Â ÀÏ¹Ý ºí·° ÀåÄ¡³ª ¹®ÀÚ ÀåÄ¡¿Í´Â ´Þ¸® /dev µð·ºÅ丮 ³»¿¡ ƯÁ¤ÇÑ ÀåÄ¡ ÆÄÀÏÀ» °¡ÁöÁö ¾ÊÀ¸¸ç, ´Ü¼øÇÑ read/write ¿¬»ê¸¸À¸·Î´Â Á¢±ÙÇÒ ¼ö ¾øÀ¸¹Ç·Î ÀÏ¹Ý ÀåÄ¡¿Í´Â ´Þ¸® Ãë±ÞµÈ´Ù. net_device ±¸Á¶Ã¼´Â I/O ¿¬»ê¿¡ ÇÊ¿äÇÑ Çϵå¿þ¾î Á¤º¸ »Ó ¾Æ´Ï¶ó À̸¦ °ü¸®Çϱâ À§ÇÑ °í¼öÁØÀÇ ÀÚ·á ±¸Á¶ ¹× ÇÔ¼ö¿¡ ´ëÇÑ Á¤º¸¸¦ Æ÷ÇÔÇÏ´Â °Å´ëÇÑ ±¸Á¶Ã¼·Î ³×Æ®¿öÅ© ¼­ºê ½Ã½ºÅÛ Àü¹Ý¿¡ °ÉÃÄ »ç¿ëµÈ´Ù. net_device ±¸Á¶Ã¼´Â <include/linux/netdevice.h>¿¡ Á¤ÀǵǾî ÀÖ´Ù.

¸ÕÀú net_device ±¸Á¶Ã¼ÀÇ ¾ÕÂÊ¿¡ ³ª¿À´Â Çϵå¿þ¾î Á¤º¸¸¦ »ìÆìº¸±â·Î ÇÑ´Ù. nameÀº ³×Æ®¿öÅ© ÀåÄ¡°¡ °¡Áú À̸§À» ÀúÀåÇÑ´Ù. ÀÌ´õ³Ý ÀåÄ¡ÀÇ À̸§Àº Ưº°È÷ ÁöÁ¤ÇÏÁö ¾Ê´Â ÇÑ <net/ethernet/eth.c>¿¡ Á¤ÀÇµÈ alloc_etherdev() ÇÔ¼ö¿¡ ÀÇÇØ eth0ºÎÅÍ Â÷·Ê·Î ºÎ¿©µÈ´Ù. ´ÙÀ½À¸·Î ÀåÄ¡°¡ »ç¿ëÇÒ °øÀ¯ ¸Þ¸ð¸® ¿µ¿ª, I/O ±âº» ÁÖ¼Ò, ÀÎÅÍ·´Æ® ¹øÈ£ µîÀÇ Á¤º¸¸¦ ÀúÀåÇÑ ÈÄ Æ¯Á¤ Çϵå¿þ¾î ¿ä±¸ÇÏ´Â Æ÷Æ® ¹øÈ£¿Í DMA ä³Î ¹øÈ£¸¦ °¢°¢ ÀúÀåÇÑ´Ù.

state Çʵå´Â ÀåÄ¡ÀÇ »óŸ¦ ³ªÅ¸³»´Â °ÍÀ¸·Î ÀåÄ¡°¡ openµÇ¾î µ¿ÀÛÇÒ Áغñ°¡ µÈ °æ¿ì¿¡´Â __LINK_STATE_START °ªÀÌ ¼³Á¤µÇ°í, ÀåÄ¡ÀÇ ¹öÆÛ°¡ °¡µæÂ÷¼­ ´õ ÀÌ»ó ÆÐŶÀ» ó¸®ÇÒ ¼ö ¾ø´Â °æ¿ì __LINK_STATE_XOFF °ªÀ¸·Î ¼³Á¤µÈ´Ù. <include/linux/net_device.h>¿¡ Á¤ÀÇµÈ netif_running()¿Í netif_queue_stopped() ÇÔ¼ö´Â °¢°¢ ÀÌ state Çʵ带 °Ë»çÇÏ¿© ÀûÀýÇÑ °ªÀ» ¸®ÅÏÇÑ´Ù. °¡´ÉÇÑ ¸ðµç »óÅÂÀÇ ¸ñ·ÏÀº ¿ª½Ã <include/linux/net_device.h>¿¡ enum netdev_state_t·Î Á¤ÀǵǾî ÀÖ´Ù.

ifindex Çʵå´Â ÀåÄ¡ÀÇ À̸§°ú ¸¶Âù°¡Áö·Î ÇØ´ç ÀåÄ¡¸¦ ³ªÅ¸³»´Â ¿ªÇÒÀ» ÇÏ´Â Á¤¼ö °ªÀ¸·Î dev_new_index() ÇÔ¼ö¿¡ ÀÇÇØ ºÎ¿©µÈ´Ù. ÀÌÈÄ dev_get_by_index(), dev_get_by_name() µîÀÇ ÇÔ¼ö·Î ÀåÄ¡ÀÇ ·¹ÆÛ·±½º¸¦ ¾ò¾î¿À´Â °ÍÀÌ °¡´ÉÇÏ´Ù. iflink Çʵå´Â ÆÐŶÀ» Àü¼ÛÇÒ ³×Æ®¿öÅ© ÀåÄ¡ÀÇ À妽º¸¦ ÀúÀåÇÏ´Â º¯¼ö·Î ±âº»ÀûÀ¸·Î ifindex Çʵå¿Í °°Àº °ªÀ» °¡ÁöÁö¸¸ Åͳθµ ÀåÄ¡¿Í °°Àº °æ¿ì¿¡´Â ½ÇÁ¦·Î ÆÐŶÀ» Àü¼ÛÇÒ ´Ù¸¥ ÀåÄ¡ÀÇ À妽º °ªÀ» °¡Áö°Ô µÈ´Ù. get_stats Çʵå´Â ÀåÄ¡ÀÇ Åë°è Á¤º¸(struct net_device_stats)¸¦ ¾ò±â À§ÇÑ ÇÔ¼öÀÇ Æ÷ÀÎÅ͸¦ ÀúÀåÇÑ´Ù.

mtu Çʵå´Â ÀåÄ¡°¡ Àü¼ÛÇÒ ¼ö ÀÖ´Â ÃÖ´ë ÆÐŶ Å©±â(MTU : Maximum Transfer Unit) Á¤º¸¸¦ ÀúÀåÇϸç, type Çʵå´Â Çϵå¿þ¾îÀÇ Á¾·ù(Ethernet, APPLEtalk, ATM, IrDA µî)¿¡ ´ëÇÑ Á¤º¸¸¦ ÀúÀåÇÑ´Ù. hard_header_len Çʵå´Â µ¥ÀÌÅÍ ¸µÅ© °èÃþ¿¡¼­ ÇÊ¿äÇÑ Çì´õ Á¤º¸ÀÇ ±æÀ̸¦ ³ªÅ¸³»¸ç, priv Çʵå´Â Çϵå¿þ¾îÀÇ Á¾·ù¿¡ µû¶ó ƯÁ¤ÇÑ Á¤º¸¸¦ ÀúÀåÇÒ ¸ñÀûÀ¸·Î »ç¿ëµÈ´Ù. <net/ethernet/eth.c>¿¡ Á¤ÀÇµÈ ether_setup() ÇÔ¼ö¿¡¼­ ÀÌ´õ³Ý Çϵå¿þ¾î ÀåÄ¡¿¡ ´ëÇÑ ¼³Á¤À» ½ÇÇàÇÑ´Ù. ´ÙÀ½À¸·Î´Â ÀåÄ¡ÀÇ Çϵå¿þ¾î ÁÖ¼Ò¿Í ºê·Îµå ij½ºÆ® ¿ë ÁÖ¼Ò, Çϵå¿þ¾î ÁÖ¼ÒÀÇ ±æÀÌ µîÀ» ÀúÀåÇÑ´Ù.

...

/* Protocol specific pointers */

void    *atalk_ptr;    /* AppleTalk link */
void    *ip_ptr;    /* IPv4 specific data */
void    *dn_ptr;    /* DECnet specific data */
void    *ip6_ptr;    /* IPv6 specific data */
void    *ec_ptr;    /* Econet specific data */
void    *ax25_ptr;    /* AX.25 specific data */

struct list_head    poll_list;    /* Link to poll list    */
int    quota;
int    weight;

struct Qdisc    *qdisc;
struct Qdisc    *qdisc_sleeping;
struct Qdisc    *qdisc_ingress;
struct list_head    qdisc_list;
unsigned long    tx_queue_len; /* Max frames per queue allowed */

...

/* Pointers to interface service routines.    */
int    (*open)(struct net_device *dev);
int    (*stop)(struct net_device *dev);
int    (*hard_start_xmit) (struct sk_buff *skb,
                 struct net_device *dev);
...
}

´ÙÀ½Àº µð¹ÙÀ̽º µå¶óÀ̹ö ¿µ¿ª¿¡¼­ »ç¿ëµÉ °í¼öÁØÀÇ Á¤º¸µéÀÌ´Ù. ¸ÕÀú »óÀ§ÀÇ ÇÁ·ÎÅäÄÝ¿¡ µû¸¥ Á¤º¸µéÀ» ÀúÀåÇϱâ À§ÇÑ Æ÷ÀÎÅÍ º¯¼öµéÀ» °¢°¢ À¯ÁöÇÑ´Ù.

qdisc Çʵå´Â ÀåÄ¡¿¡¼­ ÆÐŶ Á¤º¸¸¦ ÀúÀåÇÒ Å¥¿¡ ´ëÇÑ Á¤º¸¸¦ ³ªÅ¸³½´Ù. ÆÐŶÀ» Àü¼ÛÇÏ´Â °æ¿ì ÀåÄ¡°¡ Å¥¸¦ Áö¿øÇÑ´Ù¸é ÀåÄ¡ÀÇ qdisc°¡ °¡¸®Å°´Â Å¥¿¡ ¼ÒÄÏ ¹öÆÛ µ¥ÀÌÅ͸¦ ÀúÀåÇØ µÎ¾ú´Ù°¡ ³ªÁß¿¡ ó¸®ÇÏ°í ±×·¸Áö ¾Ê´Ù¸é(·çÇÁ¹é ÀåÄ¡³ª IP Åͳθµ °°Àº ¼ÒÇÁÆ®¿þ¾îÀûÀÎ ÀåÄ¡ÀÇ °æ¿ì) ¹Ù·Î Àü¼ÛÇÑ´Ù. tx_queue_len Çʵå´Â Å¥¿¡ ÀúÀåµÉ ¼ö ÀÖ´Â ÃÖ´ë ¼ÒÄÏ ¹öÆÛÀÇ ¼ö¸¦ ³ªÅ¸³½´Ù. ±×¸®°í »óÀ§ °èÃþ¿¡¼­ ÀåÄ¡¿¡ ´ëÇÑ ¿¬»êÀ» ¼öÇàÇϱâ À§ÇØ È£ÃâµÇ´Â ÇÔ¼öµéÀÇ Æ÷ÀÎÅ͸¦ ÀúÀåÇÑ´Ù.

°£´ÜÇÑ ¼ÒÄÏ ÇÁ·Î±×·¡¹Ö ¿¹Á¦
´ÙÀ½Àº ´Ü¼øÇÑ ¿¡ÄÚ Å¬¶óÀÌ¾ðÆ® ÇÁ·Î±×·¥À¸·Î W. Richard StevensÀÇ ¡ºUnix Network Programming¡»À̶ó´Â Ã¥ÀÇ 1Àå¿¡ ³ª¿À´Â ¿¹Á¦¸¦ ¾à°£ ¼öÁ¤ÇÑ °ÍÀÌ´Ù. °£·«ÇÑ ¼³¸íÀ» À§ÇØ ´ëºÎºÐÀÇ ¿¡·¯ ó¸® ºÎºÐÀº »ý·«Çß°í write ºÎºÐÀ» Ãß°¡Çß´Ù. ÀÌ ÇÁ·Î±×·¥À» ½ÇÇà½ÃŲ´Ù¸é ¼­¹ö¿¡ "hello"¶ó´Â ¹®ÀÚ¿­À» Àü¼ÛÇÑ µÚ ¶È°°ÀÌ "hello"¶ó´Â ¹®ÀÚ¿­À» ¼­¹ö·ÎºÎÅÍ ¹Þ°Ô µÉ °ÍÀÌ´Ù. ´ÙÀ½ÀÇ ¿¹Á¦¿¡¼­ ÁÖÀÇ ±í°Ô ºÁ¾ß ÇÒ ÇÔ¼ö´Â socket, connect, write, readÀÇ ³× °¡ÁöÀÌ´Ù. ÀÌµé °¢°¢¿¡ ´ëÇØ Ä¿³Î ³»ºÎ¿¡¼­ ¾î¶² ÀÏÀÌ ÀϾ´ÂÁö »ìÆìº¸ÀÚ.

#include "unp.h"

int main(int argc, char **argv)
{
  int sockfd;
  char line[MAXLINE + 1];
  struct sockaddr_in servaddr;

  if (argc != 2)
    err_quit("usage: a.out <IPaddress>");

  sockfd = socket(AF_INET, SOCK_STREAM, 0);

  bzero(&servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = ntons(7);
  inet_pton(AF_INET, argv[1], &servaddr,sin_addr);

  connect(sockfd, (SA *) &servadr, sizeof(servaddr));

  write(sockfd, "hello", 5);
  read(sockfd, recvline, MAXLINE);
  recvline[n] = 0; /* null terminate */
  fputs(recvline, stdout);

  exit(0);
}

¼ÒÄÏÀÇ »ý¼º°ú ¿¬°á
socket() ½Ã½ºÅÛ ÄÝ
¸ÕÀú ¼ÒÄÏÀÇ »ý¼ºÀ» À§ÇØ socket ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇÏ¸é ¸®´ª½º ½Ã½ºÅÛ ÄÝÀÇ Ã³¸® ¹æ½Ä¿¡ µû¶ó ´ëÀÀÇÏ´Â Ä¿³Î ó¸® ·çƾÀÎ sys_socket() ÇÔ¼ö°¡ È£ÃâµÈ´Ù. ÀÌ ÇÔ¼ö´Â <net/socket.c>¿¡ Á¤ÀǵǾî ÀÖÀ¸¸ç sock_create() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© ¼ÒÄÏ ±¸Á¶Ã¼¸¦ »ý¼ºÇϰí À̸¦ sock_map_fd() ÇÔ¼ö¸¦ ÀÌ¿ëÇØ ÆÄÀÏ µð½ºÅ©¸³ÅÍ¿¡ ¿¬°áÇÑ µÚ ÀÌ °ªÀ» ¸®ÅÏÇÑ´Ù. sock_create() ÇÔ¼ö´Â ¹Ù·Î __sock_create() ÇÔ¼ö¸¦ È£ÃâÇϸç ÀÌ ÇÔ¼ö°¡ ½ÇÁ¦ ¼ÒÄÏÀ» »ý¼ºÇÏ´Â ÀÏÀ» ¼öÇàÇÑ´Ù.

static int __sock_create(int family, int type, int protocol, struct socket **res, int kern)
{
  int i;
  int err;
  struct socket *sock;

  if (family < 0 || family >= NPROTO)
    return -EAFNOSUPPORT;
  if (type < 0 || type >= SOCK_MAX)
    return -EINVAL;

  if (family == PF_INET && type == SOCK_PACKET) {
    static int warned;
    if (!warned) {
        warned = 1;
        printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", current->comm);
    }
    family = PF_PACKET;
  }

  err = security_socket_create(family, type, protocol, kern);
  if (err)
    return err;

#if defined(CONFIG_KMOD)
  if (net_families[family]==NULL)
  {
    request_module("net-pf-%d",family);
  }
#endif

  net_family_read_lock();
  if (net_families[family] == NULL) {
    i = -EAFNOSUPPORT;
    goto out;
  }

¸ÕÀú ÀÎÀÚ·Î ÁÖ¾îÁø family¿Í type º¯¼ö°¡ ¿Ã¹Ù¸¥ °ªÀÎÁö¸¦ °Ë»çÇÑ´Ù. ¾ÕÀÇ ¿¹Á¦ÀÇ °æ¿ì¶ó¸é PF_INET°ú SOCK_STREAMÀÌ ³Ñ¾î¿À°Ô µÈ´Ù. PF_INETÀÇ PF´Â ¡®Protocol Family¡¯¸¦ ÀǹÌÇϸç AF(Address Family)¿¡ ÇØ´çÇÏ´Â °ª°ú µ¿ÀÏÇÏ´Ù. ¸®´ª½º¿¡¼­ Áö¿øÇÏ´Â ÇÁÅäÅäÄÝÀÇ ¸ñ·ÏÀº <include/linux/socket.h>¿¡ Á¤ÀǵǾî ÀÖ´Ù. ±×¸®°í ȣȯ¼ºÀ» À§ÇØ PF_INET¿¡ ´ëÇÏ¿© SOCK_PACKET ŸÀÔÀ» ¸í½ÃÇÑ °æ¿ì family °ªÀ» PF_PACKETÀ¸·Î ¼öÁ¤ÇÑ´Ù. ±×¸®°í security_socket_create() ÇÔ¼ö¸¦ ¸ÕÀú È£ÃâÇÏ¿© ¼ÒÄÏÀ» »ý¼ºÇϱâ À§ÇÑ º¸¾È »çÇ×À» Á¡°ËÇÑ´Ù.

À̸¦ À§ÇØ security_operations ±¸Á¶Ã¼ÀÇ socket_create Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö°¡ È£ÃâµÈ´Ù. º°µµÀÇ security_operations ±¸Á¶Ã¼°¡ µî·ÏµÇÁö ¾Ê¾Ò´Ù¸é ÀÌ ÇÔ¼öÀÇ ±âº» °ªÀº dummy_socket_create() ÇÔ¼ö·Î ´Ü¼øÈ÷ 0À» ¸®ÅÏÇÑ´Ù. ÀÌÈÄ¿¡ net_families º¯¼ö°¡ ÀúÀåÇϰí ÀÖ´Â µî·ÏµÈ ÇÁ·ÎÅäÄÝÀÇ ¹è¿­¿¡¼­ ÁÖ¾îÁø family°¡ Á¸ÀçÇÏ´ÂÁö °Ë»çÇÑ´Ù. ¸¸¾à Ä¿³Î ¸ðµâÀ» Áö¿øÇÏ´Â °æ¿ì¶ó¸é(Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì) request_module() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© ¸ðµâÀ» ¿äûÇϰí net_family ±¸Á¶Ã¼¸¦ Àбâ À§ÇÑ ¶ôÀ» ȹµæÇÑ´Ù.

if (!(sock = sock_alloc()))
   {
      printk(KERN_WARNING "socket: no more sockets\n");
      i = -ENFILE;   /* Not exactly a match, but its the
         closest posix thing */
      goto out;
   }

    sock->type = type;

   i = -EAFNOSUPPORT;
   if (!try_module_get(net_families[family]->owner))
      goto out_release;

   if ((i = net_families[family]->create(sock, protocol)) < 0)
      goto out_module_put;

   if (!try_module_get(sock->ops->owner)) {
      sock->ops = NULL;
      goto out_module_put;
   }

   module_put(net_families[family]->owner);
   *res = sock;
   security_socket_post_create(sock, family, type, protocol, kern);

out:
   net_family_read_unlock();
   return i;
out_module_put:
   module_put(net_families[family]->owner);
out_release:
   sock_release(sock);
   goto out;
}

±×¸®°í´Â sock_alloc() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© BSD ¼ÒÄÏ ±¸Á¶Ã¼(struct socket)¸¦ »ý¼ºÇÑ´Ù. »ý¼ºµÈ ¼ÒÄÏÀÇ Å¸ÀÔ¿¡ ÀÎÀÚ·Î ÁÖ¾îÁø type º¯¼ö¸¦ ¼³Á¤Çϰí try_module_get() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© family ÀÎÀÚ°¡ °¡¸®Å°´Â ÇÁ·ÎÅäÄÝÀÌ ¸ðµâ·Î ±¸ÇöµÈ °æ¿ì »ç¿ë Ä«¿îÅ͸¦ Áõ°¡½ÃŲ´Ù. ´ÙÀ½À¸·Î ÁÖ¾îÁø ÇÁ·ÎÅäÄÝ(family)¿¡ ¸Â´Â net_families ±¸Á¶Ã¼ÀÇ ¸â¹öÀÎ create() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© Ä¿³Î¿¡¼­ »ç¿ëÇÒ ¼ÒÄÏ ±¸Á¶Ã¼(struct sock)¸¦ »ý¼ºÇÑ´Ù.

¾ÕÀÇ °æ¿ì inet_family_ops ±¸Á¶Ã¼ÀÇ create() ÇÔ¼öÀÎ inet_create() ÇÔ¼ö°¡ È£ÃâµÈ´Ù. Ä¿³Î¿¡¼­´Â ÀÌ·¸°Ô »ý¼ºµÈ INET ¼ÒÄÏ(struct sock)À» »ç¿ëÇÏ¿© ÇÊ¿äÇÑ ÀÛ¾÷À» ó¸®ÇÏÁö¸¸ »ç¿ëÀÚ ·¹º§¿¡¼­´Â BSD ¼ÒÄÏ(struct socket) ÀÎÅÍÆäÀ̽º¸¦ »ç¿ëÇÏ¿© ÇÁ·Î±×·¡¹ÖÀÌ ÀÌ·ç¾îÁø´Ù. ±×¸®°í´Â try_module_get() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© ¼ÒÄÏ °ü·Ã ¿¬»êÀÚ ±¸Á¶Ã¼°¡ Á¸ÀçÇÏ´ÂÁö °Ë»çÇÑ µÚ res º¯¼ö¿¡ »ý¼ºµÈ ¼ÒÄÏÀÇ Æ÷ÀÎÅ͸¦ ÀúÀåÇÑ´Ù. ¸¶Áö¸·À¸·Î security_socket_post_create() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© º¸¾È »çÇ×À» Á¡°ËÇÑ µÚ net_family ±¸Á¶Ã¼¿¡ ´ëÇÑ ¶ôÀ» ÇØÁ¦ÇÏ°í ¸®ÅÏÇÑ´Ù.

connect() ½Ã½ºÅÛ ÄÝ
connect() ºÎºÐÀº ¼ÒÄÏÀ» ÅëÇØ Åë½ÅÇÒ »ó´ë¹æ Ãø°úÀÇ ½Å·Ú¼º ÀÖ´Â ¿¬°áÀ» È®¸³ÇÏ´Â °úÁ¤ÀÌ´Ù. ¸ÕÀú conect()¸¦ È£ÃâÇÑ Ãø(Ŭ¶óÀ̾ðÆ®)¿¡¼­ ¿¬°áÀ» ¿äûÇϱâ À§ÇØ SYNÀ̶ó´Â ÇüÅÂÀÇ ÆÐŶÀ» »ó´ë¹æ(¼­¹ö)¿¡°Ô º¸³½´Ù. SYN ÆÐŶÀ» ¹ÞÀº ¼­¹ö´Â ÀÌ¿¡ ´ëÇÑ È®ÀÎÀ» À§ÇØ SYN-ACK ÆÐŶÀ» º¸³»°í, ¸¶Áö¸·À¸·Î Ŭ¶óÀÌ¾ðÆ®°¡ ÀÌ¿¡ ´ëÇÑ ÀÀ´äÀ¸·Î ACK ÆÐŶÀ» ¼­¹ö¿¡°Ô º¸³¿À¸·Î½á ¿¬°áÀÌ ¼º¸³µÇ´Â ÇüÅÂÀÌ´Ù. ÀÌ·¸°Ô ¿¬°á ¿äû½Ã ÃÑ 3´Ü°è·Î ÆÐŶÀ» ÁÖ°í¹Þ±â ¶§¹®¿¡ 3-way handshake¶ó°í ÇÑ´Ù.

<±×¸² 2> 3-way handshake in TCP

connect() ½Ã½ºÅÛ Äݵµ ¸¶Âù°¡Áö·Î sys_connect() ÇÔ¼ö¿¡¼­ 󸮵ȴÙ. ¸ÕÀú ÀÎÀÚ·Î ÁÖ¾îÁø ÆÄÀÏ µð½ºÅ©¸³Å͸¦ ÅëÇØ ÇØ´ç BSD ¼ÒÄÏÀÇ Á¤º¸¸¦ ¾ò¾î¿Â ÈÄ ¼ÒÄÏ¿¡ ¿¬°üµÈ ¿¬»êÀÚ ±¸Á¶Ã¼ÀÇ connect() ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. socket() ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇÒ ¶§ PF_INET, SOCK_STREAMÀ¸·Î ¼³Á¤ÇßÀ¸¹Ç·Î ÀÌ °úÁ¤¿¡¼­ <net/ipv4/af_inet.c>¿¡ Á¤ÀÇµÈ inet_stream_ops ±¸Á¶Ã¼ÀÇ inet_stream_connect() ÇÔ¼ö°¡ È£ÃâµÈ´Ù. ÀÌ ÇÔ¼ö´Â BSD ¼ÒÄÏ ±¸Á¶Ã¼ÀÇ state Çʵ带 °Ë»çÇÏ¿© ¾ÆÁ÷ connect°¡ È£ÃâµÇÁö ¾ÊÀº SS_UNCONNECTED »óŶó¸é ÇØ´ç ¼ÒÄÏ¿¡ ¿¬°üµÈ ÇÁ·ÎÅäÄÝÀÇ connect() ÇÔ¼ö¸¦ ´Ù½Ã È£ÃâÇϰí ŸÀӾƿô¿¡ °ü·ÃµÈ 󸮸¦ ÇÑ ÈÄ state¸¦ SS_CONNECTED »óÅ·Πº¯°æÇÑ´Ù.

TCP ÇÁ·ÎÅäÄÝ¿¡¼­ ó¸®ÇÏ´Â connect ÇÔ¼ö´Â tcp_prot ±¸Á¶Ã¼ÀÇ tcp_v4_connect()ÀÌ´Ù. ÀÌ ÇÔ¼ö´Â <net/ipv4/tcp_ipv4.c>¿¡ Á¤ÀǵǾî ÀÖÀ¸¸ç, ¸ÕÀú connect() ½Ã½ºÅÛ ÄÝÀÇ ÀÎÀÚ·Î ÁÖ¾îÁø ¼ÒÄÏ ÁÖ¼Ò¿¡ ´ëÇØ ip_route_connect() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ¶ó¿ìÆÃ Å×À̺íÀ» °Ë»öÇÏ°í ÆÐŶÀ» Àü¼ÛÇÒ ¸ñÀûÁö Á¤º¸¸¦ ¾ò¾î¿Â´Ù. ÀÌ·¸°Ô ¾ò¾î¿Â Á¤º¸¸¦ ÀÌ¿ëÇÏ¿© INET ¼ÒÄÏÀÇ Á¤º¸¸¦ ÀûÀýÈ÷ ¼³Á¤Çϰí sk_state Çʵ带 TCP_SYN_SENT »óÅ·Πº¯°æÇÑ´Ù.

±×¸®°í´Â tcp_v4_hash_connect() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© Ŭ¶óÀÌ¾ðÆ® ÃøÀÇ Æ÷Æ®¸¦ ÀÚµ¿À¸·Î ÇÒ´çÇÑ´Ù. ÀÌ °ªÀº sysctl_local_port_range[0], sysctl_local_port_range[1](±âº» °ªÀº 1024, 4999) »çÀÌÀÇ °ªÀ¸·Î ÇÒ´ç °¡´ÉÇϸç, ÀÌÀü¿¡ ÇÒ´çµÈ °ªÀÌ tcp_port_rover º¯¼ö¿¡ ÀúÀåµÇ¾î ÀÖÀ¸¹Ç·Î(Ãʱ⠰ªÀº 1023) ÀÌ °ªº¸´Ù 1¸¸Å­ ´õ Å« °ª¿¡¼­ºÎÅÍ °Ë»öÀ» ½ÃÀÛÇÑ´Ù. ÀÌ·¸°Ô Æ÷Æ®°¡ ÇÒ´çµÇ¸é ip_route_newports() ÇÔ¼ö¸¦ ´Ù½Ã È£ÃâÇÏ¿© »õ·Î ÇÒ´çµÈ Æ÷Æ®¿¡ ´ëÇØ ¶ó¿ìÆÃ Å×À̺íÀÇ º¯°æ »çÇ×ÀÌ ÀÖ´ÂÁö ´Ù½Ã °Ë»öÇÑ´Ù. ±×¸®°í ¸¶Áö¸·À¸·Î tcp_connect() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© SYN ÆÐŶÀ» À§ÇÑ ¼ÒÄÏ ¹öÆÛ¸¦ »ý¼ºÇϰí tcp_transmit_skb() ÇÔ¼ö¸¦ ÅëÇØ Àü¼ÛÇÑ´Ù.

±×¸®°í ÀÌÈÄ¿¡´Â ¼­¹ö Ãø¿¡¼­ SYN-ACK ÆÐŶÀÌ µµÂøÇϱ⸦ ±â´Ù¸®°Ô µÈ´Ù. SYN-ACK ÆÐŶÀ» ¼ö½ÅÇß´Ù¸é tcp_rcv_state_process()¿¡ ÀÇÇØ tcp_rcv_synsent_state_process() ÇÔ¼ö°¡ È£ÃâµÈ´Ù. ÇÑ ¹ø¿¡ Àü¼ÛÇÒ ¼ö ÀÖ´Â ÆÐŶÀÇ ÃÖ´ë Å©±âÀÎ MSS(Maximum Segment Size) °ªÀ» µ¿±âÈ­Çϰí sk_state Çʵ带 TCP_ESTABLISHED »óÅ·Πº¯°æÇÑ ÈÄ ACK ÆÐŶÀ» ¼­¹ö·Î Àü¼ÛÇÑ´Ù.

ÆÐŶÀÇ Àü¼Û
ÀÀ¿ë °èÃþ - Echo client
ÀÀ¿ë ÇÁ·Î±×·¥¿¡¼­ ³×Æ®¿öÅ©·Î µ¥ÀÌÅ͸¦ Àü¼ÛÇϱâ À§Çؼ­´Â »ý¼ºµÈ ¼ÒÄÏ¿¡ write, send, sendto, sendmsg µîÀÇ ½Ã½ºÅÛ ÄÝÀ» »ç¿ëÇÒ ¼ö ÀÖ´Ù. ¿©±â¼­´Â °¡Àå ÀϹÝÀûÀÎ ÇüÅÂÀÎ write ¿¬»ê¿¡ ´ëÇØ »ìÆìº¸µµ·Ï ÇϰڴÙ. write ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇϸé Ä¿³ÎÀÇ sys_write() ÇÔ¼ö°¡ È£ÃâµÈ´Ù. ÀÌ ÇÔ¼ö´Â ¸®´ª½ºÀÇ VFS(Virtual File System) Çü½ÄÀ» µû¶ó ÁÖ¾îÁø ÆÄÀÏ¿¡ ¸Â´Â ¿¬»êÀ» ó¸®ÇÒ ¼ö ÀÖµµ·Ï vfs_write() ÇÔ¼ö¸¦ È£ÃâÇÏ¸ç °á±¹ file ±¸Á¶Ã¼ÀÇ f_op ¿¬»êÀÚ ±¸Á¶Ã¼¿¡¼­ write Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ´ÙÀ½Àº <net/socket.c>¿¡ Á¤ÀÇµÈ ¼ÒÄÏ¿¡ ´ëÇÑ f_op ¿¬»êÀÚ ±¸Á¶Ã¼ÀÌ´Ù.

static struct file_operations socket_file_ops = {
  .owner =    THIS_MODULE,
  .llseek =    no_llseek,
  .aio_read =    sock_aio_read,
  .aio_write =    sock_aio_write,
  .poll =    sock_poll,
  .ioctl =     sock_ioctl,
  .mmap =    sock_mmap,
  .open =    sock_no_open,  /* special open code to disallow open via /proc */
  .release =    sock_close,
  .fasync =    sock_fasync,
  .readv =    sock_readv,
  .writev =    sock_writev,
  .sendpage =    sock_sendpage
};

¿©±â¼­ º¼ ¼ö ÀÖµíÀÌ socket_file_ops ±¸Á¶Ã¼¿¡¼­´Â write ¿¬»êÀ» Á¤ÀÇÇÏÁö ¾Ê¾Ò´Ù. ÀÌ °æ¿ì vfs_write() ÇÔ¼ö´Â do_sync_write() ÇÔ¼ö¿¡ ÀÇÇØ aio_write() ÇÔ¼ö¸¦ È£ÃâÇϵµ·Ï µÇ¾î ÀÖÀ¸¹Ç·Î °á±¹ sock_aio_write() ÇÔ¼ö°¡ È£ÃâµÈ´Ù. sock_aio_write() ÇÔ¼ö´Â ÀûÀýÇÑ ÀÎÀÚ¸¦ ¼³Á¤ÇÑ ÈÄ __sock_sendmsg() ÇÔ¼ö¸¦ È£ÃâÇÏ°Ô µÈ´Ù. ¾Õ¿¡¼­´Â write ½Ã½ºÅÛ ÄÝ¿¡ °üÇØ »ìÆìºÃÁö¸¸ writev, send, sendto, sendmsg ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇÑ °æ¿ì¿¡µµ °á°úÀûÀ¸·Î´Â sock_sendmsg() ÇÔ¼ö°¡ È£ÃâµÇ°í, ÀÌ ÇÔ¼ö´Â ´Ù½Ã __sock_sendmsg() ÇÔ¼ö¸¦ È£ÃâÇϱ⠶§¹®¿¡ ÀÌÈÄÀÇ °úÁ¤Àº ¸ðµÎ µ¿ÀÏÇÏ°Ô Ã³¸®µÈ´Ù.

static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        struct msghdr *msg, size_t size)
{
    struct sock_iocb *si = kiocb_to_siocb(iocb);
    int err;

    si->sock = sock;
    si->scm = NULL;
    si->msg = msg;
    si->size = size;

    err = security_socket_sendmsg(sock, msg, size);
    if (err)
        return err;

    return sock->ops->sendmsg(iocb, sock, msg, size);
}

__sock_sendmsg() ÇÔ¼ö°¡ È£ÃâµÈ ½ÃÁ¡¿¡¼­ msg ÀÎÀÚÀÇ msg_iov Çʵ尡 °¡¸®Å°´Â iovec ±¸Á¶Ã¼ÀÇ iov_base´Â write() ½Ã½ºÅÛ ÄÝÀÌ È£ÃâµÉ ¶§ ÁÖ¾îÁø »ç¿ëÀÚ °ø°£ÀÇ µ¥ÀÌÅÍÀÎ "hello"¸¦ °¡¸®Å°¸ç size ÀÎÀÚ´Â 5°¡ µÈ´Ù. ÀÌ ÇÔ¼ö´Â ¼ÒÄÏ I/O ¿¬»ê¿¡ ÇÊ¿äÇÑ sock_iocb ±¸Á¶Ã¼¸¦ ÀûÀýÈ÷ ¼³Á¤ÇÑ µÚ security_socket_sendmsg() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© º¸¾È »çÇ×À» Á¡°ËÇÑ´Ù. ÀÌÈÄ¿¡ BSD ¼ÒÄÏ ±¸Á¶Ã¼ÀÇ ops ¿¬»êÀÚ ±¸Á¶Ã¼¿¡ ÀÖ´Â sendmsg Çʵ忡 ÀúÀåµÈ ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù.

ÀÌ¿Í °°ÀÌ PF_INETÀ¸·Î ¼ÒÄÏÀ» »ý¼ºÇÑ °æ¿ì inet_stream_ops ±¸Á¶Ã¼ÀÇ inet_sendmsg() ÇÔ¼ö°¡ È£ÃâµÈ´Ù. inet_sendmsg() ÇÔ¼ö´Â ÁÖ¾îÁø ¼ÒÄÏ¿¡ ´ëÇÑ INET ¼ÒÄÏÀÇ Á¤º¸¸¦ ¾ò¾î¿Â ÈÄ sk_prot ±¸Á¶Ã¼ÀÇ sendmsg Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ ÁÖ¾îÁø ÀÎÀÚ¿Í ÇÔ²² È£ÃâÇÑ´Ù(¿©±â¼­ BSD ¼ÒÄÏÀÌ INET ¼ÒÄÏÀ¸·Î ¹Ù²î¾î ³Ñ°ÜÁø´Ù). ¿ì¸®´Â SOCK_STREAM ÀÎÀÚ¸¦ ÁÖ¾î ¼ÒÄÏÀ» »ý¼ºÇ߱⠶§¹®¿¡ ÀÌ °úÁ¤¿¡¼­ ÃÖÁ¾ÀûÀ¸·Î TCP ÇÁ·ÎÅäÄÝÀÇ sendmsg ó¸® ÇÔ¼öÀÎ tcp_sendmsg() ÇÔ¼ö°¡ È£ÃâµÈ´Ù.

Àü¼Û °èÃþ - TCP
tcp_sendmsg() ÇÔ¼ö´Â <net/ipv4/tcp.c>¿¡ Á¤ÀǵǾî ÀÖ´Ù. ¸ÕÀú ¼ÒÄÏ¿¡ ´ëÇÑ ¶ôÀ» ȹµæÇϰí msg¿¡ ´ëÇÑ Ç÷¡±×°¡ ÀÖ´Ù¸é ¼³Á¤ÇÑ´Ù. TCP_CHECK_TIMER() ¸ÅÅ©·Î´Â ÇöÀç ¾Æ¹«·± ÀÛ¾÷µµ ¼öÇàÇÏÁö ¾Ê´Â´Ù. sock_sndtimeo() ÇÔ¼ö´Â ÆÐŶ Àü¼Û½Ã ´ë±âÇÒ ½Ã°£À» MSG_DONTWAIT Ç÷¡±×°¡ ¼³Á¤µÈ °æ¿ì 0À¸·Î ±×·¸Áö ¾Ê´Ù¸é sk_sndtimeo °ªÀ¸·Î ¼³Á¤ÇÑ´Ù.

sk_sndtimeo °ªÀº setsockopt() ½Ã½ºÅÛ ÄÝÀ» ÅëÇØ Ưº°È÷ ÁöÁ¤ÇÏÁö ¾Ê¾ÒÀ¸¹Ç·Î MAX_SCHEDULE_TIMEOUT (= LONG_MAX) °ªÀ» °¡Áö¸ç ½ÇÁ¦ÀûÀ¸·Î °ÅÀÇ ¹«ÇÑÁ¤ ±â´Ù¸®°Ô µÈ´Ù. ±×¸®°í ÇöÀç ¼ÒÄÏÀÇ »óŰ¡ ¿¬°áÀÌ È®¸³µÈ »óÅÂ(TCPF_ESTABLISHED)°¡ ¾Æ´Ï¶ó¸é sk_stream_wait_connect() ÇÔ¼ö¸¦ ÅëÇØ timeo ½Ã°£ µ¿¾È ¿¬°áÀÌ È®¸³µÇ±â¸¦ ±â´Ù¸°´Ù. ±×·± ´ÙÀ½ tcp_current_mss() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ÆÐŶ Çì´õ ºÎºÐÀ» Á¦¿ÜÇÑ ½ÇÁ¦ µ¥ÀÌÅÍ ¿µ¿ªÀÇ Å©±â¸¦ °è»êÇÑ´Ù.

ÀÌÁ¦ ½ÇÁ¦ µ¥ÀÌÅÍ Àü¼Û¿¡ ÇÊ¿äÇÑ Á¤º¸¸¦ ¼³Á¤Çϴµ¥ "hello"¶ó´Â ¹®ÀÚ¿­ ÇϳªÀÇ µ¥ÀÌÅ͸¸À» °¡Áö°í ÀÖÀ¸¹Ç·Î iovlen = 1, iov->iov_base = "hello", iov->iov_len = 5·Î ¼³Á¤µÇ¾î ÀÖÀ» °ÍÀÌ´Ù. copied´Â ½ÇÁ¦ Àü¼ÛµÈ µ¥ÀÌÅÍÀÇ ¾çÀ» ³ªÅ¸³»´Â º¯¼ö·Î óÀ½¿¡´Â 0À¸·Î ¼³Á¤ÇÑ´Ù. ±×¸®°í ÇöÀç±îÁö ½ÇÇàµÇ´Â µ¿¾È ¿¡·¯°¡ ¹ß»ýµÆ´ÂÁö ¼ÒÄÏÀÌ ´ÝÇû´ÂÁö¸¦ °Ë»çÇÏ¿© ÀÌ °æ¿ì ÀûÀýÇÑ Ã³¸®¸¦ Çϰí Àü¼ÛÀ» Á¾·áÇÑ´Ù.

  while (--iovlen >= 0) {
  int seglen = iov->iov_len;
  unsigned char __user *from = iov->iov_base;

  iov++;

  while (seglen > 0) {
    int copy;

    skb = sk->sk_write_queue.prev;

    if (!sk->sk_send_head ||
      (copy = mss_now - skb->len) <= 0) {

new_segment:
      /* Allocate new segment. If the interface is SG,
      * allocate skb fitting to single page.
      */
      if (!sk_stream_memory_free(sk))
        goto wait_for_sndbuf;

      skb = sk_stream_alloc_pskb(sk, select_size(sk, tp),
        0, sk->sk_allocation);
      if (!skb)
        goto wait_for_memory;

      /*
      * Check whether we can use HW checksum.
      */
      if (sk->sk_route_caps &
        (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM |
        NETIF_F_HW_CSUM))
          skb->ip_summed = CHECKSUM_HW;

      skb_entail(sk, tp, skb);
      copy = mss_now;
  }

Àü¼ÛÀº °¢°¢ÀÇ iov¿¡ ´ëÇÏ¿© ÀϾ¹Ç·Î ¿ì¸®ÀÇ °æ¿ì´Â Çѹø¸¸ ó¸®µÉ °ÍÀÌ´Ù. ÇöÀç iov¿¡ ´ëÇÏ¿© µ¥ÀÌÅÍ(¼¼±×¸ÕÆ®)ÀÇ ±æÀÌ¿Í Æ÷ÀÎÅ͸¦ °¢°¢ seglen, from º¯¼ö¿¡ ÀúÀåÇÑ ÈÄ¿¡ iov Æ÷ÀÎÅ͸¦ Áõ°¡½ÃŲ´Ù. seglen=5À̹ǷΠwhile¹® ¾ÈÀ¸·Î µé¾î¿Í¼­ skb Æ÷ÀÎÅ͸¦ ¼ÒÄÏÀÇ Àü¼Û Å¥ ³»¿¡ ÀÖ´Â ¸¶Áö¸· ¼ÒÄÏ ¹öÆÛ¸¦ °¡¸®Å°µµ·Ï ¼³Á¤ÇÑ´Ù(¾ÆÁ÷Àº ¾Æ¹«·± ¼ÒÄÏ ¹öÆÛµµ µé¾îÀÖÁö ¾Ê´Ù). ¼ÒÄÏÀÌ ÃÖÃÊ¿¡ »ý¼ºµÇ¸é sk_send_head Çʵ尡 NULL·Î ¼³Á¤µÇ¹Ç·Î if¹® ¾ÈÂÊÀÇ new_segment ºÎºÐÀ¸·Î µé¾î°¡¼­ »õ·Î¿î ¼ÒÄÏ ¹öÆÛ¸¦ »ý¼ºÇÑ´Ù.

sk_stream_memory_free() ÇÔ¼ö·Î ÇöÀç ¼ÒÄÏÀÇ Àü¼Û ¹öÆÛ(sndbuf)¿¡ °ø°£ÀÌ ³²¾ÆÀÖ´ÂÁö °Ë»çÇÑ ÈÄ sk_stream_alloc_pskb() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© ¼ÒÄÏ ¹öÆÛ¸¦ ÇÒ´çÇÑ´Ù. ±×¸®°í ³×Æ®¿öÅ© ÀåÄ¡¿¡¼­ Çϵå¿þ¾î ÀûÀ¸·Î üũ¼¶À» Áö¿øÇÏ´ÂÁö¸¦ °Ë»çÇÏ¿© ÀÌ °æ¿ì Çϵå¿þ¾î¿¡¼­ ó¸®ÇÒ ¼ö ÀÖµµ·Ï skb->ip_summed Çʵ带 CHECKSUM_HW ·Î Ç¥½ÃÇÑ´Ù. ÀÌ·¸°Ô »ý¼ºµÈ ¼ÒÄÏ ¹öÆÛ´Â skb_entail() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© Àü¼Û ÀϷùøÈ£¸¦ ¼³Á¤ÇÑ ÈÄ¿¡ ¼ÒÄÏ ±¸Á¶Ã¼ÀÇ Àü¼Û Å¥¿¡ ³Ö¾îÁø´Ù.

  /* Where to copy to? */
  if (skb_tailroom(skb) > 0) {
    if (copy > skb_tailroom(skb))
      copy = skb_tailroom(skb);
    if ((err = skb_add_data(skb, from, copy)) != 0)
      goto do_fault;
  } else {
    int merge = 0;
    int i = skb_shinfo(skb)->nr_frags;
    struct page *page = TCP_PAGE(sk);
    int off = TCP_OFF(sk);

    if (skb_can_coalesce(skb, i, page, off) &&
      off != PAGE_SIZE) {
      merge = 1;
    } else if (i == MAX_SKB_FRAGS ||
      (!i &&
        !(sk->sk_route_caps & NETIF_F_SG))) {
    tcp_mark_push(tp, skb);
      goto new_segment;
    } else if (page) {
      off = (off + L1_CACHE_BYTES - 1) &
      ~(L1_CACHE_BYTES - 1);
    if (off == PAGE_SIZE) {
      put_page(page);
    TCP_PAGE(sk) = page = NULL;
       }
    }

    if (!page) {
      /* Allocate new cache page. */
      if (!(page = sk_stream_alloc_page(sk)))
      goto wait_for_memory;
      off = 0;
    }

    if (copy > PAGE_SIZE - off)
      copy = PAGE_SIZE - off;

    err = skb_copy_to_page(sk, from, skb, page,
        off, copy);
    if (err) {
      if (!TCP_PAGE(sk)) {
      TCP_PAGE(sk) = page;
      TCP_OFF(sk) = 0;
      }
      goto do_error;
    }

    /* Update the skb. */
    if (merge) {
      skb_shinfo(skb)->frags[i - 1].size +=
        copy;
    } else {
      skb_fill_page_desc(skb, i, page, off, copy);
      if (TCP_PAGE(sk)) {
      get_page(page);
      } else if (off + copy < PAGE_SIZE) {
      get_page(page);
      TCP_PAGE(sk) = page;
      }
    }

    TCP_OFF(sk) = off + copy;
  }

´ÙÀ½À¸·Î ¼ÒÄÏ ¹öÆÛÀÇ °ø°£(tailroom)ÀÌ ³²¾ÆÀÖ´Ù¸é ÀÌ °ø°£¿¡ skb_add_data() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© µ¥ÀÌÅ͸¦ º¹»çÇÑ´Ù. ³²Àº °ø°£ÀÌ ¾ø´Ù¸é skb_can_coalesce() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ¼ÒÄÏÀÇ Àü¼Û ¸Þ½ÃÁö¸¦ À§ÇÑ ÆäÀÌÁö ³»¿¡ º¹»çÇÒ ¼ö ÀÖ´ÂÁö °Ë»çÇϰí, ±×·¸Áö ¾Ê°í ³×Æ®¿öÅ© ÀåÄ¡°¡ Scatter-Gather I/O¸¦ Áö¿øÇÏÁö ¾Ê°Å³ª ÀÌ¹Ì MAX_SKB_FRAGS ¸¸Å­ÀÇ ´ÜÆíÈ­(fragmentation)°¡ ÀÌ·ïÁ³´Ù¸é new_segment ºÎºÐÀ¸·Î µ¹¾Æ°¡¼­ »õ·Î¿î ¼ÒÄÏ ¹öÆÛ¸¦ »ý¼ºÇÑ´Ù. ¸¸ÀÏ ÀÌ¹Ì ÆäÀÌÁö°¡ ²Ë Â÷ ÀÖ´Ù¸é ÆäÀÌÁö¸¦ ÇØÁ¦ÇÏ°í »õ·Î¿î ÆäÀÌÁö¸¦ ÇÒ´ç¹Þ¾Æ skb_copy_to_page() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© ÆäÀÌÁö¿¡ µ¥ÀÌÅ͸¦ º¹»çÇÑ´Ù. ±×¸®°í µ¥ÀÌÅͰ¡ º¹»çµÈ Á¤º¸¸¦ ¼ÒÄÏ ¹öÆÛÀÇ µ¥ÀÌÅÍ¿¡ ÇØ´çÇÏ´Â skb_share_info ±¸Á¶Ã¼¿¡ ±â·ÏÇÑ ÈÄ ¼ÒÄÏÀÇ ÆäÀÌÁö¿Í ¿ÀÇÁ¼Â Á¤º¸µµ °»½ÅÇÑ´Ù.

    if (!copied)
TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;

    tp->write_seq += copy;
    TCP_SKB_CB(skb)->end_seq += copy;
    skb_shinfo(skb)->tso_segs = 0;

    from += copy;
    copied += copy;
    if ((seglen -= copy) == 0 && iovlen == 0)
        goto out;

    if (skb->len != mss_now || (flags & MSG_OOB))
        continue;

    if (forced_push(tp)) {
        tcp_mark_push(tp, skb);
        __tcp_push_pending_frames(sk, tp, mss_now, TCP_NAGLE_PUSH);
    } else if (skb == sk->sk_send_head)
        tcp_push_one(sk, mss_now);
    continue;
    ...
out:
    if (copied)
        tcp_push(sk, tp, flags, mss_now, tp->nonagle);
    TCP_CHECK_TIMER(sk);
    release_sock(sk);
    return copied;

copied º¯¼ö°¡ 0À̶ó¸é TCP Çì´õÀÇ PSH Ç÷¡±×¸¦ Áö¿ì°í Àü¼Û ÀϷùøÈ£¸¦ °»½ÅÇÑ µÚ from°ú copied º¯¼öµµ º¹»çµÈ ¸¸Å­ Áõ°¡½ÃŲ´Ù. ù ¹øÂ° if¹®ÀÇ Á¶°ÇÀ» ¸¸Á·ÇϹǷΠout ºÎºÐÀ¸·Î À̵¿ÇÑ µÚ tcp_push() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© ÆÐŶÀ» Àü¼ÛÇÑ´Ù.

tcp_push() ÇÔ¼ö´Â __tcp_push_pending_frames() ÇÔ¼ö¸¦ È£ÃâÇϰí ÀÌ ÇÔ¼ö´Â ´Ù½Ã tcp_write_xmit() ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. tcp_write_xmit() ÇÔ¼ö´Â ¼ÒÄÏ ³»ÀÇ Àü¼ÛµÉ ¼ÒÄÏ ¹öÆÛ(sk_send_head)¿¡ ´ëÇØ tcp_snd_test()¸¦ È£ÃâÇÏ¿© ÇØ´ç ¼ÒÄÏ ¹öÆÛ¸¦ Àü¼ÛÇÒÁö Å¥¿¡ ³ÖÀ»Áö °áÁ¤ÇÑ ÈÄ tcp_transmit_skb() ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ÀÌ ÇÔ¼ö´Â ¼ÒÄÏÀÇ TCP ¿¬»êÀ» ³ªÅ¸³»´Â tcp_func ±¸Á¶Ã¼ÀÇ queue_xmit Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ È£ÃâÇÏ´Â µ¥ ÀÌ ÇÔ¼ö´Â IP °èÃþÀÇ ip_queue_xmit()¿¡ ÇØ´çÇÑ´Ù.

³×Æ®¿öÅ© °èÃþ - IP
ipqueue_xmit() ÇÔ¼ö´Â <net/ipv4/ip_output.c>¿¡ Á¤ÀǵǾî ÀÖ´Ù. ÀÌ ÇÔ¼ö´Â Å©°Ô µÎ ºÎºÐÀ¸·Î ³ª´­ ¼ö Àִµ¥ ¸ÕÀú ¾ÕºÎºÐÀº Ä¿³ÎÀÇ ¶ó¿ìÆÃ Å×À̺íÀ» °Ë»öÇÏ¿© ÆÐŶÀÌ Àü¼ÛµÉ ¸ñÀûÁöÀÇ ÁÖ¼Ò¸¦ ¾Ë¾Æ³»´Â ÀÏÀÌ´Ù. ¸ÕÀú ÇØ´ç ¼ÒÄÏÀ¸·Î ÀÌ¹Ì ´Ù¸¥ ÆÐŶÀ» º¸³»¼­ ¸ñÀûÁö¿¡ ´ëÇÑ Ä³½Ã µ¥ÀÌÅ͸¦ °¡Áö°í ÀÖ´Ù¸é ÀÌ °úÁ¤À» »ý·«ÇÑ´Ù. ±×¸®°í __sk_dst_check() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ¸¸¾à ¸ñÀûÁö¿¡ ´ëÇÑ Á¤º¸¸¦ °¡Áö°í ÀÖÁö ¾Ê°Å³ª ´õ ÀÌ»ó »ç¿ëÇÒ ¼ö ¾ø´Â µ¥ÀÌÅÍÀÎ °æ¿ì¿¡´Â »õ·Î ¶ó¿ìÆÃ Å×À̺íÀ» °Ë»öÇϵµ·Ï ÇÑ´Ù.

°Ë»ö¿¡ ÇÊ¿äÇÑ Á¤º¸´Â flowi ±¸Á¶Ã¼¿¡ ÀúÀåÇϸç Àü¼ÛÇÒ ÀÎÅÍÆäÀ̽º Á¤º¸, Ãâ¹ßÁö¿Í ¸ñÀûÁöÀÇ ³×Æ®¿öÅ© ÁÖ¼Ò ¹× Æ÷Æ® ¹øÈ£, ÇÁ·ÎÅäÄݰú TOS(Type of Service) Á¤º¸ µîÀÌ ÀúÀåµÈ´Ù. ÀÌ·¸°Ô »ý¼ºÇÑ Á¤º¸¸¦ °¡Áö°í ip_route_output_flow() ÇÔ¼ö¸¦ È£ÃâÇÏ¸é °Ë»ö °á°ú°¡ rtable ±¸Á¶Ã¼¿¡ ÀúÀåµÇ°í À̸¦ ¼ÒÄϰú ¼ÒÄÏ ¹öÆÛ¿¡ ÀúÀåÇÑ´Ù.

¿©±â±îÁö ¿Ô´Ù¸é ¸ñÀûÁö¿¡ ´ëÇÑ ¶ó¿ìÆÃ Á¤º¸¸¦ °¡Áö°í ÀÖ´Â °æ¿ìÀÌ´Ù. ¸ÕÀú Strict Source Routing ¿É¼ÇÀÌ ¼³Á¤µÇ¾î ÀÖ´Â °æ¿ì ¸ñÀûÁö°¡ Á¤ÇØÁø °æ·Î¿Í ´Ù¸£´Ù¸é ¿¡·¯·Î ó¸®ÇÑ´Ù. ±×¸®°í ³ª¼­ IP Çì´õ Á¤º¸¸¦ ¼³Á¤ÇÑ´Ù. IP ¿É¼ÇÀÌ ÁÖ¾îÁø °æ¿ì¿¡´Â ip_options_build() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© ¿É¼Ç Á¤º¸¸¦ »ý¼ºÇÑ´Ù. ±×¸®°í ip_select_ident_more() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© fragment ID¸¦ ¼³Á¤ÇÑ µÚ ip_send_check() ÇÔ¼ö¿¡¼­ checksum °ªÀ» °è»êÇÑ´Ù.

¸¶Áö¸·À¸·Î ¼ÒÄÏ ¹öÆÛÀÇ ¿ì¼±¼øÀ§¸¦ ¼³Á¤ÇÑ ÈÄ NF_IP_LOCAL_OUTÀ̶ó´Â Netfilter HookÀ¸·Î ³Ñ°Ü ÆÐŶÀ» ÇÊÅ͸µÇÒÁö¸¦ °Ë»çÇÑ ´ÙÀ½¿¡ NF_HOOK() ¸ÅÅ©·ÎÀÇ ¸¶Áö¸· ÀÎÀÚ·Î ÁÖ¾îÁø dst_output() ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. dst_output() ÇÔ¼ö´Â ¼ÒÄÏ ¹öÆÛÀÇ ¸ñÀûÁö Á¤º¸¸¦ °¡Áö´Â dst ±¸Á¶Ã¼ÀÇ output Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. À̰ÍÀº ip_route_output_flow() ÇÔ¼ö¸¦ ó¸®ÇÏ´Â °úÁ¤¿¡¼­ ip_output() ÇÔ¼ö·Î ¼³Á¤µÈ´Ù.

ip_output() ÇÔ¼ö´Â ¿ì¼± ÆÐŶÀÇ Àü¼ÛÀÌ ¿äûµÆÀ½À» ³ªÅ¸³»´Â Åë°è Á¤º¸(IPSTATS_MIB_OUTREQUESTS)¸¦ Áõ°¡½ÃŲ´Ù. ¼ÒÄÏ ¹öÆÛÀÇ µ¥ÀÌÅÍÀÇ ±æÀ̸¦ °Ë»çÇÏ¿© ÇöÀç ¸ñÀûÁö·Î º¸³¾ ¼ö ÀÖ´Â ÃÖ´ë Àü¼Û Å©±â(MTU: Maximum Transfer Unit)º¸´Ù Å« °æ¿ì¿¡´Â ip_fragment() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ÆÐŶÀ» ³ª´²¼­ º¸³»°í, ±×·¸Áö ¾ÊÀº °æ¿ì¿¡´Â ip_finish_output() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ±×´ë·Î ÆÐŶÀ» Àü¼ÛÇÑ´Ù. ¿ì¸®ÀÇ °æ¿ì µ¥ÀÌÅÍÀÇ ±æÀÌ´Â 5À̹ǷΠip_finish_output() ÇÔ¼ö°¡ È£ÃâµÉ °ÍÀÌ´Ù.

packet_routed:
  if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
      goto no_route;

  /* OK, we know where to send it, allocate and build IP header. */
  iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
  *((__u16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
  iph->tot_len = htons(skb->len);
  if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
    iph->frag_off = htons(IP_DF);
  else
    iph->frag_off = 0;
  iph->ttl = ip_select_ttl(inet, &rt->u.dst);
  iph->protocol = sk->sk_protocol;
  iph->saddr = rt->rt_src;
  iph->daddr = rt->rt_dst;
  skb->nh.iph = iph;
  /* Transport layer set skb->h.foo itself. */

  if (opt && opt->optlen) {
    iph->ihl += opt->optlen >> 2;
    ip_options_build(skb, opt, inet->daddr, rt, 0);
  }

  ip_select_ident_more(iph, &rt->u.dst, sk, skb_shinfo(skb)->tso_segs);

  /* Add an IP checksum. */
  ip_send_check(iph);

  skb->priority = sk->sk_priority;

  return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
      dst_output);

no_route:
  IP_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
  kfree_skb(skb);
  return -EHOSTUNREACH;
}

ip_finish_output() ÇÔ¼ö´Â ¼ÒÄÏ ¹öÆÛÀÇ ÀåÄ¡ Á¤º¸¿Í ÇÁ·ÎÅäÄÝ Á¤º¸¸¦ ¼³Á¤ÇÑ µÚ NF_IP_POST_ROUTING Netfilter HookÀ» ÅëÇØ ip_finish_output2() ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ip_finish_output2() ÇÔ¼ö´Â <net/ipv4/ip_output.c>¿¡ Á¤ÀǵǾî ÀÖ´Ù.

ÀÌ ÇÔ¼ö´Â ¸ÕÀú ÇöÀç ¼ÒÄÏ ¹öÆÛ ³»¿¡ µ¥ÀÌÅÍ ¸µÅ© °èÃþÀÇ Çì´õ Á¤º¸(dev->hard_header)°¡ µé¾î°¥ ¸¸ÇÑ °ø°£ÀÌ ÀÖ´ÂÁö °Ë»çÇÏ¿© ¾ø´Â °æ¿ì skb_realloc_headroom() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© °ø°£À» È®º¸ÇÑ´Ù. ±×¸®°í ³ÝÇÊÅÍ µð¹ö±ë ¿É¼ÇÀÌ ¼³Á¤µÇ¾î ÀÖ´Â °æ¿ì nf_debug_ip_finish_output2() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ÇÊ¿äÇÑ ¸Þ½ÃÁö¸¦ Ãâ·ÂÇÑ´Ù.

±×¸®°í ¸ñÀûÁö¿¡ ´ëÇÑ Çϵå¿þ¾î Çì´õ ij½Ã Á¤º¸¸¦ °¡Áö°í ÀÖ´Ù¸é ij½Ã¿¡ Æ÷ÇÔµÈ Çì´õ Á¤º¸¸¦ ¼ÒÄÏ ¹öÆÛ¿¡ ÀúÀåÇϰí, ij½ÃÀÇ hh_output Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ij½Ã Á¤º¸¸¦ °¡Áö°í ÀÖÁö ¾Ê´Ù¸é Á÷Á¢ ´ÙÀ½ ¹ø Àü¼ÛµÉ ¸ñÀûÁö(neighbour)¿¡ ´ëÇÑ output Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. output Çʵå´Â neigh_resolve_output() ÇÔ¼ö¸¦ °¡¸®Å²´Ù. ÀÌ ÇÔ¼ö´Â ³»ºÎÀûÀ¸·Î neigh_opt ±¸Á¶Ã¼ÀÇ queue_xmit Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ È£ÃâÇϴµ¥ hh_output Çʵ尡 °¡¸®Å°´Â °Í°ú µ¿ÀÏÇÏ°Ô dev_queue_xmit() ÇÔ¼ö¸¦ °¡¸®Å²´Ù. ÀÌÁ¦ dev_queue_xmit() ÇÔ¼ö¸¦ µû¶ó µ¥ÀÌÅÍ ¸µÅ© °èÃþÀ¸·Î ³»·Á°¡ º¸ÀÚ.

µ¥ÀÌÅÍ ¸µÅ© °èÃþ - pci-skeleton
dev_queue_xmit() ÇÔ¼ö´Â IP °èÃþ¿¡¼­ ó¸®µÈ ¼ÒÄÏ ¹öÆÛ¸¦ ½ÇÁ¦ ³×Æ®¿öÅ© ÀåÄ¡¿¡°Ô·Î ³Ñ°Ü Àü¼ÛÇÏ´Â ¿ªÇÒÀ» Çϸç <net/core/dev.c>¿¡ Á¤ÀǵǾî ÀÖ´Ù.

¿ì¼± ¼ÒÄÏ ¹öÆÛ°¡ ¼ÒÄÏÀÇ µ¥ÀÌÅÍ Àü¼Û¿ë ÆäÀÌÁö(sk_sndmsg_page) ³»¿¡ fragment·Î ³ª´²Á® ÀÖ´Ù. ÇÏÁö¸¸ Àü¼ÛÇÒ ³×Æ®¿öÅ© ÀåÄ¡¿¡¼­ fragment ȤÀº SG(Scatter-Gather) I/O¸¦ Áö¿øÇÏÁö ¾Ê°Å³ª, Çϳª ÀÌ»óÀÇ fragment°¡ ÀåÄ¡¿¡¼­ DMA·Î Á¢±ÙÇÒ ¼ö ¾ø´Â ¿µ¿ª¿¡ ÀÖ´Ù¸é __skb_linearize() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© °¡´ÉÇÑ ¿µ¿ª ³»ÀÇ ÇϳªÀÇ µ¥ÀÌÅÍ·Î ÇÕÄ£´Ù. ±×¸®°í checksumÀÌ ¾ÆÁ÷ °è»êµÇÁö ¾Ê¾Ò´Ù¸é ¿©±â¼­ skb_checksum_help() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© °è»êÇϰí local_bh_disable() ¸ÅÅ©·Î¸¦ ÀÌ¿ëÇÏ¿© ÇöÀç CPU¿¡ ´ëÇØ softirq¸¦ ±ÝÁö½ÃŲ´Ù.

  if (q->enqueue) {
    spin_lock(&dev->queue_lock);

    rc = q->enqueue(skb, q);

    qdisc_run(dev);

    spin_unlock(&dev->queue_lock);
    rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;
    goto out;
  }

  if (dev->flags & IFF_UP) {
    int cpu = smp_processor_id(); /* ok because BHs are off */

    if (dev->xmit_lock_owner != cpu) {

      HARD_TX_LOCK(dev, cpu);

      if (!netif_queue_stopped(dev)) {
        if (netdev_nit)
          dev_queue_xmit_nit(skb, dev);

        rc = 0;
        if (!dev->hard_start_xmit(skb, dev)) {
          HARD_TX_UNLOCK(dev);
          goto out;
        }
      }
      HARD_TX_UNLOCK(dev);
      if (net_ratelimit())
        printk(KERN_CRIT "Virtual device %s asks to "
          "queue packet!\n", dev->name);
    } else {
      if (net_ratelimit())
        printk(KERN_CRIT "Dead loop on virtual device "
          "%s, fix it urgently!\n", dev->name);
    }
  }

  rc = -ENETDOWN;
  local_bh_enable();

out_kfree_skb:
  kfree_skb(skb);
  return rc;
out:
  local_bh_enable();
  return rc;
}

ÀÌÁ¦ ½ÇÁ¦·Î °¢ ÀåÄ¡¿¡ ÇØ´çÇÏ´Â Àü¼Û ÇÔ¼ö¸¦ ºÒ·¯ ÆÐŶÀ» Àü¼ÛÇÒ Â÷·ÊÀÌ´Ù. ¸ÕÀú ÇØ´ç ÀåÄ¡¿¡¼­ Àü¼ÛµÉ µ¥ÀÌÅ͸¦ À§ÇÑ Å¥¸¦ Áö¿øÇÑ´Ù¸é(q->enqueue), ÀÌ Å¥¿¡ ¼ÒÄÏ ¹öÆÛ¸¦ Áý¾î³Ö°í qdisc_run() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© Àü¼ÛÇÑ´Ù. qdisc_run() ÇÔ¼ö´Â ´Ù½Ã qdisc_restart() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ÇöÀç ³×Æ®¿öÅ© ÀåÄ¡°¡ ÆÐŶÀ» Àü¼ÛÇÒ ¼ö ÀÖ´ÂÁö °Ë»çÇÏÇÑ´Ù(netif_queue_stopped(dev)). ¿©±â¼­ Àü¼ÛÇÒ ¼ö ÀÖ´Ù¸é dev ±¸Á¶Ã¼ÀÇ hard_start_xmit Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ³×Æ®¿öÅ© ÀåÄ¡¿¡°Ô ³Ñ±â°í, ±×·¸Áö ¾Ê´Ù¸é ´Ù½Ã Å¥¿¡ ³Ö°í netif_schedule() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© NET_TX_SOFTIRQ¸¦ ¹ß»ý½ÃÄÑ ÀÌÈÄ¿¡ Àü¼ÛµÇµµ·Ï ÇÑ´Ù.

ÇØ´ç ÀåÄ¡¿¡¼­ Å¥¸¦ Áö¿øÇÏÁö ¾Ê´Â´Ù¸é Á÷Á¢ Àü¼ÛÇϴµ¥ ¸ÕÀú ÇöÀç ÀåÄ¡¿¡ ´ëÇÑ ÀåÄ¡¿¡ ´ëÇÑ ¶ôÀ» °¡Áö°í ÀÖ´Â CPU¸¦ °Ë»çÇÏ¿© ¸¸¾à ÀÌ¹Ì ¶ôÀ» °¡Áö°í ÀÖ´Â °æ¿ì¶ó¸é ¹«¾ð°¡ À߸øµÈ °æ¿ìÀ̹ǷΠ¿¡·¯·Î ó¸®ÇÑ´Ù. ±×·¸Áö ¾Ê´Ù¸é netif_queue_stopped() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© ÀåÄ¡°¡ ÆÐŶÀ» Àü¼ÛÇÒ ¼ö ÀÖ´ÂÁö °Ë»çÇÑ ÈÄ ¿ª½Ã hard_start_xmit Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ÀÌ ÇÔ¼ö´Â °¢ ÀåÄ¡ÀÇ µå¶óÀ̹ö ³»¿¡ À§Ä¡Çϰí ÀÖÀ¸¸ç ÀÌ¿¡ ´ëÇÑ ÀϹÝÀûÀÎ ÇüÅ·Π<drivers/net/isa-skeleton.c> ÆÄÀÏ ³»ÀÇ net_send_packet() ÇÔ¼ö ȤÀº <drivers/net/pci-skeleton.c> ÆÄÀÏ ³»ÀÇ netdrv_start_xmit() ÇÔ¼ö¸¦ ÂüÁ¶Çϱ⠹ٶõ´Ù.

ÆÐŶÀÇ ¼ö½Å
ÀÌÁ¦ ³×Æ®¿öÅ© ÀåÄ¡¸¦ ÅëÇØ ¹ÞÀº ÆÐŶÀÌ Ã³¸®µÇ´Â °úÁ¤¿¡ ´ëÇØ »ìÆìº¸ÀÚ.

µ¥ÀÌÅÍ ¸µÅ© °èÃþ - pci-skeleton
³×Æ®¿öÅ© ÀåÄ¡°¡ ÆÐŶÀ» ¼ö½ÅÇϸé ÀÎÅÍ·´Æ®°¡ ¹ß»ýÇÑ´Ù. ÀÌ ÀÎÅÍ·´Æ®¿¡ ´ëÇÑ Ã³¸®´Â °¢ ÀåÄ¡¿¡ µû¶ó ´Ù¸£¹Ç·Î ¿©±â¼­´Â <drivers/net/pci-skeleton.c> ÆÄÀÏ¿¡¼­ ±¸ÇöÇÑ PCI ¹ö½º¸¦ »ç¿ëÇÏ´Â ÀϹÝÀûÀÎ ³×Æ®¿öÅ© ÀåÄ¡¿¡ ´ëÇÑ ºÎºÐÀ» »ìÆìº¼ °ÍÀÌ´Ù. ¸ÕÀú ÀÌ ÀåÄ¡ÀÇ open() ÇÔ¼ö¿¡¼­ ´ÙÀ½°ú °°ÀÌ ÀÎÅÍ·´Æ®¸¦ µî·ÏÇÑ´Ù.

static int netdrv_open (struct net_device *dev)
{
    ...

    retval = request_irq (dev->irq, netdrv_interrupt, SA_SHIRQ, dev->name, dev);
    if (retval) {
        DPRINTK ("EXIT, returning %d\n", retval);
        return retval;
    }

    ...
}

ÀåÄ¡ÀÇ irq ¹øÈ£¿¡ ÇØ´çÇÏ´Â ÀÎÅÍ·´Æ®¿¡ ´ëÇØ netdrv_interrupt() ÇÔ¼ö¸¦ µî·ÏÇÑ´Ù. ÀÌ ÇÔ¼ö´Â ÀåÄ¡ÀÇ »óÅ ·¹Áö½ºÅÍÀÇ °ªÀ» Àоî Àü¼Û(TX)°ú ¼ö½Å(RX)¿¡ ÇØ´çÇÏ´Â ÀÎÅÍ·´Æ® ó¸® ÇÔ¼ö¸¦ È£ÃâÇϴµ¥ ¿©±â¼­´Â netdrv_rx_interrupt() ÇÔ¼ö°¡ È£ÃâµÈ´Ù. ÀÌ ÇÔ¼ö¿¡¼­´Â dev_alloc_skb() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© ¼ÒÄÏ ¹öÆÛ¸¦ »ý¼ºÇϰí, eth_copy_and_sum() ÇÔ¼ö¸¦ ÀÌ¿ëÇÏ¿© µ¥ÀÌÅ͸¦ º¹»çÇÑ µÚ, eth_type_trans() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© Çϵå¿þ¾î Çì´õ Á¤º¸¸¦ ¼³Á¤Çϰí ÀÌ´õ³Ý ÇÁ·ÎÅäÄÝ Á¤º¸¸¦ ¸®ÅÏÇÑ´Ù. ±×¸®°í netif_rx() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ¼ÒÄÏ ¹öÆÛ¸¦ ÇöÀç CPUÀÇ softnet_data ±¸Á¶Ã¼ÀÇ input_pkt_queue¿¡ ³Ö°í, dev ±¸Á¶Ã¼ÀÇ poll_list Á¤º¸¸¦ softnet_data ±¸Á¶Ã¼ÀÇ poll_list¿¡ Ãß°¡ÇÑ ÈÄ NET_RX_SOFTIRQ¸¦ ¹ß»ý½ÃŲ´Ù. ±×¸®°í ÆÐŶ ¼ö½Å¿¡ ´ëÇÑ Åë°è Á¤º¸¸¦ °»½ÅÇÑ ÈÄ¿¡ ÀÎÅÍ·´Æ®¸¦ 󸮸¦ ¸¶Ä£´Ù. ³ª¸ÓÁö ºÎºÐÀº softirq·Î ó¸®Çϸç ÀÌ¿¡ ´ëÇÑ Ã³¸®´Â <net/core/dev.c>¿¡ Á¤ÀÇµÈ net_rx_action() ÇÔ¼ö°¡ ¸Ã°í ÀÖ´Ù.

ÀÌ ÇÔ¼ö´Â ÇöÀç CPUÀÇ softnet_data ±¸Á¶Ã¼ÀÇ poll_list¿¡ ´ëÇÏ¿© 󸮸¦ ÇÑ´Ù. ±× ÀÚ·á ±¸Á¶¿¡ Á¢±ÙÇÏ´Â µ¿¾È¿¡´Â ÀÎÅÍ·´Æ®·Î ÀÎÇØ »õ·Î¿î ÆÐŶÀÌ Ãß°¡µÇÁö ¾Êµµ·Ï ÀÎÅÍ·´Æ®¸¦ ±ÝÁö½ÃÄÑ¾ß ÇÑ´Ù. ÀåÄ¡°¡ ó¸®ÇÒ ¼ö ÀÖ´Â ¾çÀ» ³Ñ¾ú°Å³ª ³Ê¹« ¸¹Àº ½Ã°£ÀÌ È帥 °æ¿ì¿¡´Â ´ÙÀ½ ¹ø softirq ½ÃÁ¡¿¡¼­ ó¸®Çϵµ·Ï softnet_break ºÎºÐÀ¸·Î À̵¿ÇÏ¿© ¸®ÅÏÇϰí, ±×·¸Áö ¾Ê´Ù¸é dev ±¸Á¶Ã¼ÀÇ poll Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ÀÌ ÇÔ¼ö´Â process_backlog()¿¡ ÇØ´çÇϸç softnet_data ±¸Á¶Ã¼ÀÇ input_pkt_queue ±¸Á¶Ã¼ ³»ÀÇ ¼ÒÄÏ ¹öÆÛ Á¤º¸¸¦ Çϳª¾¿ ²¨³»¼­ netif_receive_skb() ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ÀÌ ÇÔ¼ö´Â Çϵå¿þ¾î Çì´õ Á¤º¸¸¦ Àоî ÀûÀýÇÑ Ã³¸®¸¦ ÇÑ ÈÄ ÆÐŶÀÇ ÇÁ·ÎÅäÄÝ¿¡ ÇØ´çÇÏ´Â packet_type ±¸Á¶Ã¼ÀÇ Ã³¸® ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ÀÌ °æ¿ì ip_packet_type ±¸Á¶Ã¼ÀÇ ip_rcv() ÇÔ¼ö°¡ È£ÃâµÉ °ÍÀÌ´Ù.

³×Æ®¿öÅ© °èÃþ - IP
ÀÌ ÇÔ¼ö´Â ¸ÕÀú Àڽſ¡°Ô º¸³»Áø ÆÐŶÀÌ ¾Æ´Ï¶ó¸é ¹ö¸°´Ù. ±×¸®°í Åë°è Á¤º¸¸¦ °»½ÅÇÑ ÈÄ ¼ÒÄÏ ¹öÆÛÀÇ µ¥ÀÌÅͰ¡ °øÀ¯µÇ°í ÀÖ´ÂÁö °Ë»çÇÏ¿© ±×·± °æ¿ì ¼ÒÄÏ ¹öÆÛ ±¸Á¶Ã¼ ÀÚü¸¦ º¹»ç(clone)ÇÑ´Ù. ±×¸®°í pskb_may_pull() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ¹ÞÀº ÆÐŶÀÇ µ¥ÀÌÅÍ ±æÀ̰¡ IP Çì´õ Á¤º¸¸¦ Æ÷ÇÔÇÏ´Â ±æÀÌÀÎÁö¸¦ °Ë»çÇÑ ÈÄ À̸¦ IP Çì´õ·Î ÀνÄÇÑ´Ù. ±×¸®°í RFC1122ÀÇ ÆÐŶ °ÅºÎ(discard) ±ÔÁ¤¿¡ µû¶ó ´ÙÀ½ 4°¡Áö »çÇ×À» Á¡°ËÇÑ´Ù.

¨ç ÆÐŶÀÇ ±æÀ̰¡ IP Çì´õ Á¤º¸ÀÇ ±æÀ̺¸´Ù ÀÛÁö´Â ¾ÊÀº°¡? ¨èIP ¹öÀüÀÇ 4Àΰ¡? ¨échecksumÀÌ ¿Ã¹Ù¸¥°¡? ¨êÆÐŶÀÇ ±æÀÌ Á¤º¸°¡ ¿Ã¹Ù¸¥°¡? ¿©±â¼­ IP Çì´õ¿¡ Æ÷ÇÔµÈ Çì´õ ±æÀÌ Á¤º¸(ihl Çʵ忡 ÇØ´ç)´Â 4ÀÇ ¹è¼öÀÇ ÇüÅ·Π±â·ÏµÇ¾î ÀÖÀ¸¹Ç·Î ½ÇÁ¦ ±æÀÌ¿Í ºñ±³Çϱâ À§Çؼ­´Â 4¸¦ °öÇÏ´Â ÇüŰ¡ µÇ¾î¾ß ÇÑ´Ù(ihl * 4 ȤÀº ihl << 2). ȤÀº IP Çì´õÀÇ ÃÖ¼Ò ±æÀÌ´Â 20¹ÙÀÌÆ®À̹ǷΠÀ̸¦ °Ë»çÇϱâ À§Çؼ­´Â ihl Çʵ尡 5º¸´Ù ÀÛÀºÁö °Ë»çÇÒ ¼öµµ ÀÖ´Ù. ÀÌ ´Ü°è¸¦ °ÅÄ£ ¿Ã¹Ù¸¥ ÆÐŶÀ̶ó¸é NF_IP_PRE_ROUTING Netfilter HookÀ» °ÅÃÄ ip_rcv_finish() ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù.

ip_rcv_finish() ÇÔ¼ö´Â ¸ÕÀú ip_route_input() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ¸®´ª½º »ó¿¡¼­ ÆÐŶÀ» ó¸®Çϱâ À§ÇÑ ¸ñÀûÁö Á¤º¸¸¦ ¼³Á¤ÇÑ´Ù. ÃÖÁ¾ ¸ñÀûÁö°¡ ÀÚ±â ÀÚ½ÅÀ̶ó¸é ¼ÒÄÏ ¹öÆÛÀÇ dst ±¸Á¶Ã¼ÀÇ input Çʵ尡 ip_local_deliver() ÇÔ¼ö¸¦ °¡¸®Å°µµ·Ï ¼³Á¤µÈ´Ù. ±×·¸Áö ¾Ê°í ÀÚ½ÅÀ» °ÅÃÄ ´Ù¸¥ È£½ºÆ®¿¡°Ô º¸³»Áö´Â ÆÐŶÀÇ °æ¿ì¿¡´Â ip_forward() ÇÔ¼ö·Î ¼³Á¤µÈ´Ù. ±×¸®°í IP Çì´õ ³»¿¡ ¿É¼Ç Á¤º¸°¡ Æ÷ÇԵǾî ÀÖ´Ù¸é(Çì´õÀÇ ±æÀ̰¡ 20 ¹ÙÀÌÆ®º¸´Ù Ä¿Áö¹Ç·Î ihl Çʵ尡 5º¸´Ù Å©´Ù) ip_options_complie() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ip_options ±¸Á¶Ã¼ÀÇ ÇüÅ·Π¸¸µç´Ù. ±×¸®°í dst_input() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© dst ±¸Á¶Ã¼ÀÇ input Çʵ尡 °¡¸®Å°´Â ip_local_deliver() ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù.

ip_local_deliver() ÇÔ¼ö´Â ÆÐŶÀÌ fragment¶ó¸é ip_defrag() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ipq ±¸Á¶Ã¼¿¡ ÀúÀåÇϰí, ±×·¸Áö ¾Ê´Ù¸é NF_IP_LOCAL_INÀ̶ó´Â Netfilter HookÀ» ÅëÇØ ip_local_deliver_finish() ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ÀÌ ÇÔ¼ö´Â ¸ÕÀú IP Çì´õ ±æÀ̸¸Å­ µ¥ÀÌÅ͸¦ À̵¿½ÃÄÑ TCP Çì´õ Á¤º¸·Î ¼³Á¤ÇÑ µÚ ÇØ´ç ÇÁ·ÎÅäÄÝ¿¡ ÇØ´çÇÏ´Â Á¤º¸¸¦ ã¾Æ »óÀ§ ÇÁ·ÎÅäÄÝ·Î ³Ñ°ÜÁÖ´Â ÀÏÀ» ÇÑ´Ù. ÀÌ °æ¿ì tcp_protocol ±¸Á¶Ã¼ÀÇ tcp_v4_rcv() ÇÔ¼ö°¡ È£ÃâµÈ´Ù.

Àü¼Û °èÃþ - TCP
tcp_v4_rcv() ÇÔ¼ö´Â ÁÖ¾îÁø TCP Çì´õ Á¤º¸¿¡ µû¶ó ÀûÀýÇÑ Ã³¸®¸¦ ÇÑ µÚ ¼ÒÄÏ ¹öÆÛÀÇ Ãâ¹ßÁö¿Í ¸ñÀûÁöÀÇ ³×Æ®¿öÅ© ÁÖ¼Ò ¹× Æ÷Æ® ¹øÈ£¸¦ ÅëÇØ __tcp_v4_lookup() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ±×¿¡ ÇØ´çÇÏ´Â ¼ÒÄÏ Á¤º¸¸¦ ã¾Æ³½´Ù. ±×¸®°í ¼ÒÄÏ¿¡ ÇÊÅͰ¡ Á¸ÀçÇÏ´Â °æ¿ì sk_filter() ÇÔ¼ö¸¦ ÅëÇØ ÇÊÅ͸µÀ» Çϰí tcp_v4_do_rcv() ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ÀÌ ÇÔ¼ö´Â <net/ipv4/tcp_ipv4.c>¿¡ Á¤ÀǵǾî ÀÖ´Ù.

ÀÌ ÇÔ¼ö´Â ÇöÀç ¼ÒÄÏÀÇ »óÅ¿¡ µû¶ó °¢°¢ ´Ù¸¥ ó¸® ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ¸ÕÀú ÀϹÝÀûÀ¸·Î ¼ÒÄÏÀÌ ¿¬°áµÈ »óŶó¸é (TCP_ESTABLISHED) tcp_rcv_established() ÇÔ¼ö¸¦ È£ÃâÇϰí, ±×·¸Áö ¾Ê°í ¼ÒÄÏÀ» ±â´Ù¸®´Â ÁßÀ̶ó¸é (TCP_LISTEN) tcp_v4_hnd_req() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© ¿¬°á¿¡ ´ëÇÑ ¿äûÀ» ó¸®ÇÑ´Ù. ±× ¿ÜÀÇ »óÅ¿¡ ´ëÇØ¼­´Â connect() ½Ã½ºÅÛ ÄÝ¿¡ ´ëÇÑ ºÎºÐ¿¡¼­ °£·«È÷ »ìÆìº» ´ë·Î tcp_rcv_state_process() ÇÔ¼ö°¡ È£ÃâµÈ´Ù. tcp_rcv_established() ÇÔ¼ö´Â ACK¿¡ ´ëÇÑ Ã³¸®¿Í ŸÀÓ½ºÅÆÇÁ, ¼ö½Å ÀϷùøÈ£ ¹× À©µµ¿ì¿¡ ´ëÇÑ Ã³¸®¸¦ ÇÑ ÈÄ¿¡ »ç¿ëÀÚ °ø°£À¸·Î µ¥ÀÌÅ͸¦ º¹»çÇØ ÁØ´Ù.

ÀÌ ¶§ softirq¸¦ ó¸®ÇÏ´Â ÇÁ·Î¼¼½º(current)°¡ ¼ÒÄÏÀ» ±â´Ù¸®´Â ÇÁ·Î¼¼½º¶ó¸é ÇöÀç ÇÁ·Î¼¼½ºÀÇ »óŸ¦ TASK_RUNNINGÀ¸·Î ¸¸µé°í tcp_copy_to_iovec() ÇÔ¼ö¸¦ ÅëÇØ Á÷Á¢ µ¥ÀÌÅ͸¦ º¹»çÇÑ´Ù. ±×·¸Áö ¾Ê´Ù¸é ¼ÒÄÏ ¹öÆÛ¸¦ ¼ÒÄÏ ±¸Á¶Ã¼ÀÇ sk_receive_queueÀÇ ¸Ç ¸¶Áö¸·¿¡ ³Ö°í ¼ÒÄÏ ¹öÆÛÀÇ ¼ÒÀ¯ÀÚ¸¦ ÇØ´ç ¼ÒÄÏÀ¸·Î ¼³Á¤ÇÑ µÚ ¼ÒÄÏ ±¸Á¶Ã¼ÀÇ sk_data_ready Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. ÀÌ ÇÔ¼ö´Â sock_def_readable() ÇÔ¼ö·Î ¼³Á¤µÇ¾î ÀÖÀ¸¸ç, sk ±¸Á¶Ã¼ÀÇ sk_sleep Çʵ尡 °¡¸®Å°´Â wait_queue¿¡¼­ Àáµé¾î ÀÖ´Â ÇÁ·Î¼¼½ºµéÀ» ±ú¿î´Ù.

ÀÀ¿ë °èÃþ
ÀÀ¿ë ÇÁ·Î±×·¥¿¡¼­ read() ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇϸé write()ÀÇ °æ¿ì¿Í ¸¶Âù°¡Áö·Î sys_read()¡ævfs_read()¡ædo_sync_read()¡æsock_aio_read() ÇÔ¼ö¸¦ °ÅÃÄ __sock_recvmsg() ÇÔ¼ö°¡ È£ÃâµÇ¸ç, <net/socket.c>¿¡ Á¤ÀǵǾî ÀÖ´Ù.

ÀÌ ÇÔ¼ö´Â ¼ÒÄÏ I/O ¿¬»êÀ» À§ÇÑ sock_iocb ±¸Á¶Ã¼¸¦ ÃʱâÈ­ÇÑ µÚ, security_socket_recvmsg() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© º¸¾È »çÇ×À» Á¡°ËÇÏ°í ½ÇÁ¦ ·çƾÀÎ BSD ¼ÒÄÏ ±¸Á¶Ã¼ÀÇ ops ±¸Á¶Ã¼ÀÇ recvmsg Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. inet_stream_ops ±¸Á¶Ã¼ÀÇ recvmsg Çʵå´Â sock_common_recvmsg() ÇÔ¼ö¸¦ °¡¸®Å°°í ÀÖÀ¸¸ç, ÀÌ ÇÔ¼ö´Â ´Ù½Ã INET ¼ÒÄÏÀÇ recvmsg Çʵ尡 °¡¸®Å°´Â ÇÔ¼ö¸¦ È£ÃâÇÑ´Ù. TCP¿¡¼­ ÀÌ ÇÔ¼ö´Â tcp_sendmsg()¿¡ ÇØ´çÇÑ´Ù.
ÀÌ ÇÔ¼ö´Â ·çÇÁ¸¦ µ¹¸ç sk_receive_queue ³»ÀÇ ¼ÒÄÏ ¹öÆÛ¸¦ °Ë»çÇÏ¿© ¿øÇÏ´Â offset ¿¡ ÇØ´çÇÏ´Â ¼ÒÄÏ ¹öÆÛÀÇ µ¥ÀÌÅ͸¦ ã¾Æ º¹»çÇÑ´Ù. ÀÌ °úÁ¤¿¡¼­ ÇÁ·Î¼¼½º°¡ ½Ã±×³ÎÀ» ¹Þ´Â´Ù¸é sock_rcvtimeo() ÇÔ¼ö¿¡¼­ °è»êµÈ timeo °ª¿¡ µû¶ó -ERESTARTSYS ȤÀº -EINTR ¿¡·¯¿Í ÇÔ²² ¸®ÅϵȴÙ.

sk_receive_queue¿¡¼­ ÇØ´çÇÏ´Â ¼ÒÄÏ ¹öÆÛ¸¦ ãÁö ¸øÇϸé sk_wait_data() ÇÔ¼ö¸¦ È£ÃâÇÏ¿© timeo ½Ã°£¸¸Å­ ±â´Ù¸°´Ù. ÀÌ ¶§ ÇÁ·Î¼¼½º´Â INET ¼ÒÄÏ ±¸Á¶Ã¼ÀÇ sk_sleep Çʵ尡 °¡¸®Å°´Â wait_queue¿¡¼­ Àáµç´Ù. ÀÌ ÈÄ¿¡ ÆÐŶÀ» ¹ÞÀ¸¸é tcp_rcv_established()¿¡¼­ ÀÌ wait_queue ³»ÀÇ ÇÁ·Î¼¼½ºµéÀ» ±ú¿ì°Ô µÉ °ÍÀÌ´Ù.

°èÃþº° ÆÐŶ È帧 Á¤¸®
Áö±Ý²¯ ³×Æ®¿öÅ© ÆÐŶÀÌ ¼Û/¼ö½ÅµÇ´Â °úÁ¤À» ÆÐŶÀÇ Àü´Þ °úÁ¤À» µû¶ó°¡¸ç »ìÆìº¸¾Ò´Ù. Áö±ÝºÎÅÍ À̸¦ °£´ÜÈ÷ ºí·°µµ·Î Á¤¸®ÇÏ¿© °¢ °èÃþ¿¡¼­ ÆÐŶÀÇ ¼Û/¼ö½ÅÀ» ó¸®ÇÏ´Â °ÍÀ» ´Ü°è º°·Î »ìÆìº¸±â·Î ÇÑ´Ù. <±×¸² 3>¿¡¼­ ¿ÞÂÊÀÌ ¼ö½Å °úÁ¤, ¿À¸¥ÂÊÀÌ ¼Û½Å °úÁ¤À» º¸¿©ÁØ´Ù.

µ¥ÀÌÅÍ ¸µÅ© °èÃþ
<±×¸² 3>Àº µ¥ÀÌÅÍ ¸µÅ© °èÃþ¿¡¼­ ÆÐŶÀÌ ¼Û/¼ö½Å µÇ´Â °úÁ¤À» º¸¿©ÁØ´Ù. ÆÐŶÀÌ ¼ö½ÅµÇ¸é ÀÎÅÍ·´Æ® ó¸® ·çƾ¿¡ ÀÇÇØ ¼ÒÄÏ ¹öÆÛ¸¦ »ý¼ºÇÏ¿© µ¥ÀÌÅ͸¦ º¹»çÇϰí Çϵå¿þ¾î Çì´õ Á¤º¸¸¦ ¼³Á¤ÇÑ µÚ ÇöÀç CPUÀÇ ¼ö½Å Å¥¿¡ ³Ö°í softirq¿¡°Ô·Î 󸮸¦ ³Ñ±ä´Ù. ÆÐŶÀ» ¼Û½ÅÇÒ ¶§´Â ÀÏ´Ü ³×Æ®¿öÅ© ÀåÄ¡¸¶´Ù ÇÒ´çµÈ Å¥¿¡ ¼ÒÄÏ ¹öÆÛ¸¦ ³Ö°í ÇöÀç ¼Û½ÅÀÌ °¡´ÉÇÑÁö¸¦ °Ë»çÇÏ¿© µð¹ÙÀ̽º µå¶óÀ̹öÀÇ hard_start_xmit ·çƾÀ» È£ÃâÇÏ¿© Á÷Á¢ ¼Û½ÅÇϰųª softirq¸¦ ¹ß»ý½ÃÄÑ ÀÌÈÄ¿¡ ¼Û½ÅÇϵµ·Ï ÇÑ´Ù. ¾Õ¿¡¼­ µð¹ÙÀ̽º µå¶óÀ̹ö °èÃþÀÇ ÇÔ¼ö´Â <drivers/net/pci-skeleton.c> ³»ÀÇ Ã³¸® ÇÔ¼öµé¿¡ ÇØ´çÇÑ´Ù.

<±×¸² 3> µ¥ÀÌÅÍ ¸µÅ© °èÃþ

³×Æ®¿öÅ© °èÃþ - IP
<±×¸² 4>´Â ³×Æ®¿öÅ© °èÃþÀÇ ÆÐŶ Àü¼ÛµµÀÌ´Ù. Ä¿³ÎÀÇ ÄÄÆÄÀÏ °úÁ¤¿¡¼­ ³×Æ®¿öÅ© ÇÊÅ͸µ(network filtering) ±â´ÉÀÌ Æ÷ÇÔµÇ¸é ÆÐŶÀÇ Àü¼Û °úÁ¤¿¡¼­ ´ÙÀ½°ú °°Àº 5°¡ÁöÀÇ Netfilter HookÀ» °ÅÄ¡´Â µ¥ °¢°¢ÀÇ ¿ªÇÒÀº ´ÙÀ½°ú °°´Ù.

¡ß NF_IP_PRE_ROUTING : ³×Æ®¿öÅ© ÀåÄ¡·ÎºÎÅÍ ¼ö½ÅµÈ ¸ðµç ÆÐŶÀ» ó¸®ÇÑ´Ù. ½ÇÁ¦·Î ÆÐŶ¿¡ ´ëÇÑ Ã³¸®°¡ ÀÌ·ç¾îÁö±â Àü¿¡ ÇÊÅ͸µÀÌ °¡´ÉÇÏ°Ô µÇ¹Ç·Î DOS °ø°Ý¿¡ ´ëÇÑ Ã³¸®³ª ¸ñÀûÁö ³×Æ®¿öÅ© ÁÖ¼Ò º¯È¯(DNAT)ÀÇ Ã³¸®, Åë°è Á¤º¸ ±â·Ï µîÀ» Çϱ⿡ ¾Ë¸Â´Ù.
¡ß NF_IP_LOCAL_IN : ·ÎÄà ¸Ó½Å¿¡°Ô Àü¼ÛµÈ ÆÐŶ¸¸À» ó¸®ÇÑ´Ù.
¡ß NF_IP_FORWARD : ·ÎÄà ¸Ó½ÅÀ» ÅëÇØ ´Ù¸¥ ¸Ó½Å¿¡°Ô·Î forwardingµÇ´Â ÆÐŶ¸¸À» ó¸®ÇÑ´Ù.
¡ß NF_IP_LOCAL_OUT : ·ÎÄà ¸Ó½Å¿¡¼­ ¼Û½ÅÇÏ´Â ÆÐŶ¸¸À» ó¸®ÇÑ´Ù.
¡ß NF_IP_POST_ROUTING : ³×Æ®¿öÅ© ÀåÄ¡¸¦ ÅëÇØ ¼Û½ÅÇÏ´Â ¸ðµç ÆÐŶÀ» ó¸®ÇÑ´Ù(forwarding ÆÐŶ Æ÷ÇÔ). Ãâ¹ßÁö ³×Æ®¿öÅ© ÁÖ¼Ò º¯È¯(SNAT)À̳ª masqueradingÀÇ Ã³¸®, Åë°è Á¤º¸ ±â·Ï µîÀ» Çϱ⿡ ¾Ë¸Â´Ù.

<±×¸² 4> ³×Æ®¿öÅ© °èÃþ

Àü¼Û °èÃþ - TCP
<±×¸² 5>´Â Àü¼Û °èÃþÀÇ ÆÐŶ ó¸® °úÁ¤À» º¸¿©ÁØ´Ù. TCP °èÃþ¿¡¼­ ÆÐŶÀ» ¼ö½ÅÇϸé ÇöÀç ¼ÒÄÏÀÇ »óÅ¿¡ µû¶ó °¢±â ´Ù¸¥ ÇÔ¼ö°¡ È£ÃâµÈ´Ù. ¼ÒÄÏÀÌ ¿¬°áµÈ »óÅÂÀÇ Ã³¸® ÇÔ¼öÀÎ tcp_rcv_established()´Â ¼ÒÄÏ ¹öÆÛÀÇ µ¥ÀÌÅ͸¦ »ç¿ëÀÚ °ø°£ÀÇ ¹öÆÛ¿¡ º¹»çÇϸç À̸¦ ±â´Ù¸®¸ç Àáµç ÇÁ·Î¼¼½º°¡ ÀÖ´Ù¸é ±ú¿î´Ù. ¼Û½Å °úÁ¤¿¡¼­´Â ¼ÒÄÏ ¹öÆÛ¸¦ »ý¼ºÇÏ¿© µ¥ÀÌÅ͸¦ º¹»çÇÏ°í ¸ðµç °èÃþÀÇ Çì´õ Á¤º¸°¡ µé¾î°¥ ¸¸ÇÑ °ø°£À» È®º¸ÇØ µÐ´Ù.

<±×¸² 5> Àü¼Û °èÃþ

Ä¿³Î ÇØÄ¿°¡ ¸¹ÀÌ µîÀåÇϱæ
À̹ø ±Û¿¡¼­´Â ¸®´ª½ºÀÇ ³×Æ®¿öÅ© ¼­ºê ½Ã½ºÅÛ¿¡ ´ëÇØ °£·«ÇÏ°Ô »ìÆìº¸¾Ò´Ù. ¹°·Ð ÀÌ ¹Û¿¡µµ ´õ ¸¹Àº ºÎºÐÀÌ ÀÖÁö¸¸ ÇÊÀÚÀÇ ºÎÁ·ÇÑ ½Ç·Â°ú ÇÑÁ¤µÈ Áö¸éÀ¸·Î ÀÎÇØ ´õ ¼Ò°³ÇÏÁö ¸øÇÑ °ÍÀÌ ¾Æ½±±â¸¸ ÇÒ µû¸§ÀÌ´Ù.

Ç×»ó ½ÃÀÛÇÒ ¶§´Â ¸¶À½¸¸ ¾Õ¼­¼­ ¸¹Àº °ÍÀ» ¼Ò°³ÇÏ·Á°í ÇÏ´Ù°¡ µÚ·Î °¥¼ö·Ï ÇÊÀÚÀÇ ÇѰ踦 ±ú´Ý°í ¿ëµÎ»ç¹ÌÀÇ ÇüÅ·ΠÁøÇàµÇ´Â °Í °°¾Æ ºÎ²ô·´°í µ¶Àڵ鿡°Ô Á˼۽º·¯¿î ¸¶À½ÀÌ µç´Ù. ¾ÕÀ¸·Î ±¹³»¿¡¼­µµ ÈǸ¢ÇÑ Ä¿³Î ÇØÄ¿°¡ ¸¹ÀÌ µîÀåÇÏ¿© ¸®´ª½º Áø¿µ¿¡¼­ Ȱ¾àÀ» ÇØ ÁÖ±æ ±â´ëÇϸç 3ȸ¿¡ °ÉÄ£ ¸®´ª½º Ä¿³Î 2.6¿¡ ´ëÇÑ ¿¬À縦 ¸¶Ä¡°íÀÚ ÇÑ´Ù.@

* ÀÌ ±â»ç´Â ZDNet KoreaÀÇ Á¦ÈÞ¸ÅüÀÎ ¸¶ÀÌÅ©·Î¼ÒÇÁÆ®¿þ¾î¿¡ °ÔÀçµÈ ³»¿ëÀÔ´Ï´Ù.
°ü·Ã±â»ç
[¸®´ª½º Ä¿³Î 2.6ÀÇ ¼¼°è] ¨ç Ä¿³Î ºôµå¡¤ºÎÆÃ °úÁ¤ ºÐ¼®
Åä¹ßÁî, Ä¿³Î °ü¸® SW ³íÀÁ¾ÁöºÎ Âï´Ù¡¹
Åä¹ßÁ¸®´ª½º¿¡°Õ »õ ÁýÀÌ ÇÊ¿äÇÏ´Ù¡¹
Åä¹ßÁî, ¸®´ª½º ¼º´É¡¸Á¤±âÀûÀ¸·Î Å×½ºÆ®ÇÏÀÚ¡¹
¿ÀǼҽº·Î »õ·Ó°Ô µµÀüÇϴ¡¸½ã ¼Ö¶ó¸®½º 10¡¹
Åä¹ßÁî°¡ ¹àÈ÷´Â¡¸¿ÀǼҽº ¼Ö¶ó¸®½º¿Í ¸®´ª½º °³¹ß öÇС¹
[óÀ½ºÎÅÍ ´Ù½Ã ¹è¿ì´Â ¸®´ª½º] ¨ç ¼³Ä¡¿Í ±âº» ¸í·É¾î
Ä¿³Î 2.6À¸·Î ¾÷±×·¹À̵å!¡¸A to Z¡¹
¸ÞÀνºÆ®¸² OS·Î ·¹º§¾÷¡¸¸®´ª½º Ä¿³Î2.6¡¹
µ¶ÀÚÀÇ°ß ³²±â±â (·Î±×ÀÎ ÈÄ µ¶ÀÚ ÀǰßÀ» ³²±â½Ç ¼ö ÀÖ½À´Ï´Ù.)
¾ÆÀ̵ð ºñ¹Ð¹øÈ£
 
 
[¼öÆÛ°³¹ßÀÚÀÇ ±æ ¨í] Çʼö ¾ÆÀÌ...
[¼öÆÛ°³¹ßÀÚÀÇ ±æ ¨è] ¿ëÀ» ¸¸³ª...
[¼öÆÛ°³¹ßÀÚÀÇ ±æ ¨ç] °¡½¿ÀÇ ²Þ...
[¼öÆÛ°³¹ßÀÚÀÇ ±æ ¨ê] ±âº»±â ¾ø...
[¼öÆÛ°³¹ßÀÚÀÇ ±æ ¨ì] ÇÁ·Î±×·¡¹Ö...
[¼öÆÛ°³¹ßÀÚÀÇ ±æ ¨é] ³ª´®°ú ±³...
[¼öÆÛ°³¹ßÀÚÀÇ ±æ ¨ë] »õ·Î¿î ½Ã...
'ÁÖÃãÁÖÃã ¼Ò´Ï' º¸±ÞÇü Ä·ÄÚ´õ ½ÃÀå »ï¼º ¸Í°ø¡¦À¯Æ©ºê ¸ÂÃãÇü 'VM-MX20C' [00:07:48]
ÁøÇà ·ùÁØ¿µ ±âÀÚ, Á¦ÀÛ À¯È¸Çö PD
[ZDNET ¿µ¹®¹æ¼Û]±¸±Û À¥ºê¶ó¿ìÀú '±¸±Û Å©·Ò' º£Å¸¹öÀü °ø°³ [00:01:29]
Áöµð³ÝÄÚ¸®¾Æ ¿µ»óÁ¦ÀÛÆÀ
¡°À¥ Ç¥ÁØÀº ¹«½¼!¡±¡¦IE8¿¡ ´ë...
°øÀÎÀÎÁõüÁ¦, ¿ì¸®¿¡°Ô ÀÓ¹ÚÇÑ ¹Ì...
³×À̹ö´Â ¿Ö '10´ë ÇØÄ¿'¿¡ ´ç...
[¼öÆÛ°³¹ßÀÚÀÇ ±æ ¨ç] °¡½¿ÀÇ ²Þ...
"¾×ƼºêX¿Í °øÁ¸ ¸ð»ö"¡¦±¸±Û, ...
'À§ÇÇ Àǹ«È­' ÆóÁö ºÐÀ§±â·Î¡¦