zoukankan      html  css  js  c++  java
  • ip_vs实现分析(1)

    本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
    msn: yfydz_no1@hotmail.com
    来源:http://yfydz.cublog.cn


    1. 前言
    ipvs是章文嵩先生主持的一个开源项目,早在2.2内核时就已经以内核补丁形式出现,RedHat6.1和6.0的一个重要区别就是增加了IPVS。从2.4.24后IPVS已经成为Linux官方标准内核的一部分,2.2时IPVS是完全独立的部分,2.4以后借用了netfilter的一些处理机制,但主体还是比较独立,但功能和netfilter有重复的地方。
    IPVS官方网站为: http://www.linuxvirtualserver.org
    以下内核代码版本2.6.17.11, ipvs版本为1.2.1。

    2. IPVS的外部表现

    根据LVS官方网站的介绍,LVS支持三种负载均衡模式:NAT,tunnel和direct routing(DR)。NAT是通用模式,所有交互数据必须通过均衡器;后两种则是一种半连接处理方式,请求数据通过均衡器,而服务器的回应则是直接路由返回的,而这两种方法的区别是tunnel模式下由于进行了IP封装所以可路由,而DR方式是修改MAC地址来实现,所以必须同一网段。

    3. 几个重要结构
    3.1 协议
    这个结构用来描述IPVS支持的IP协议。IPVS的IP层协议支持TCP, UDP, AH和ESP这4种IP层协议
    struct ip_vs_protocol {
    // 链表中的下一项
     struct ip_vs_protocol *next;
    // 协议名称, "TCP", "UDP"...
     char   *name;
    // 协议值: 6, 17, ...
     __u16   protocol;
    // 不进行分配
     int   dont_defrag;
    // 协议应用计数器,也据是该协议的中多连接协议的数量
     atomic_t  appcnt;  /* counter of proto app incs */
    // 协议各状态的超时数组
     int   *timeout_table; /* protocol timeout table */
    // 协议初始化
     void (*init)(struct ip_vs_protocol *pp);
    // 协议释放
     void (*exit)(struct ip_vs_protocol *pp);
    // 协议调度
     int (*conn_schedule)(struct sk_buff *skb,
            struct ip_vs_protocol *pp,
            int *verdict, struct ip_vs_conn **cpp);
    // 查找in方向的IPVS连接
     struct ip_vs_conn *
     (*conn_in_get)(const struct sk_buff *skb,
             struct ip_vs_protocol *pp,
             const struct iphdr *iph,
             unsigned int proto_off,
             int inverse);
    // 查找out方向的IPVS连接
     struct ip_vs_conn *
     (*conn_out_get)(const struct sk_buff *skb,
       struct ip_vs_protocol *pp,
       const struct iphdr *iph,
       unsigned int proto_off,
       int inverse);
    // 源NAT操作
     int (*snat_handler)(struct sk_buff **pskb,
           struct ip_vs_protocol *pp, struct ip_vs_conn *cp);
    // 目的NAT操作
     int (*dnat_handler)(struct sk_buff **pskb,
           struct ip_vs_protocol *pp, struct ip_vs_conn *cp);
    // 协议校验和计算
     int (*csum_check)(struct sk_buff *skb, struct ip_vs_protocol *pp);
    // 当前协议状态名称: 如"LISTEN", "ESTABLISH"...
     const char *(*state_name)(int state);
    // 协议状态迁移
     int (*state_transition)(struct ip_vs_conn *cp, int direction,
        const struct sk_buff *skb,
        struct ip_vs_protocol *pp);
    // 登记应用
     int (*register_app)(struct ip_vs_app *inc);
    // 去除应用登记
     void (*unregister_app)(struct ip_vs_app *inc);
     int (*app_conn_bind)(struct ip_vs_conn *cp);
    // 数据包打印
     void (*debug_packet)(struct ip_vs_protocol *pp,
            const struct sk_buff *skb,
            int offset,
            const char *msg);
    // 调整超时
     void (*timeout_change)(struct ip_vs_protocol *pp, int flags);
    // 设置各种状态下的协议超时
     int (*set_state_timeout)(struct ip_vs_protocol *pp, char *sname, int to);
    };

    3.2 IPVS连接

    这个结构用来描述IPVS的连接。IPVS的连接和netfilter定义的连接类似
    /*
     * IP_VS structure allocated for each dynamically scheduled connection
     */
    struct ip_vs_conn {
    // HASH链表
     struct list_head        c_list;         /* hashed list heads */
     /* Protocol, addresses and port numbers */
    // 客户机地址
     __u32                   caddr;          /* client address */
    // 服务器对外的虚拟地址
     __u32                   vaddr;          /* virtual address */
    // 服务器实际地址
     __u32                   daddr;          /* destination address */
    // 客户端的端口
     __u16                   cport;
    // 服务器对外虚拟端口
     __u16                   vport;
    // 服务器实际端口
     __u16                   dport;
    // 协议类型
     __u16                   protocol;       /* Which protocol (TCP/UDP) */
     /* counter and timer */
    // 连接引用计数
     atomic_t  refcnt;  /* reference count */
    // 定时器
     struct timer_list timer;  /* Expiration timer */
    // 超时时间
     volatile unsigned long timeout; /* timeout */
     /* Flags and state transition */
    // 状态转换锁
     spinlock_t              lock;           /* lock for state transition */
     volatile __u16          flags;          /* status flags */
     volatile __u16          state;          /* state info */
     /* Control members */
    // 主连接, 如FTP
     struct ip_vs_conn       *control;       /* Master control connection */
    // 子连接数
     atomic_t                n_control;      /* Number of controlled ones */
    // 真正服务器
     struct ip_vs_dest       *dest;          /* real server */
    // 进入的数据统计
     atomic_t                in_pkts;        /* incoming packet counter */
     /* packet transmitter for different forwarding methods.  If it
        mangles the packet, it must return NF_DROP or better NF_STOLEN,
        otherwise this must be changed to a sk_buff **.
      */
    // 数据包发送
     int (*packet_xmit)(struct sk_buff *skb, struct ip_vs_conn *cp,
          struct ip_vs_protocol *pp);
     /* Note: we can group the following members into a structure,
        in order to save more space, and the following members are
        only used in VS/NAT anyway */
    // IPVS应用
     struct ip_vs_app        *app;           /* bound ip_vs_app object */
    // 应用的私有数据
     void                    *app_data;      /* Application private data */
    // 进入数据的序列号
     struct ip_vs_seq        in_seq;         /* incoming seq. struct */
    // 发出数据的序列号
     struct ip_vs_seq        out_seq;        /* outgoing seq. struct */
    };

    3.3 IPVS服务
    这个结构用来描述IPVS对外的虚拟服务器信息。
    /*
     * The information about the virtual service offered to the net
     * and the forwarding entries
     */
    struct ip_vs_service {
    // 按普通协议,地址,端口进行HASH的链表
     struct list_head s_list;   /* for normal service table */
    // 按nfmark进行HASH的链表(感觉没必要)
     struct list_head f_list;   /* for fwmark-based service table */
    // 引用计数
     atomic_t  refcnt;   /* reference counter */
    // 使用计数
     atomic_t  usecnt;   /* use counter */
    // 协议
     __u16   protocol; /* which protocol (TCP/UDP) */
    // 虚拟服务器地址
     __u32   addr;   /* IP address for virtual service */
    // 虚拟端口
     __u16   port;   /* port number for the service */
    // 就是skb中的nfmark
     __u32                   fwmark;   /* firewall mark of the service */
    // 标志
     unsigned  flags;   /* service status flags */
    // 超时
     unsigned  timeout;  /* persistent timeout in ticks */
    // 网络掩码
     __u32   netmask;  /* grouping granularity */
    // 真实服务器的地址链表
     struct list_head destinations;  /* real server d-linked list */
    // 真实服务器的数量
     __u32   num_dests;     /* number of servers */
    // 服务统计信息
     struct ip_vs_stats      stats;         /* statistics for the service */
    // 应用
     struct ip_vs_app *inc;   /* bind conns to this app inc */
     /* for scheduling */
    // 调度指针
     struct ip_vs_scheduler *scheduler;    /* bound scheduler object */
     rwlock_t  sched_lock;    /* lock sched_data */
     void   *sched_data;   /* scheduler application data */
    };

    3.4 IPVS目的服务器
    这个结构用来描述具体的真实服务器的信息
    /*
     * The real server destination forwarding entry
     * with ip address, port number, and so on.
     */
    struct ip_vs_dest {
    // 
     struct list_head n_list;   /* for the dests in the service */
     struct list_head d_list;   /* for table with all the dests */
    // 服务器地址
     __u32   addr;  /* IP address of the server */
    // 服务器端口
     __u16   port;  /* port number of the server */
    // 目标标志,易变参数
     volatile unsigned flags;  /* dest status flags */
    // 连接标志
     atomic_t  conn_flags; /* flags to copy to conn */
    // 服务器权重
     atomic_t  weight;  /* server weight */
    // 引用次数
     atomic_t  refcnt;  /* reference counter */
    // 统计数
     struct ip_vs_stats      stats;          /* statistics */
     /* connection counters and thresholds */
    // 活动的连接
     atomic_t  activeconns; /* active connections */
    // 不活动的连接
     atomic_t  inactconns; /* inactive connections */
    // 保持的连接
     atomic_t  persistconns; /* persistent connections */
    // 连接上限
     __u32   u_threshold; /* upper threshold */
    // 连接下限
     __u32   l_threshold; /* lower threshold */
     /* for destination cache */
     spinlock_t  dst_lock; /* lock of dst_cache */
     struct dst_entry *dst_cache; /* destination cache entry */
     u32   dst_rtos; /* RT_TOS(tos) for dst */
     /* for virtual service */
     struct ip_vs_service *svc;  /* service it belongs to */
     __u16   protocol; /* which protocol (TCP/UDP) */
     __u32   vaddr;  /* virtual IP address */
     __u16   vport;  /* virtual port number */
     __u32   vfwmark; /* firewall mark of service */
    };
    3.5 IPVS调度器
    这个结构用来描述IPVS调度算法,目前调度方法包括rr,wrr,lc, wlc, lblc, lblcr, dh, sh等
    /*
     * The scheduler object
     */
    struct ip_vs_scheduler {
     struct list_head n_list;  /* d-linked list head */
     char   *name;  /* scheduler name */
     atomic_t  refcnt;  /* reference counter */
     struct module  *module; /* THIS_MODULE/NULL */
     /* scheduler initializing service */
     int (*init_service)(struct ip_vs_service *svc);
     /* scheduling service finish */
     int (*done_service)(struct ip_vs_service *svc);
     /* scheduler updating service */
     int (*update_service)(struct ip_vs_service *svc);
     /* selecting a server from the given service */
     struct ip_vs_dest* (*schedule)(struct ip_vs_service *svc,
               const struct sk_buff *skb);
    };

    3.6 IPVS应用

    IPVS应用是针对多连接协议的, 目前也就只支持FTP。由于ip_vs_app.c是从2.2过来的,没有管内核是否本身有NAT的情况,所以相当于自身实现了应用协议的NAT处理,包括内容信息的改变,TCP序列号确认号的调整等,而现在这些都由netfilter实现了,IPVS可以不用管这些,只处理连接调度就行了。
    IPVS的应用模块化还不是很好,在处理连接端口时,还要判断是否是FTPPORT,也就是说不支持其他多连接协议的,应该象netfilter一样为每个多连接协议设置一个helper,自动调用,不用在程序里判断端口。
    /*
     * The application module object (a.k.a. app incarnation)
     */
    struct ip_vs_app
    {
    // 用来挂接到应用链表
     struct list_head a_list;  /* member in app list */
     int   type;  /* IP_VS_APP_TYPE_xxx */
     char   *name;  /* application module name */
    // 协议, TCP, UDP...
     __u16   protocol;
    // 模块本身
     struct module  *module; /* THIS_MODULE/NULL */
    // 应用的具体实例链表
     struct list_head incs_list; /* list of incarnations */
     /* members for application incarnations */
    // 将应用结构挂接到对应协议(TCP, UDP...)的应用表
     struct list_head p_list;  /* member in proto app list */
     struct ip_vs_app *app;  /* its real application */
     __u16   port;  /* port number in net order */
     atomic_t  usecnt;  /* usage counter */
     /* output hook: return false if can't linearize. diff set for TCP.  */
     int (*pkt_out)(struct ip_vs_app *, struct ip_vs_conn *,
             struct sk_buff **, int *diff);
     /* input hook: return false if can't linearize. diff set for TCP. */
     int (*pkt_in)(struct ip_vs_app *, struct ip_vs_conn *,
            struct sk_buff **, int *diff);
     /* ip_vs_app initializer */
     int (*init_conn)(struct ip_vs_app *, struct ip_vs_conn *);
     /* ip_vs_app finish */
     int (*done_conn)(struct ip_vs_app *, struct ip_vs_conn *);

     /* not used now */
     int (*bind_conn)(struct ip_vs_app *, struct ip_vs_conn *,
        struct ip_vs_protocol *);
     void (*unbind_conn)(struct ip_vs_app *, struct ip_vs_conn *);
     int *   timeout_table;
     int *   timeouts;
     int   timeouts_size;
     int (*conn_schedule)(struct sk_buff *skb, struct ip_vs_app *app,
            int *verdict, struct ip_vs_conn **cpp);
     struct ip_vs_conn *
     (*conn_in_get)(const struct sk_buff *skb, struct ip_vs_app *app,
             const struct iphdr *iph, unsigned int proto_off,
             int inverse);
     struct ip_vs_conn *
     (*conn_out_get)(const struct sk_buff *skb, struct ip_vs_app *app,
       const struct iphdr *iph, unsigned int proto_off,
       int inverse);
     int (*state_transition)(struct ip_vs_conn *cp, int direction,
        const struct sk_buff *skb,
        struct ip_vs_app *app);
     void (*timeout_change)(struct ip_vs_app *app, int flags);
    };
     
    3.7 用户空间数据结构

    用户空间信息是ipvsadm程序接收用户输入后传递给内核ipvs的信息,信息都是很直接的,没有各种控制信息。ipvsadm和ipvs的关系相当于iptables和netfilter的关系。

    3.7.1 用户空间的虚拟服务信息
    /*
     * The struct ip_vs_service_user and struct ip_vs_dest_user are
     * used to set IPVS rules through setsockopt.
     */
    struct ip_vs_service_user {
     /* virtual service addresses */
     u_int16_t  protocol;
     u_int32_t  addr;  /* virtual ip address */
     u_int16_t  port;
     u_int32_t  fwmark;  /* firwall mark of service */
     /* virtual service options */
     char   sched_name[IP_VS_SCHEDNAME_MAXLEN];
     unsigned  flags;  /* virtual service flags */
     unsigned  timeout; /* persistent timeout in sec */
     u_int32_t  netmask; /* persistent netmask */
    };
    3.7.2 用户空间的真实服务器信息
    struct ip_vs_dest_user {
     /* destination server address */
     u_int32_t  addr;
     u_int16_t  port;
     /* real server options */
     unsigned  conn_flags; /* connection flags */
     int   weight;  /* destination weight */
     /* thresholds for active connections */
     u_int32_t  u_threshold; /* upper threshold */
     u_int32_t  l_threshold; /* lower threshold */
    };
    3.7.3 用户空间的统计信息
    /*
     * IPVS statistics object (for user space)
     */
    struct ip_vs_stats_user
    {
     __u32                   conns;          /* connections scheduled */
     __u32                   inpkts;         /* incoming packets */
     __u32                   outpkts;        /* outgoing packets */
     __u64                   inbytes;        /* incoming bytes */
     __u64                   outbytes;       /* outgoing bytes */
     __u32   cps;  /* current connection rate */
     __u32   inpps;  /* current in packet rate */
     __u32   outpps;  /* current out packet rate */
     __u32   inbps;  /* current in byte rate */
     __u32   outbps;  /* current out byte rate */
    };
    3.7.4 用户空间的获取信息结构
    /* The argument to IP_VS_SO_GET_INFO */
    struct ip_vs_getinfo {
     /* version number */
     unsigned int  version;
     /* size of connection hash table */
     unsigned int  size;
     /* number of virtual services */
     unsigned int  num_services;
    };
    3.7.5 用户空间的服务规则项信息
    /* The argument to IP_VS_SO_GET_SERVICE */
    struct ip_vs_service_entry {
     /* which service: user fills in these */
     u_int16_t  protocol;
     u_int32_t  addr;  /* virtual address */
     u_int16_t  port;
     u_int32_t  fwmark;  /* firwall mark of service */
     /* service options */
     char   sched_name[IP_VS_SCHEDNAME_MAXLEN];
     unsigned  flags;          /* virtual service flags */
     unsigned  timeout; /* persistent timeout */
     u_int32_t  netmask; /* persistent netmask */
     /* number of real servers */
     unsigned int  num_dests;
     /* statistics */
     struct ip_vs_stats_user stats;
    };
    3.7.6 用户空间的服务器项信息
    struct ip_vs_dest_entry {
     u_int32_t  addr;  /* destination address */
     u_int16_t  port;
     unsigned  conn_flags; /* connection flags */
     int   weight;  /* destination weight */
     u_int32_t  u_threshold; /* upper threshold */
     u_int32_t  l_threshold; /* lower threshold */
     u_int32_t  activeconns; /* active connections */
     u_int32_t  inactconns; /* inactive connections */
     u_int32_t  persistconns; /* persistent connections */
     /* statistics */
     struct ip_vs_stats_user stats;
    };

    3.7.7 用户空间的获取服务器项信息
    /* The argument to IP_VS_SO_GET_DESTS */
    struct ip_vs_get_dests {
     /* which service: user fills in these */
     u_int16_t  protocol;
     u_int32_t  addr;  /* virtual address */
     u_int16_t  port;
     u_int32_t  fwmark;  /* firwall mark of service */
     /* number of real servers */
     unsigned int  num_dests;
     /* the real servers */
     struct ip_vs_dest_entry entrytable[0];
    };

    3.7.8 用户空间的获取虚拟服务项信息
    /* The argument to IP_VS_SO_GET_SERVICES */
    struct ip_vs_get_services {
     /* number of virtual services */
     unsigned int  num_services;
     /* service table */
     struct ip_vs_service_entry entrytable[0];
    };

    3.7.9 用户空间的获取超时信息结构
    /* The argument to IP_VS_SO_GET_TIMEOUT */
    struct ip_vs_timeout_user {
     int   tcp_timeout;
     int   tcp_fin_timeout;
     int   udp_timeout;
    };

    3.7.10 用户空间的获取IPVS内核守护进程信息结构
    /* The argument to IP_VS_SO_GET_DAEMON */
    struct ip_vs_daemon_user {
     /* sync daemon state (master/backup) */
     int   state;
     /* multicast interface name */
     char   mcast_ifn[IP_VS_IFNAME_MAXLEN];
     /* SyncID we belong to */
     int   syncid;
    };
  • 相关阅读:
    JPA的查询语言—使用构造器
    Servlet3.0使用注解定义Servlet
    jQuery操作<input type="radio">
    JPA的查询语言—使用原生SQL
    jQuery动态添加<input type="file">
    JPA的查询语言—JPQL的关联查询
    jQuery操作<select>
    Servlet3.0异步处理
    jQuery操作<input type="checkbox">
    mysql binlog二进制日志详解
  • 原文地址:https://www.cnblogs.com/qq78292959/p/2538200.html
Copyright © 2011-2022 走看看