LVS
lvs-devel
Google
 
Web LinuxVirtualServer.org

[rfc 2/2] [PATCH 2/2] Add support for persistence engines.

To: lvs-devel@xxxxxxxxxxxxxxx, netdev@xxxxxxxxxxxxxxx, netfilter@xxxxxxxxxxxxxxx, netfilter-devel@xxxxxxxxxxxxxxx
Subject: [rfc 2/2] [PATCH 2/2] Add support for persistence engines.
Cc: Wensong Zhang <wensong@xxxxxxxxxxxx>, Julian Anastasov <ja@xxxxxx>, Patrick McHardy <kaber@xxxxxxxxx>
From: Simon Horman <horms@xxxxxxxxxxxx>
Date: Thu, 05 Aug 2010 20:47:57 +0900
This adds the --pe [engine] option to the -A and -E commands
which allows a persistence engine to be associated with a virtual service.
The absence of --pe sets no persistence engine.

The --pe option only works when ipvsadm is compiled to use netlink
for user-space/kernel communication.

This patch also allows the --persistent-conn option to be given to the -L
command, which will list persistence engine data, if any is present, when
listing connections (and persistence templates).

At this time the only (proposed) persistence engine is sip.

Signed-off-by: Simon Horman <horms@xxxxxxxxxxxx>

v0.4
* Fix indentation of --pe help text
---
 Makefile            |    3 ++-
 PERSISTENCE_ENGINES |    1 +
 ipvsadm.8           |    4 ++++
 ipvsadm.c           |   51 ++++++++++++++++++++++++++++++++++++++++-----------
 libipvs/ip_vs.h     |    8 ++++++++
 libipvs/libipvs.c   |   44 +++++++++++++++++++++++++++++++-------------
 6 files changed, 86 insertions(+), 25 deletions(-)
 create mode 100644 PERSISTENCE_ENGINES

diff --git a/Makefile b/Makefile
index 46300ef..23274e5 100644
--- a/Makefile
+++ b/Makefile
@@ -29,6 +29,7 @@ NAME          = ipvsadm
 VERSION                = $(shell cat VERSION)
 RELEASE                = 1
 SCHEDULERS     = "$(shell cat SCHEDULERS)"
+PE_LIST                = "$(shell cat PERSISTENCE_ENGINES)"
 PROGROOT       = $(shell basename `pwd`)
 ARCH           = $(shell uname -m)
 RPMSOURCEDIR   = $(shell rpm --eval '%_sourcedir')
@@ -83,7 +84,7 @@ ifneq (0,$(HAVE_NL))
 LIBS           += -lnl
 endif
 DEFINES                = -DVERSION=\"$(VERSION)\" 
-DSCHEDULERS=\"$(SCHEDULERS)\" \
-                 $(POPT_DEFINE)
+                 -DPE_LIST=\"$(PE_LIST)\" $(POPT_DEFINE)
 DEFINES                += $(shell if [ ! -f ../ip_vs.h ]; then \
                     echo "-DHAVE_NET_IP_VS_H"; fi;)
 
diff --git a/PERSISTENCE_ENGINES b/PERSISTENCE_ENGINES
new file mode 100644
index 0000000..641cf83
--- /dev/null
+++ b/PERSISTENCE_ENGINES
@@ -0,0 +1 @@
+sip
diff --git a/ipvsadm.8 b/ipvsadm.8
index 816e307..001ae74 100644
--- a/ipvsadm.8
+++ b/ipvsadm.8
@@ -391,6 +391,10 @@ with this option will display the persistent connection 
counter
 information of each server in service listing. The persistent
 connection is used to forward the actual connections from the same
 client/network to the same server.
+.sp
+The \fIlist\fP command with the -c, --connection option and this option
+will include persistence engine data, if any is present, when listing
+connections.
 .TP
 .B --sort
 Sort the list of virtual services and real servers. The virtual
diff --git a/ipvsadm.c b/ipvsadm.c
index 1ac6c7f..0332b22 100644
--- a/ipvsadm.c
+++ b/ipvsadm.c
@@ -181,13 +181,15 @@ static const char* cmdnames[] = {
 #define OPT_SYNCID             0x080000
 #define OPT_EXACT              0x100000
 #define OPT_ONEPACKET          0x200000
-#define NUMBER_OF_OPT          22
+#define OPT_PERSISTENCE_ENGINE  0x400000
+#define NUMBER_OF_OPT          23
 
 static const char* optnames[] = {
        "numeric",
        "connection",
        "service-address",
        "scheduler",
+       "pe",
        "persistent",
        "netmask",
        "real-server",
@@ -282,6 +284,7 @@ enum {
        TAG_PERSISTENTCONN,
        TAG_SORT,
        TAG_NO_SORT,
+       TAG_PERSISTENCE_ENGINE,
 };
 
 /* various parsing helpers & parsing functions */
@@ -421,6 +424,8 @@ parse_options(int argc, char **argv, struct 
ipvs_command_entry *ce,
                { "exact", 'X', POPT_ARG_NONE, NULL, 'X', NULL, NULL },
                { "ipv6", '6', POPT_ARG_NONE, NULL, '6', NULL, NULL },
                { "ops", 'o', POPT_ARG_NONE, NULL, 'o', NULL, NULL },
+               { "pe", '\0', POPT_ARG_STRING, &optarg, TAG_PERSISTENCE_ENGINE,
+                 NULL, NULL },
                { NULL, 0, 0, NULL, 0, NULL, NULL }
        };
 
@@ -647,6 +652,10 @@ parse_options(int argc, char **argv, struct 
ipvs_command_entry *ce,
                        set_option(options, OPT_ONEPACKET);
                        ce->svc.flags |= IP_VS_SVC_F_ONEPACKET;
                        break;
+               case TAG_PERSISTENCE_ENGINE:
+                       set_option(options, OPT_PERSISTENCE_ENGINE);
+                       strncpy(ce->svc.pe_name, optarg, IP_VS_PENAME_MAXLEN);
+                       break;
                default:
                        fail(2, "invalid option `%s'",
                             poptBadOption(context, POPT_BADOPTION_NOALIAS));
@@ -763,9 +772,10 @@ static int process_options(int argc, char **argv, int 
reading_stdin)
 
        switch (ce.cmd) {
        case CMD_LIST:
-               if (options & (OPT_CONNECTION|OPT_TIMEOUT|OPT_DAEMON) &&
-                   options & (OPT_STATS|OPT_PERSISTENTCONN|
-                              OPT_RATE|OPT_THRESHOLDS))
+               if ((options & (OPT_CONNECTION|OPT_TIMEOUT|OPT_DAEMON) &&
+                    options & (OPT_STATS|OPT_RATE|OPT_THRESHOLDS)) ||
+                   (options & (OPT_TIMEOUT|OPT_DAEMON) &&
+                    options & OPT_PERSISTENTCONN))
                        fail(2, "options conflicts in the list command");
 
                if (options & OPT_CONNECTION)
@@ -1060,7 +1070,7 @@ static void usage_exit(const char *program, const int 
exit_status)
        version(stream);
        fprintf(stream,
                "Usage:\n"
-               "  %s -A|E -t|u|f service-address [-s scheduler] [-p [timeout]] 
[-M netmask]\n"
+               "  %s -A|E -t|u|f service-address [-s scheduler] [-p [timeout]] 
[-M netmask] [--pe persistence_engine]\n"
                "  %s -D -t|u|f service-address\n"
                "  %s -C\n"
                "  %s -R\n"
@@ -1105,6 +1115,8 @@ static void usage_exit(const char *program, const int 
exit_status)
                "  --ipv6         -6                   fwmark entry uses IPv6\n"
                "  --scheduler    -s scheduler         one of " SCHEDULERS ",\n"
                "                                      the default scheduler is 
%s.\n"
+               "  --pe            engine              alternate persistence 
engine may be " PE_LIST ",\n"
+               "                                      not set by default.\n"
                "  --persistent   -p [timeout]         persistent service\n"
                "  --netmask      -M netmask           persistent granularity 
mask\n"
                "  --real-server  -r server-address    server-address is host 
(and port)\n"
@@ -1225,6 +1237,8 @@ static void print_conn(char *buf, unsigned int format)
        char            state[16];
        unsigned int    expires;
        unsigned short  af = AF_INET;
+       char            pe_name[IP_VS_PENAME_MAXLEN];
+       char            pe_data[IP_VS_PEDATA_MAXLEN];
 
        int n;
        char temp1[INET6_ADDRSTRLEN], temp2[INET6_ADDRSTRLEN], 
temp3[INET6_ADDRSTRLEN];
@@ -1232,9 +1246,10 @@ static void print_conn(char *buf, unsigned int format)
        unsigned int    minutes, seconds;
        char            expire_str[12];
 
-       if ((n = sscanf(buf, "%s %s %hX %s %hX %s %hX %s %d",
+       if ((n = sscanf(buf, "%s %s %hX %s %hX %s %hX %s %d %s %s",
                        protocol, temp1, &cport, temp2, &vport,
-                       temp3, &dport, state, &expires)) == -1)
+                       temp3, &dport, state, &expires,
+                       pe_name, pe_data)) == -1)
                exit(1);
 
        if (strcmp(protocol, "TCP") == 0)
@@ -1268,8 +1283,13 @@ static void print_conn(char *buf, unsigned int format)
        minutes = expires / 60;
        sprintf(expire_str, "%02d:%02d", minutes, seconds);
 
-       printf("%-3s %-6s %-11s %-18s %-18s %s\n",
-              protocol, expire_str, state, cname, vname, dname);
+       if (format & FMT_PERSISTENTCONN)
+               printf("%-3s %-6s %-11s %-18s %-18s %-16s %-18s %s\n",
+                      protocol, expire_str, state, cname, vname, dname,
+                      pe_name, pe_data);
+       else
+               printf("%-3s %-6s %-11s %-18s %-18s %s\n",
+                      protocol, expire_str, state, cname, vname, dname);
 
        free(cname);
        free(vname);
@@ -1295,8 +1315,13 @@ void list_conn(unsigned int format)
                exit(1);
        }
        printf("IPVS connection entries\n");
-       printf("pro expire %-11s %-18s %-18s %s\n",
-              "state", "source", "virtual", "destination");
+       if (format & FMT_PERSISTENTCONN)
+               printf("pro expire %-11s %-18s %-18s %-18s %-16s %s\n",
+                      "state", "source", "virtual", "destination",
+                      "pe name", "pe_data");
+       else
+               printf("pro expire %-11s %-18s %-18s %s\n",
+                      "state", "source", "virtual", "destination");
 
        /*
         * Print the VS information according to the format
@@ -1459,6 +1484,8 @@ print_service_entry(ipvs_service_entry_t *se, unsigned 
int format)
                                        printf(" -M %i", se->netmask);
                                }
                }
+               if (se->pe_name[0])
+                       printf(" pe %s", se->pe_name);
                if (se->flags & IP_VS_SVC_F_ONEPACKET)
                        printf(" ops");
        } else if (format & FMT_STATS) {
@@ -1488,6 +1515,8 @@ print_service_entry(ipvs_service_entry_t *se, unsigned 
int format)
                        if (se->af == AF_INET6)
                                if (se->netmask != 128)
                                        printf(" mask %i", se->netmask);
+                       if (se->pe_name[0])
+                               printf(" pe %s", se->pe_name);
                        if (se->flags & IP_VS_SVC_F_ONEPACKET)
                                printf(" ops");
                }
diff --git a/libipvs/ip_vs.h b/libipvs/ip_vs.h
index 843c51a..9726a17 100644
--- a/libipvs/ip_vs.h
+++ b/libipvs/ip_vs.h
@@ -92,8 +92,11 @@
 #define IP_VS_CONN_F_ONE_PACKET        0x2000          /* forward only one 
packet */
 
 #define IP_VS_SCHEDNAME_MAXLEN 16
+#define IP_VS_PENAME_MAXLEN    16
 #define IP_VS_IFNAME_MAXLEN    16
 
+#define IP_VS_PEDATA_MAXLEN    255
+
 union nf_inet_addr {
         __u32           all[4];
         __be32          ip;
@@ -134,6 +137,7 @@ struct ip_vs_service_user {
        __be32                  netmask;        /* persistent netmask */
        u_int16_t               af;
        union nf_inet_addr      addr;
+       char                    pe_name[IP_VS_PENAME_MAXLEN];
 };
 
 struct ip_vs_dest_kern {
@@ -240,6 +244,7 @@ struct ip_vs_service_entry {
 
        u_int16_t               af;
        union nf_inet_addr      addr;
+       char                    pe_name[IP_VS_PENAME_MAXLEN];
 
 };
 
@@ -429,6 +434,9 @@ enum {
        IPVS_SVC_ATTR_NETMASK,          /* persistent netmask */
 
        IPVS_SVC_ATTR_STATS,            /* nested attribute for service stats */
+
+       IPVS_SVC_ATTR_PE_NAME,          /* name of scheduler */
+
        __IPVS_SVC_ATTR_MAX,
 };
 
diff --git a/libipvs/libipvs.c b/libipvs/libipvs.c
index 979d5bd..a157e18 100644
--- a/libipvs/libipvs.c
+++ b/libipvs/libipvs.c
@@ -40,6 +40,15 @@ static int family, try_nl = 1;
        { errno = EAFNOSUPPORT; return ret; }                   \
        s->__addr_v4 = s->addr.ip;                              \
 
+#define CHECK_PE(s, ret) if (s->pe_name)                       \
+       { errno = EAFNOSUPPORT; return ret; }
+
+#define CHECK_COMPAT_DEST(s, ret) CHECK_IPV4(s, ret)
+
+#define CHECK_COMPAT_SVC(s, ret)                               \
+       CHECK_IPV4(s, ret);                                     \
+       CHECK_PE(s, ret);
+
 #ifdef LIBIPVS_USE_NL
 struct nl_msg *ipvs_nl_message(int cmd, int flags)
 {
@@ -218,6 +227,8 @@ static int ipvs_nl_fill_service_attr(struct nl_msg *msg, 
ipvs_service_t *svc)
        }
 
        NLA_PUT_STRING(msg, IPVS_SVC_ATTR_SCHED_NAME, svc->sched_name);
+       if (svc->pe_name)
+               NLA_PUT_STRING(msg, IPVS_SVC_ATTR_PE_NAME, svc->pe_name);
        NLA_PUT(msg, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags);
        NLA_PUT_U32(msg, IPVS_SVC_ATTR_TIMEOUT, svc->timeout);
        NLA_PUT_U32(msg, IPVS_SVC_ATTR_NETMASK, svc->netmask);
@@ -245,7 +256,7 @@ int ipvs_add_service(ipvs_service_t *svc)
        }
 #endif
 
-       CHECK_IPV4(svc, -1);
+       CHECK_COMPAT_SVC(svc, -1);
        return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ADD, (char *)svc,
                          sizeof(struct ip_vs_service_kern));
 }
@@ -265,7 +276,7 @@ int ipvs_update_service(ipvs_service_t *svc)
                return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL);
        }
 #endif
-       CHECK_IPV4(svc, -1);
+       CHECK_COMPAT_SVC(svc, -1);
        return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_EDIT, (char *)svc,
                          sizeof(struct ip_vs_service_kern));
 }
@@ -285,7 +296,7 @@ int ipvs_del_service(ipvs_service_t *svc)
                return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL);
        }
 #endif
-       CHECK_IPV4(svc, -1);
+       CHECK_COMPAT_SVC(svc, -1);
        return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_DEL, (char *)svc,
                          sizeof(struct ip_vs_service_kern));
 }
@@ -310,7 +321,7 @@ int ipvs_zero_service(ipvs_service_t *svc)
                return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL);
        }
 #endif
-       CHECK_IPV4(svc, -1);
+       CHECK_COMPAT_SVC(svc, -1);
        return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ZERO, (char *)svc,
                          sizeof(struct ip_vs_service_kern));
 }
@@ -360,8 +371,8 @@ nla_put_failure:
        }
 #endif
 
-       CHECK_IPV4(svc, -1);
-       CHECK_IPV4(dest, -1);
+       CHECK_COMPAT_SVC(svc, -1);
+       CHECK_COMPAT_DEST(dest, -1);
        memcpy(&svcdest.svc, svc, sizeof(svcdest.svc));
        memcpy(&svcdest.dest, dest, sizeof(svcdest.dest));
        return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ADDDEST,
@@ -389,8 +400,8 @@ nla_put_failure:
                return -1;
        }
 #endif
-       CHECK_IPV4(svc, -1);
-       CHECK_IPV4(dest, -1);
+       CHECK_COMPAT_SVC(svc, -1);
+       CHECK_COMPAT_DEST(dest, -1);
        memcpy(&svcdest.svc, svc, sizeof(svcdest.svc));
        memcpy(&svcdest.dest, dest, sizeof(svcdest.dest));
        return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_EDITDEST,
@@ -419,8 +430,8 @@ nla_put_failure:
        }
 #endif
 
-       CHECK_IPV4(svc, -1);
-       CHECK_IPV4(dest, -1);
+       CHECK_COMPAT_SVC(svc, -1);
+       CHECK_COMPAT_DEST(dest, -1);
        memcpy(&svcdest.svc, svc, sizeof(svcdest.svc));
        memcpy(&svcdest.dest, dest, sizeof(svcdest.dest));
        return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_DELDEST,
@@ -593,6 +604,11 @@ static int ipvs_services_parse_cb(struct nl_msg *msg, void 
*arg)
                nla_get_string(svc_attrs[IPVS_SVC_ATTR_SCHED_NAME]),
                IP_VS_SCHEDNAME_MAXLEN);
 
+       if (svc_attrs[IPVS_SVC_ATTR_PE_NAME])
+               strncpy(get->entrytable[i].pe_name,
+                       nla_get_string(svc_attrs[IPVS_SVC_ATTR_PE_NAME]),
+                       IP_VS_PENAME_MAXLEN);
+
        get->entrytable[i].netmask = 
nla_get_u32(svc_attrs[IPVS_SVC_ATTR_NETMASK]);
        get->entrytable[i].timeout = 
nla_get_u32(svc_attrs[IPVS_SVC_ATTR_TIMEOUT]);
        nla_memcpy(&flags, svc_attrs[IPVS_SVC_ATTR_FLAGS], sizeof(flags));
@@ -937,7 +953,8 @@ ipvs_get_service_err2:
        }
 #endif
 
-       CHECK_IPV4(svc, NULL);
+       CHECK_COMPAT_SVC(svc, NULL);
+       CHECK_PE(svc, NULL);
        if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_SERVICE,
                       (char *)svc, &len)) {
                free(svc);
@@ -945,6 +962,7 @@ ipvs_get_service_err2:
        }
        svc->af = AF_INET;
        svc->addr.ip = svc->__addr_v4;
+       svc->pe_name[0] = '\0';
        return svc;
 }
 
@@ -1086,9 +1104,9 @@ const char *ipvs_strerror(int err)
                const char *message;
        } table [] = {
                { ipvs_add_service, EEXIST, "Service already exists" },
-               { ipvs_add_service, ENOENT, "Scheduler not found" },
+               { ipvs_add_service, ENOENT, "Scheduler or persistence engine 
not found" },
                { ipvs_update_service, ESRCH, "No such service" },
-               { ipvs_update_service, ENOENT, "Scheduler not found" },
+               { ipvs_update_service, ENOENT, "Scheduler or persistence engine 
not found" },
                { ipvs_del_service, ESRCH, "No such service" },
                { ipvs_zero_service, ESRCH, "No such service" },
                { ipvs_add_dest, ESRCH, "Service not defined" },
-- 
1.7.1


--
To unsubscribe from this list: send the line "unsubscribe lvs-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

<Prev in Thread] Current Thread [Next in Thread>