igmpproxy源代碼學習——igmpProxyInit()函數詳解,igmpproxy初始化
在運行igmpproxy的主程序igmpproxyRun()以前須要對igmpproxy進行一些配置,這些配置都是在igmpProxyInit()中完成的。
要進行的配置主要有:
信號處理配置物理網絡接口配置加載配置文件的加載虛擬網絡設備初始化路由向量表初始化定時器初始化
信號處理配置
首先進行信號處理配置:
sigemptyset(&sa.sa_mask);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
buildIfVc 物理網絡接口配置加載
函數buildIfVc用於完成物理網絡接口加載配置,
將物理網絡接口的配置保存在全局變量 IfDescVc[ MAX_IF ]中(這是目的)。
Sock = socket( AF_INET, SOCK_DGRAM, 0 )用於創建基於UDP數據包的網絡套接字
ioctl( Sock, SIOCGIFCONF, &IoCtlReq )用來獲取全部網絡接口列表(包含接口名字,IP地址)
而後進入一個循環體,該循環體會調用將前面獲取的
接口名字屢次使用傳入ioctl來分別得到子網掩碼、索引號、Flags等信息。這些信息包括IP地址都將保存在
IfDescVc[ MAX_IF ]
中 關於IfDescVc的類型struct IfDesc 以下所示:
struct IfDesc {
char Name[ sizeof( ((struct ifreq *)NULL)->ifr_name ) ];
struct in_addr InAdr; /* == 0 for non IP interfaces */
short Flags;
short state; //狀態:如upstream、downstream
struct SubnetList* allowednets; //一個子網鏈表
unsigned int robustness;
unsigned char threshold; /* ttl limit */
unsigned int ratelimit;
unsigned int index;
};
configureVifs配置文件中信息的加載
在buildIfVc中,咱們獲取了物理網絡接口的一些信息,保存在IfDescVc中,可是要建立添加虛擬網路設備,咱們還有一些本身的配置(在config文件中,也就是loadConfig函數中實現的功能),這些配置咱們經過loadConfig函數已經保存在vifconf中了。
函數
configuireVifs()的任務就是將配置文件中關於虛擬網絡設備的諸如threshold、allowednets、ratelimit等信息加載到
IfDescVc[ MAX_IF ]
中。
到這個函數完成這後,咱們
IfDescVc[ MAX_IF ]中才保存了虛擬網絡設備所須要的全部信息——這些信息由兩部分組成,一個是物理網絡接口的配置,一個是配置文件中關於虛擬網絡設備的一些其餘的描述(config文件igmpProxy.conf中的配置)
虛擬網絡設備初始化AddVif
在建立虛擬網絡設備以前須要執行
enableMRouter()完成對mrouter的初始化,建立套接口。具體以下:
if ( (MRouterFD = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0 )//打開套接口MRouterFD
log( LOG_ERR, errno, "IGMP socket open" );
if ( setsockopt( MRouterFD, IPPROTO_IP, MRT_INIT,(void *)&Va, sizeof( Va ) ) )//激活Linux內核模塊mrouted服務
return errno;
前面經過
buildIfVc()和
configureVifs()咱們已經將要初始化的虛擬網絡設備所須要的信息都保存在
IfDescVc[ MAX_IF ]
中了,接下來就是經過循環讀取
IfDescVc[ MAX_IF ]中的信息建立VIF虛擬網絡設備。
AddVif()主要經過下面一行代碼完成。
setsockopt( MRouterFD, IPPROTO_IP, MRT_ADD_VIF, (char *)&VifCtl, sizeof( VifCtl ) )
從上面代碼咱們看到參數VifCtl,該參數保存了虛擬網絡設備的一些控制信息。VifCtl的類型
struct
vifctl以下
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) */
union {
struct in_addr vifc_lcl_addr; /* Local interface address */
int vifc_lcl_ifindex; /* Local interface index */
};
struct in_addr vifc_rmt_addr; /* IPIP tunnel addr */
};
初始化igmp數據包 initIgmp();
初始化igmp數據包的報文格式,建立發送和接收數據包的緩衝區,爲以後發送查詢和接收報告作準備。
igmp數據包是其實是在ip包首部中寫入igmp相關信息,關於struct ip附上定義:
struct ip
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ip_hl:4; /* header length */
unsigned int ip_v:4; /* version */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int ip_v:4; /* version */
unsigned int ip_hl:4; /* header length */
#endif
u_int8_t ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src, ip_dst; /* source and dest address */
};
allhosts_group = htonl(INADDR_ALLHOSTS_GROUP); //224.0.0.1 在本子網上的全部參加多播的主機和路由器
allrouters_group = htonl(INADDR_ALLRTRS_GROUP); //224.0.0.2 在本子網上的全部參加多播的路由器
初始化路由表 initRouteTable();
初始化路由表,爲每一個下行接口加入多播組
allrouters_group
joinMcGroup( getMcGroupSock(), Dp, allrouters_group );
joinleave( int Cmd, int UdpSock, struct IfDesc *IfDp, uint32 mcastaddr )
由於傳入的cmd爲j,表示加入組(若是傳入不是j,表示離開組)
joinleave最主要的代碼是:
setsockopt( UdpSock, IPPROTO_IP,
Cmd == 'j' ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP,
(void *)&CtlReq, sizeof( CtlReq ) )
初始化時間表callout_init();
void callout_init() {
queue = NULL;
}