PF - 冗余与高可用性

时间:2020-12-21 01:23:33

 

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; 进行状态信息同步