carp 模块源代码文件
KMOD= carp SRCS= ip_carp.c sha1.c SRCS+= device_if.h bus_if.h vnode_if.h SRCS+= opt_carp.h opt_bpf.h opt_inet.h opt_inet6.h opt_ofed.h
CARP包头结构
/* * The CARP header layout is as follows: * * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |Version| Type | VirtualHostID | AdvSkew | Auth Len | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Reserved | AdvBase | Checksum | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Counter (1) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Counter (2) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SHA-1 HMAC (1) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SHA-1 HMAC (2) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SHA-1 HMAC (3) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SHA-1 HMAC (4) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | SHA-1 HMAC (5) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */
struct carp_header { #if BYTE_ORDER == LITTLE_ENDIAN u_int8_t carp_type:4, carp_version:4; #endif #if BYTE_ORDER == BIG_ENDIAN u_int8_t carp_version:4, carp_type:4; #endif u_int8_t carp_vhid; /* virtual host id */ u_int8_t carp_advskew; /* advertisement skew */ u_int8_t carp_authlen; /* size of counter+md, 32bit chunks */ u_int8_t carp_pad1; /* reserved */ u_int8_t carp_advbase; /* advertisement interval */ u_int16_t carp_cksum; u_int32_t carp_counter[2]; unsigned char carp_md[20]; /* SHA1 HMAC */ } __packed;
模块加载时执行
static int carp_mod_load(void);
int pf_proto_register(int family, struct protosw *npr); // 注册PF模块协议
int pf_proto_unregister(int family, int protocol, int type) // 注销PF模块协议
CARP 关键数据结构
struct carp_softc { struct ifnet *sc_carpdev; /* Pointer to parent ifnet. */ struct ifaddr **sc_ifas; /* Our ifaddrs. */ struct sockaddr_dl sc_addr; /* Our link level address. */ struct callout sc_ad_tmo; /* Advertising timeout. */ #ifdef INET struct callout sc_md_tmo; /* Master down timeout. */ #endif #ifdef INET6 struct callout sc_md6_tmo; /* IPv6: Master down timeout. */ #endif struct mtx sc_mtx; int sc_vhid; int sc_advskew; int sc_advbase; int sc_naddrs; int sc_naddrs6; int sc_ifasiz; enum { INIT = 0, BACKUP, MASTER } sc_state; int sc_suppress; int sc_sendad_errors; #define CARP_SENDAD_MAX_ERRORS 3 int sc_sendad_success; #define CARP_SENDAD_MIN_SUCCESS 3 int sc_init_counter; uint64_t sc_counter; /* authentication */ #define CARP_HMAC_PAD 64 unsigned char sc_key[CARP_KEY_LEN]; unsigned char sc_pad[CARP_HMAC_PAD]; SHA1_CTX sc_sha1; TAILQ_ENTRY(carp_softc) sc_list; /* On the carp_if list. */ LIST_ENTRY(carp_softc) sc_next; /* On the global list. */ };
/* carp 接口数据结构 */ struct carp_if { int cif_naddrs; TAILQ_HEAD(, carp_softc) cif_vrs; struct ip_moptions cif_imo; struct ifnet *cif_ifp; struct mtx cif_mtx; uint32_t cif_flags; #define CIF_PROMISC 0x00000001 };
CARP配置数据结构
struct carpreq { int carpr_count; // 接口个数 int carpr_vhid; // 虚拟主机名 #define CARP_MAXVHID 255 int carpr_state; // CARP状态 #define CARP_STATES "INIT", "BACKUP", "MASTER" #define CARP_MAXSTATE 2 int carpr_advskew; // CARP 密钥 #define CARP_MAXSKEW 240 int carpr_advbase; // CARP 发送数据包间隔 unsigned char carpr_key[CARP_KEY_LEN]; };
CARP 模块操作IOCTL提供接口
int carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td);
函数主要流程:
第一步:copyin 函数将用户态配置数据复制到 carpr 中 [copyin(ifr->ifr_data, &carpr, sizeof carpr)]
第二步:将接口名称与接口数据结构一一对应, ifp = ifunit_ref(ifr->ifr_name);
第三步:不支持 以太网、VLAN、BRIDGE, FDDI, ISO88025 协议
第四步:共享锁
第五步:实现以下两个接口
#define SIOCSVH _IOWR('i', 245, struct ifreq) #define SIOCGVH _IOWR('i', 246, struct ifreq)
用户态程序由ifconfig 来调用
pfsync 协议数据同步
将状态与配置信息进行同步
源代码文件
KMOD= pfsync SRCS= if_pfsync.c \ opt_pf.h opt_inet.h opt_inet6.h SRCS+= bus_if.h device_if.h
模块加载时执行初始化函数
pfsync_init();
主要流程:
1. 将协议注册入IPv4协议栈
2. 初始化pfsync指针
static void pfsync_pointers_init() { PF_RULES_WLOCK(); pfsync_state_import_ptr = pfsync_state_import; pfsync_insert_state_ptr = pfsync_insert_state; pfsync_update_state_ptr = pfsync_update_state; pfsync_delete_state_ptr = pfsync_delete_state; pfsync_clear_states_ptr = pfsync_clear_states; pfsync_defer_ptr = pfsync_defer; PF_RULES_WUNLOCK(); }
数据结构
struct pfsync_pkt { struct ip *ip; struct in_addr src; u_int8_t flags; };
看pfsyc 实现接口
static int pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
#define SIOCSETPFSYNC _IOW('i', 247, struct ifreq) #define SIOCGETPFSYNC _IOWR('i', 248, struct ifreq)
关键数据结构
组播地址
/* * Structure attached to inpcb.ip_moptions and * passed to ip_output when IP multicast options are in use. * This structure is lazy-allocated. */ struct ip_moptions { struct ifnet *imo_multicast_ifp; /* ifp for outgoing multicasts */ struct in_addr imo_multicast_addr; /* ifindex/addr on MULTICAST_IF */ u_long imo_multicast_vif; /* vif num outgoing multicasts */ u_char imo_multicast_ttl; /* TTL for outgoing multicasts */ u_char imo_multicast_loop; /* 1 => hear sends if a member */ u_short imo_num_memberships; /* no. memberships this socket */ u_short imo_max_memberships; /* max memberships this socket */ struct in_multi **imo_membership; /* group memberships */ struct in_mfilter *imo_mfilters; /* source filters */ STAILQ_ENTRY(ip_moptions) imo_link; };
关键函数
pfsync_multicast_setup; 使用组播地址 244.0.0.240 来进行数据同步
pfsync_request_update; 进行状态信息同步