다음 이전 차례

7. 멀티캐스트 내부

이 절의 목적은 멀티캐스트가 어떻게 작동하는지를 이해하는데 필요한 정보를 제공하는 것 도 아니고 멀티캐스트 프로그래밍에 대한 정보를 제공하자는 것도 아니다. 하지만 멀티캐스트의 기반을 이루는 프로토콜과 구현을 살펴봄으로서 쉽게 저지르는 실수와 잘못된 이해를 피할 수 있을 것이다.

7.1 IGMP.

IP_ADD_MEMBERSHIP 과 IP_DROP_MEMBERSHIP에서 이 명령으로 커널에 제공한 정보는 어떤 멀티캐스트 데이터그램을 받고 어떤 것을 버릴 것인지를 결정하는데 쓰인다고 했다. 맞는 말이라고 할 수 있지만, 모두 맞는 말은 아니다. 이러한 일반화는 전 세계 모든 멀티캐스트데이터그램이 우리의 호스트로 전달된 후, 호스트에서 프로세스가 발행한 회원관계를 확인 후 데이터그램의 폐기 여부를 결정한다는 말이 된다. 생각할 필요도 없이, 이것은 엄청난 대역폭 낭비임을 알 수 있다.

실제로는 호스트가 자신의 라우터에게, 그 라우터는 상위 라우터에게, 그리고 그 상위 라우터에게....어떤 멀티캐스트 그룹에 관심이 있는지 알려준다. 멀티캐스트 그룹 트래픽을 받을 것인지 말 것인지 결정하는 알고리즘 자체에는 상당히 변화가 심한데, 단 한가지 변하지 않는 것이 있다면, 이 정보를 전달하는 방법이다. 이것은 IGMP(Internet Group Management Protocol을 이용한다. 프로토콜번호 2인 IGMP는 ICMP와 유사한 새로운 프로토콜인데 IP 데이터그램을 이용하며 레벨 2 적응단계의 호스트는 이 프로토콜을 의무적으로 구현해야 한다. 전술한 바와 같이 이것은 라우터에게 회원정보를 전송하는 호스트와 라우터사이의 통신 양쪽 모두 사용한다. 다음 글에서 호스트-라우터간 관계만을 설명하기로 한다. 왜냐하면 mrouted소스 코드를 제외하고는 라우터-라우터간 통신을 해설하는 자료를 찾지 못하였기 때문이다. (RFC 1075-Distance Vector Multicast Routing Protocol은 이제 사용하지 않으며, mrouted는 아직 문서화되지 않은 변형된 DVMRP를 구현하고 있다.)

RFC 988-IGMP 버전 0은 이제 사용하지 않는다.

IGMP 버전 1은 RFC-1112에 정의되어 있고, RFC-2236 (IGMP version 2) 에서 개정되어 현재까지 많이 사용하고 있다. 리눅스 커널에서는 IGMP 버전 1 전체와 버전 2일부가 구현되어 있다.

지금부터 이 프로토콜에 대한 약식설명을 보자. RFC-2236을 펼쳐 놓고 정확한 정식 설명을 보는 것도 좋다.

모든 IGMP 메시지는 다음 구조를 가진다.

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |      Type     | Max Resp Time |           Checksum            |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                         Group Address                         |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

IGMP 버전 1 (이하 IGMPv1) 는 전송시 "Max Resp Time" 을 "Unused",즉 모두 0 으로 하고 수신시에는 무시한다. "Type"란은 4비트 폭으로 나누어 "Version"과 "Type"으로 사용한다. IGMPv1 에서는 "회원질의(Membership Query)"를 0x11 (version 1, type 1)으로 확인하고, IGMPv2 에서는 0x11 로 확인하기 때문에 8비트를 사실상 동일하게 해석 한다.

IGMPv2 는 주로 추가사항들로 이루어져 있기 때문에 IGMPv1 을 일단 설명한 후 IGMPv2 추가사항을 설명하는 편이 좋을 것 같다.

다음 논의에서 라우터는 모든 IP 멀티캐스트 데이터그램을 받는다는 것을 기억하라.

7.2 IGMP version 1.

라우터는 주기적으로(1분에서 2분에 한번씩) TTL값 1의 IGMP 호스트 회원 질의를 전체 호스트 그룹(224.0.0.1)으로 보낸다. 모든 멀티캐스트 호스트들이 이 메시지를받지만 IGMP 호스트 회원 보고(Host Membership Report)가 폭주(storm)하는 것을 방지하기 위해 즉시 응답하지 않는다. 대신 질의를 수신한 인터페이스에 속하는 각 그룹에 대해, 임의 지연 타이머를 시작한다.

조만 간에 타이머가 완료되면 호스트는 역시 TTL 1의 IGMP 회원 보고를 멀티캐스트 그룹어드레스로 전송한다. 이 메시지는 이미 그룹에 참여하고 있는 모든 호스트들과 타이머가 완료되기를 기다리고 있는 호스트들에게 전달된다. 그러면 각 호스트들은 타이머를 중지하고 더 이상 아무런 보고도 하지 않는다. 하지만 이것으로 라우터는 자신의 서브넷에 그 멀티캐스트 그룹의 멤버가 존재한다는 것만 알면 되기 때문에 회원이 몇이나 있는지 알기 위해 더 이상, 보고 받을 필요가 없다.

몇 번 질의한 후에도 그 그룹에 대해 아무런 회원 보고가 없으면 라우터는 멤버가 없는 것으로 간주하고 해당 그룹의 트래픽을 서브넷으로 포워딩하지 않는다. IGMPv1 에서는 "그룹 탈퇴 메시지(Leave Group messages)"가 없다는 점에 주목하라.

호스트가 새 그룹에 참여하면 커널은 그룹으로 보고를 보내기 때문에 각각의 프로세스들은 새로운 회원 질의가 도착할 동안(1,2분 정도) 기다릴 필요가 없다. "IP_ADD_MEMBERSHIP" 정에서 보았겠지만, 이 IGMP 패킷은 IP_ADD_MEMBERSHI명령에 대한 응답으로 커널이 생성한다. "새 그룹"이라는 말을 주의 깊이 보자. 호스트가 이미 참여중인 그룹에 대해 프로세스가 IP_ADD_MEMBERSHIP 명령을 보낼 경우 우리는 이미 그 그룹의 트래픽을 받고 있기 때문에 아무런 IGMP 패킷도 만들어지지 않을 것이다. 대신 그룹사용 카운터가 증가한다. IGMPv1에서 IP_DROP_MEMBERSHIP 명령은 데이터그램을 생성시키지 않는다.

호스트 회원 질의는 타입 0x11, 호스트 회원 보고는 각각 타입 0x12로 구분한다.

전체 호스트 그룹에는 보고하지 않는다. 이 그룹으로의 회원은 영구적이다.

7.3 IGMP 버전 2.

상기 내용에 대한 추가 사항 중 중요한 것 한가지는 그룹 이탈 메시지(타입0x17)가 포함되었다는 사실이다. 이 메시지는 서브넷에서 마지막 호스트가 그룹을 이탈하는 시점과 질의 시간이 만료되어 라우터가 더 이상 그룹에 남아있는 회원이 없다고 결정하는 시점 사이의 대역폭 낭비(이탈 지연-leave latency)를 줄이기 위해 추가되었다. 그룹 이탈 메시지는 그룹의 다른 멤버들에게는 불필요한 정보이기 때문에 남아있는 그룹보다 전체 라우터 그룹(224.0.0.2)쪽으로 전송해야 한다. (커널 버전 2.0.33 이하에서는 이 메시지를 그룹으로 보냈었다. 호스트로서는 해를 입을 일은 없지만, 쓸데없는 정보이기 때문에 이 정보를 처리하는 것은 시간낭비일 뿐이다.) 언제 이탈 메시지를 보낼 것인가, 언제 보내지 않을 것인가 하는 문제에 대해서는 몇 가지 미묘한 문제가 있다. 관심이 있다면 RFC를 참조할 것.

IGMPv2라우터가 이탈 메시지를 받으면 라우터는 그룹을 지정하여(group-specific) 남아있는 그룹에게 질의를 보낸다. 이것도 IGMPv2 에서 추가된 사항이다. IGMPv1에서 그룹 지정 질의는 없었다. 모든 질의가 전체 호스트 그룹으로 보내는 질의였다. IGMP 헤더에 정의된 타입 값은 변하지 않았지만(전과 동일하게 0x11), "그룹 주소(Group Address)"필드는 남아있는 멀티캐스트 그룹 주소로 채워진다.

IGMPv1에서 전송시 0으로 채우고 수신시 무시하기로 하였던 "Max Resp Time" 필드는 "Membership Query"에서만 의미가 있다. 이 필드는 보고해야할 한계 시간을 설정하는데 쓰인다. 성능을 조절하는 메커니즘으로 사용한다고 볼 수 있다.

IGMPv2에서 새로운 메시지 타입 0x16이 추가되었다. 이것은 "Version 2 Membership Report"로서 IGMPv2 호스트가 IGMPv2 라우터를 발견했을 때 전송한다. (IGMPv2 호스트는 "Max Response" 필드가 0 으로 채워진 패킷을 확인하여 IGMPv1 라우터가 존재한다는 것을 알아낸다).

동시에 여러 라우터가 질의를 할 때, IGMPv2 는 "discussions"를 회피하는 메커니즘을 제공한다. 이 경우 낮은 IP 주소를 가진 라우터가 질의자(querier)가 되고 다른 라우터는 타이머를 설정한다. 낮은 번호의 라우터가 어떤 이유로 제대로 작동하지 못하면 타이머가 만료된 후 다시 질의자를 설정한다.

7.4 커널 관련 사항

이 절에서는 리눅스 커널에서 멀티캐스트 구현을 학습하기 위한 실마리를 보여줄 것이다. 구현 자체를 설명하지는 않는다. 단지 어디서 찾을 것인지만 알려주다.

이 내용은 2.0.32에서의 설명이므로 이 글을 읽는 시점에서 좀 오래된 내용일지도 모른다. (네트웍 코드는 2.1.x에서 많이 변경되었다.

리눅스 커널에서 멀티캐스트 코드는 항상 #ifdef CONFIG_IP_MULTICAST / #endif 쌍으로 둘러싸여 있기 때문에 필요하다면 언제든지 커널에 포함(inclusion/exclusion)시키거나 배제시킬 수 있다. (이 포함/배제는 컴파일 시에 행해지며 #ifdef 구문은 선행처리기가 하는 작업이라는 것을 알고 있을 것이다. 포함여부 결정은make config, make menuconfig 또는 make xconfig를 실행시킬 때 할 수 있다.)

멀티캐스트 라우터 기능을 사용하고 싶다면 #ifdef CONFIG_IP_MROUTE / #endif쌍 속의 코드들을 활성화 시켜야 한다.

커널 소스는 보통 /usr/src/linux에 있다. 하지만 위치는 변할 수도 있는 것이기 때문에 커널 소스의 위치를 간단 명료하게 LINUX라고 가정하자. 이제 커널소스를 /usr/src/linux 에 풀었을 경우, LINUX/net/ipv4/udp.c 는 /usr/src/linux/net/ipv4/udp.c 를 의미한다.

사용자 프로그램에서의 멀티캐스트 인터페이스는 멀티캐스트 프로그래밍을 설명한 절에서 setsockopt()/ getsockopt()를 통해 모두 보여 주었다. 이 두 함수는 전달받은 변수의 유효성을 검사한 다음, 다른 몇 가지 함수를 호출하여 추가 적으로 검사하고, 또 다른 함수를 호출하는 식으로 구현되었다. (이 모든 함수 호출에 관심이 있다면 LINUX/net/socket.c (함수 sys_socketcall() 와 sys_setsockopt()), LINUX/net/ipv4/af_inet.c (함수 inet_setsockopt()) 그리고 LINUX/net/ipv4/ip_sockglue.c (함수 ip_setsockopt()) 를 참조하라.)

LINUX/net/ipv4/ip_sockglue.c도 주의 깊게 보아야 한다. 여기에는 함수 ip_setsockopt() 와 ip_getsockopt() 가 들어 있는데 대부분은 (어떤 에러 체크 후에) 가능한 optname을 검사하는 스위치같은 것이다. 유니캐스트 옵션과 함께, IP_MULTICAST_TTL, IP_MULTICAST_LOOP, IP_MULTICAST_IF, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP같은 모든 멀티캐스트 옵션을 처리한다. 이 스위치 이전에 옵션을 검사하여 그것이 멀티캐스트 라우터 지정 옵션이라면 함수 ip_mroute_setsockopt() 와 ip_mroute_getsockopt() 로 라우팅 된다. (파일 LINUX/net/ipv4/ipmr.c 에 있음).

LINUX/net/ipv4/af_inet.c 에서 이전 절에서 논의했던 소켓 생성 기본 값을 볼 수 있다. (loopback enabled, TTL=1, 함수 inet_create() 중에서)


  #ifdef CONFIG_IP_MULTICAST
          sk->ip_mc_loop=1;
          sk->ip_mc_ttl=1;
          *sk->ip_mc_name=0;
          sk->ip_mc_list=NULL;
  #endif

다음 코드가 "소켓을 닫으면 커널은 이 소켓에 있던 모든 회원을 탈퇴시킨다"는 내용을 단정적으로 보여준다. (위와 동일 파일의 함수 inet_release()에서)


  #ifdef CONFIG_IP_MULTICAST
                  /* Applications forget to leave groups before exiting */
                  ip_mc_drop_socket(sk);
  #endif

링크 계층의(Link Layer)의 장치 독립적인(Device independent) 연산들은 LINUX/net/core/dev_mcast.c 에 있다.

아직 두 가지 중요한 함수들을 설명하지 않았다. 입력 처리 함수와 멀티캐스트 데이터그램 출력 함수이다. 다른 데이터그램들과 마찬가지로 입력 데이터그램은 장치 드라이버로부터 ip_rcv() 합수(LINUX/net/ipv4/ip_input.c)로 전달된다. 이 함수에서 하위 계층으로부터 전해진 멀티캐스트 패킷을 완벽하게 필터링한다(하위레이어에서 최대한 필터링하지만, IP 계층에서 우리가 관심을 가지고 있는 그룹에 대해 100% 알고 있기 때문에 패킷을 완전하게 필터링한다고 했던것을 기억하자.) 호스트가 멀티캐스트 라우터로 작동중이라면 역시 이 함수가 패킷 포워딩 여부를 결정하고 적절하게 ipmr_forward()를 호출한다. (ipmr_forward() 은 LINUX/net/ipv4/ipmr.c에 구현되어 있다.).

패킷 출력 임무를 맡은 코드는 LINUX/net/ipv4/ip_output.c에 담겨져 있다. 이곳에서 패킷을 루프백 할지 안 할지(안한다면 ip_queue_xmit()호출) 검사하기 때문에IP_MULTICAST_LOOP 옵션이 효력을 발휘하는 곳이다. 또한, 외부로 향하는 패킷이 멀티캐스트인지 유니캐스트인지에 의거하여 TTL을 정하는 곳이기도 하다. 전자의 겨우 IP_MULTICAST_TTL 로 전달된 변수를 사용한다(함수 ip_build_xmit()).

mrouted(커널에 멀티캐스트 데이터그램 라우팅 방법을 알려주는 프로그램)로 작업하는 동안, 우리는 멀티캐스트 라우터로 작동하는 우리의 리눅스 박스에서 만들어진 패킷을 제외한, 로컬 네트웍에서 생성된 멀티캐스트 데이터그램은 모두 적절하게 라우팅되는 것을 발견했다. ip_input.c 는 제대로 작동하고 있는것 같았지만 ip_output.c 는 그렇지 않았다. 출력 프로그램의 소스 코드를 읽는 동안 외부로 나가는 데이터그램들이 라우팅 여부를 결정하는 함수 ipmr_forward()를 거치지 않는 것을 발견했다. 패킷들은 로컬 네트웍으로 출력되었지만 네트웍 카드는 자신이 전송하는 데이터그램을 읽을 수 없었고, 이런 데이터그램들은 라우팅되지 않았다. 우리가 ip_build_xmit() 함수에 적절한 코드를 추가하자 모든 것이 올바로 작동하였다. (소스 수정은 사치를 떠는 것도 유식한척하는 것도 아니다; 필요다!)

ipmr_forward() 는 수 차례 언급했었다. ipmr_forward() 는 우리가 흔히 잘못 이해하고 있는 것을 풀어줄 수 있기 때문에 아주 중요한 함수이다. 멀티캐스트 트래픽을 라우팅할 때, 패킷 사본을 만들고 그것을 올바른 수신자에게 전달하는 것은 mrouted자체가 아니다. mrouted는 모든 멀티캐스트 트래픽을 수신하여, 그 정보에 근거하여 , 멀티캐스트 라우팅 테이블을 계산해 내고 커널에 라우팅 방법을 알려준다. "이 인터페이스에서 들어오는 저 그룹의 데이터그램은 저 인터페이스로 보내라."

이 라우팅 정보는 mrouted 데몬(raw 소켓 생성시 지어된 프로토콜은 IPPROTO_IGMP이어야 한다.)이 만든 raw 소켓에서 setsockopt()를 호출하여 커널에 설정한다. 이 옵션은 LINUX/net/ipv4/ipmr.c 의 ip_mroute_setsockopt()함수에서 처리한다. 소켓에서 발행한 첫번째 옵션(would be better to call them commands rather than options)은 MRT_INIT이어야 한다. 첫 번째 발행한 옵션이 MRT_INIT이 아니라면 다른 모든 명령은 무시한다. (-EACCES를 반납) 한 호스트 상에는 mrouted의 인스턴스가 꼭 하나만 존재할 수 있다. 이것을 추적하기 위해 첫 번째 MRT_INIT 을 받았을 때 구조체 sock* mroute_socket이 MRT_INIT 을 수신한 소켓을 가리키게 된다. 만일 MRT_INIT 을 발행했을때 mroute_socket이 널(null)값을 가지지 않는다면 이미 다른 mrouted가 작동중임을 의미하므로 -EADDRINUSE 을 반납한다. 나머지 다른 명령들(MRT_DONE, MRT_ADD_VIF, MRT_DEL_VIF, MRT_ADD_MFC, MRT_DEL_MFC and MRT_ASSERT)은 mroute_socket과 다른 소켓에서 올 경우 -EACCES 를 반납한다.

라우팅된 멀티캐스트 데이터그램은 물리적 인터페이스 혹은 (가상적인) 터널을 통해 전송하기 때문에, 일반적인 추상화(abstraction) 단계를 VIFs, 즉, 가상 인터페이스 (Virtual InterFaces)고안해냈다. mrouted는 물리 혹은 터널 인터페이스를 가리키는 vif 구조체를 라우팅 테이블에 추가하기 위하여 커널에 넘겨주고, 데이터그램을 어디로 포워딩할지 알려주는 멀티캐스트 포워딩 목록(multicast forwarding entries)에도 알려준다.

VIFs 는 MRT_ADD_VIF 로 추가하고 MRT_DEL_VIF 로 삭제한다.두 함수 모두 vifctl 구조체를 커널로 넘긴다. ( /usr/include/linux/mroute.h) 에서 다음과 같이 정의하고 있다.


  struct vifctl {
          vifi_t  vifc_vifi;              /* Index of VIF */
          unsigned char vifc_flags;       /* VIFF_ flags */
          unsigned char vifc_threshold;   /* ttl limit */
          unsigned int vifc_rate_limit;   /* Rate limiter values (NI) */
          struct in_addr vifc_lcl_addr;   /* Our address */
          struct in_addr vifc_rmt_addr;   /* IPIP tunnel addr */
  };

이 정보를 통해 vif_device 구조체를 만든다.


  struct vif_device
  {
          struct device   *dev;                   /* Device we are using */
          struct route    *rt_cache;              /* Tunnel route cache */
          unsigned long   bytes_in,bytes_out;
          unsigned long   pkt_in,pkt_out;         /* Statistics */
          unsigned long   rate_limit;             /* Traffic shaping (NI) */
          unsigned char   threshold;              /* TTL threshold */
          unsigned short  flags;                  /* Control flags */
          unsigned long   local,remote;           /* Addresses(remote for tunnels)*/
  };

이 구조체에서 dev 항목을 주목하라. device 구조체는 /usr/include/linux/netdevice.h 에서 정의하고 있다. 아주 큰 구조체이지만 우리는 다음 필드에만 관심을 두면 된다.

struct ip_mc_list* ip_mc_list; /* IP multicast filter chain */

ip_mc_list 구조체는 /usr/include/linux/igmp.h에서 다음과 같이 정의하고 있다. :


  struct ip_mc_list
  {
          struct device *interface;
          unsigned long multiaddr;
          struct ip_mc_list *next;
          struct timer_list timer;
          short tm_running;
          short reporter;
          int users;
  };

dev 구조체의 ip_mc_list 는 ip_mc_list 형 구조체의 연결리스트를 가리키는 포인터이다. ip_mc_list 는 해당 네트웍 인터페이스가 멤버로 참여하고 있는 멀티캐스트 그룹을 담고있다. 여기서 다시 한번, 회원은 인터페이스와 관계가 있음을 알 수 있다. LINUX/net/ipv4/ip_input.c 는 데이터그램이 (데이터그램을 수신한 인터페이스가 속하는 그룹 가운데) 어떤 그룹에 속한 것인지 결정하기 위해 이 연결리스트를 순회한다.


  #ifdef CONFIG_IP_MULTICAST
                  if(!(dev->flags&IFF_ALLMULTI) && brd==IS_MULTICAfST
                     && iph->daddr!=IGMP_ALL_HOSTS
                     && !(dev->flags&IFF_LOOPBACK))
                  {
                          /*
                           *      Check it is for one of our groups
                           */
                          struct ip_mc_list *ip_mc=dev->ip_mc_list;
                          do
                          {
                                  if(ip_mc==NULL)
                                  {
                                          kfree_skb(skb, FREE_WRITE);
                                          return 0;
                                  }
                                  if(ip_mc->multiaddr==iph->daddr)
                                          break;
                                  ip_mc=ip_mc->next;
                          }
                          while(1);
                  }
  #endif

ip_mc_list구조체에서 users 필드는 "IGMP 버전 1"에서 설명했던 것을 구현하기 위해 사용한다. 프로세스가 그룹에 참여 할때, 인터페이스가 이미 그 그룹의 회원이라면 (다시 말해서, 동일 인터페이스로 동일 그룹에 참여한 프로세스가 이미 있으면) 멤버 수(users)만 증가시킨다. IGMP 메시지를 보내지 않음을, 다음 코드에서 볼 수 있다. (ip_mc_inc_group() 에서 가져왔으며, ip_mc_join_group() 와 LINUX/net/ipv4/igmp.c에서 호출한다.)


          for(i=dev->ip_mc_list;i!=NULL;i=i->next)
          {
                  if(i->multiaddr==addr)
                  {
                          i->users++;
                          return;
                  }
          }

멤버가 탈퇴할 때 카운터를 감소하며, 카운터가 0에 다다랐을 때에만 부가적인 작업을 수행한다. (ip_mc_dec_group()).

MRT_ADD_MFC 와 MRT_DEL_MFC 는 멀티캐스트 라우팅 테이블에서 포워딩 항목을 성정하거나 삭제한다. 둘 다 mfcctl 구조체를 다음 정보와 함께 커널로 넘긴다. (/usr/include/linux/mroute.h 에서 정의)


  struct mfcctl
  {
          struct in_addr mfcc_origin;             /* Origin of mcast      */
          struct in_addr mfcc_mcastgrp;           /* Group in question    */
          vifi_t  mfcc_parent;                    /* Where it arrived     */
          unsigned char mfcc_ttls[MAXVIFS];       /* Where it is going    */
  };

이상의 정보를 가지고, ipmr_forward() 는 VIFs를 "돌아다닌다". 그리고 일치하는 포워딩 항목을 발견하면 데이터그램을 복사하여 ipmr_queue_xmit()을 호출한다. 그러면, ipmr_queue_xmit() 은 패킷을 터널을 통해 보낼 경우 라우팅 테이블에 명시 돤 출력장치와 목적지 주소를 이용해 전송한다. (즉, 반대편 터널 종단의 유니캐스트 주소) 함수 ip_rt_event() 는(출력과 직접적인 관련은 없지만 ip_output.c 에 들어 있다.) 장치 활성화 메시지 같은 네트웍 장치 관련된 이벤트(event)를 받는다. 이 함수는 장치가 전체 호스트 그룹에 참여하는 것을 보증한다.

IGMP 함수들은 LINUX/net/ipv4/igmp.c 에서 구현한다. 이 함수들에 관한 중요한 정보는 /usr/include/linux/igmp.h 와 /usr/include/linux/mroute.h 에 있다. /proc/net 의 IGMP 관련 항목은 LINUX/net/ipv4/ip_output.c에 있는 ip_init() 에서 만든다.


다음 이전 차례