[Áöµð³ÝÄÚ¸®¾Æ]³×Æ®¿öÅ© ¼ºê ½Ã½ºÅÛÀº ¸®´ª½º°¡ Áö±Ýó·³ ³Î¸® È®»êµÇ´Âµ¥ ¸¹Àº °øÇåÀ» ÇßÀ¸¸ç, ¸®´ª½ºÀÇ ÃÖ´ë ÀåÁ¡ ÁßÀÇ Çϳª·Î Àνĵǰí ÀÖ´Â ºÐ¾ßÀÌ´Ù. ÀÌó·³ Áß¿äÇÑ À§Ä¡¸¦ Â÷ÁöÇϰí ÀÖÀ½¿¡µµ Áö±Ý²¯ ¸®´ª½º Ä¿³ÎÀÇ ³×Æ®¿öÅ© ¼ºê ½Ã½ºÅÛÀÇ ±¸Á¶¸¦ ºÐ¼®Çϰí ÀÌÇØÇÏ·Á´Â ½Ãµµ°¡ ¸¹ÀÌ ºÎÁ·ÇÑ °ÍÀÌ »ç½ÇÀÌ´Ù.
À̹ø ±Û¿¡¼´Â ¸®´ª½ºÀÇ ÃÖ´ë ÀåÁ¡ Áß Çϳª·Î ²ÅÈ÷´Â ³×Æ®¿öÅ· ºÎºÐ¿¡ ´ëÇÑ ±¸ÇöÀ» »ìÆìº¸°Ú´Ù. ³×Æ®¿öÅ© ÄÚµå´Â ³Ê¹«³ª ¹æ´ëÇÑ ¿µ¿ªÀ̱⠶§¹®¿¡ ÇÑ ¹ø¿¡ »ìÆìº¸´Â °ÍÀÌ ºÒ°¡´ÉÇϹǷΠ¾ÆÁÖ ´Ü¼øÇÑ ¼ÒÄÏ ÇÁ·Î±×·¥À» ¿¹Á¦·Î ÇÏ¿© ±âº»ÀûÀÎ ¼ÒÄÏÀÇ »ý¼º, ¿¬°á, µ¥ÀÌÅÍ Àü¼Û/¼ö½Å °úÁ¤¿¡ ´ëÇØ »ìÆìº¸±â·Î ÇÑ´Ù. ³×Æ®¿öÅ©´Â ¶ÇÇÑ º¸¾È¿¡ ¹Î°¨ÇÑ ¿µ¿ªÀ̱⠶§¹®¿¡ °÷°÷¿¡ º¸¾ÈÀ» À§ÇÑ ÄÚµåµéÀÌ Æ÷ÇԵǾî ÀÖÀ½À» È®ÀÎÇÒ ¼ö ÀÖÀ» °ÍÀÌ´Ù(°¡Àå ÃֽйöÀüÀÇ ¾ÈÁ¤ Ä¿³ÎÀÎ 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ÀÇ Á¦ÈÞ¸ÅüÀÎ ¸¶ÀÌÅ©·Î¼ÒÇÁÆ®¿þ¾î¿¡ °ÔÀçµÈ ³»¿ëÀÔ´Ï´Ù.