diff -Nru ipvsadm-1.29/debian/changelog ipvsadm-1.31/debian/changelog --- ipvsadm-1.29/debian/changelog 2018-08-05 07:21:46.000000000 +0000 +++ ipvsadm-1.31/debian/changelog 2020-01-05 20:33:49.000000000 +0000 @@ -1,3 +1,11 @@ +ipvsadm (1:1.31-1) unstable; urgency=medium + + * [950ed21] New upstream version 1.31 + * [e35ba70] Refresh patch + * [5639279] Bump standards version + + -- Alexander Wirt Sun, 05 Jan 2020 21:33:49 +0100 + ipvsadm (1:1.29-1) unstable; urgency=medium * [b30c9aa] New upstream version 1.29 diff -Nru ipvsadm-1.29/debian/control ipvsadm-1.31/debian/control --- ipvsadm-1.29/debian/control 2018-07-18 11:07:23.000000000 +0000 +++ ipvsadm-1.31/debian/control 2020-01-05 20:31:38.000000000 +0000 @@ -2,7 +2,7 @@ Section: net Priority: optional Maintainer: Alexander Wirt -Standards-Version: 4.1.5 +Standards-Version: 4.4.1 Homepage: https://git.kernel.org/pub/scm/utils/kernel/ipvsadm/ipvsadm.git Vcs-Browser: https://github.com/formorer/pkg-ipvsadm Vcs-Git: https://github.com/formorer/pkg-ipvsadm.git diff -Nru ipvsadm-1.29/debian/patches/limit-weight-to-int-max.patch ipvsadm-1.31/debian/patches/limit-weight-to-int-max.patch --- ipvsadm-1.29/debian/patches/limit-weight-to-int-max.patch 2018-08-05 07:14:06.000000000 +0000 +++ ipvsadm-1.31/debian/patches/limit-weight-to-int-max.patch 2020-01-05 20:28:24.000000000 +0000 @@ -10,7 +10,7 @@ --- a/ipvsadm.8 +++ b/ipvsadm.8 -@@ -333,7 +333,7 @@ +@@ -386,7 +386,7 @@ .B -w, --weight \fIweight\fP \fIWeight\fP is an integer specifying the capacity of a server relative to the others in the pool. The valid values of \fIweight\fP @@ -21,9 +21,9 @@ algorithms distributed with the Linux Virtual Server. Setting a --- a/ipvsadm.c +++ b/ipvsadm.c -@@ -645,7 +645,7 @@ +@@ -762,7 +762,7 @@ case 'w': - set_option(options, OPT_WEIGHT); + set_option(options, OPTC_WEIGHT); if ((ce->dest.weight = - string_to_number(optarg, 0, 65535)) == -1) + string_to_number(optarg, 0, INT_MAX)) == -1) diff -Nru ipvsadm-1.29/debian/watch ipvsadm-1.31/debian/watch --- ipvsadm-1.29/debian/watch 2018-08-05 07:02:20.000000000 +0000 +++ ipvsadm-1.31/debian/watch 2020-01-05 20:26:33.000000000 +0000 @@ -1,3 +1,3 @@ version=4 -opts=pgpsigurlmangle=s/.gz$/.sign/ https://www.kernel.org/pub/linux/utils/kernel/ipvsadm/ipvsadm-(.*)\.tar\.gz +https://www.kernel.org/pub/linux/utils/kernel/ipvsadm/ipvsadm-(.*)\.tar\.gz diff -Nru ipvsadm-1.29/ipvsadm.8 ipvsadm-1.31/ipvsadm.8 --- ipvsadm-1.29/ipvsadm.8 2018-07-17 04:15:56.000000000 +0000 +++ ipvsadm-1.31/ipvsadm.8 2019-12-24 13:20:30.000000000 +0000 @@ -94,11 +94,11 @@ The first format manipulates a virtual service and the algorithm for assigning service requests to real servers. Optionally, a persistent timeout and network mask for the granularity of a persistent service -may be specified. The second format manipulates a real server that is -associated with an existing virtual service. When specifying a real -server, the packet-forwarding method and the weight of the real -server, relative to other real servers for the virtual service, may be -specified, otherwise defaults will be used. +and a persistence engine may be specified. The second format manipulates +a real server that is associated with an existing virtual service. +When specifying a real server, the packet-forwarding method and the +weight of the real server, relative to other real servers for the +virtual service, may be specified, otherwise defaults will be used. .SS COMMANDS \fBipvsadm\fR(8) recognises the commands described below. Upper-case commands maintain virtual services. Lower-case commands maintain real @@ -196,9 +196,10 @@ .TP .B -f, --fwmark-service \fIinteger\fP Use a firewall-mark, an integer value greater than zero, to denote a -virtual service instead of an address, port and protocol (UDP or -TCP). The marking of packets with a firewall-mark is configured using -the -m|--mark option to \fBiptables\fR(8). It can be used to build a +virtual service instead of an address, port and protocol (UDP, TCP or +SCTP). The marking of packets with a firewall-mark is configured using +the -m|--mark option to \fBiptables\fR(8), the meta mark set \fIvalue\fR +option to \fBnft\fR(8) or via an eBPF program. It can be used to build a virtual service associated with the same real servers, covering multiple IP address, port and protocol triplets. If IPv6 addresses are used, the -6 option must be used. @@ -267,6 +268,24 @@ \fBnq\fR - Never Queue: assigns an incoming job to an idle server if there is, instead of waiting for a fast one; if all the servers are busy, it adopts the Shortest Expected Delay policy to assign the job. +.sp +\fBfo\fR - Weighted Failover: assigns an incoming job to the server +with the highest weight that is currently available. +.sp +\fBovf\fR - Weighted Overflow: assigns an incoming job to the server +with the highest weight that is currently available and overflows +to the next when active connections exceed the node's weight. Note +that this scheduler might not be suitable for UDP because it only uses +active connections. +.sp +\fBmh\fR - Maglev Hashing: assigns incoming jobs based on Google's +Maglev hashing algorithm, providing an almost equal share of jobs to +each real server and provides minimal disruption. When the set of real +servers changes, a connection will likely be sent to the same real +server as it was before. +This scheduler has two flags: mh-fallback, which enables fallback to a +different server if the selected server was unavailable, and mh-port, +which adds the source port number to the hash computation. .TP .B -p, --persistent [\fItimeout\fP] Specify that a virtual service is persistent. If this option is @@ -295,6 +314,10 @@ IPv6 netmasks should be specified as a prefix length between 1 and 128. The default prefix length is 128. .TP +.B --pe \fIpersistence-engine\fP +Specify an alternative persistence engine to be used. Currently the +only alternative persistence engine available is sip. +.TP .B -b, --sched-flags \fIsched-flags\fP Set scheduler flags for this virtual server. \fIsched-flags\fP is a comma-separated list of flags. See the scheduler descriptions for @@ -321,6 +344,36 @@ .sp \fB-i, --ipip\fR Use ipip encapsulation (tunneling). .sp +.ti +8 +.B --tun-type \fItun-type\fP +.ti +16 +\fItun-type\fP is one of \fIipip\fP|\fIgue\fP|\fIgre\fP. +The default value of \fItun-type\fP is \fIipip\fP. +.sp +.ti +8 +.B --tun-port \fItun-port\fP +.ti +16 +\fItun-port\fP is an integer specifying the destination port. +Only valid for \fItun-type\fP \fIgue\fP. +.sp +.ti +8 +.B --tun-nocsum +.ti +16 +Specify that tunnel checksums are disabled. This is the default. +Only valid for \fItun-type\fP \fIgue\fP and \fIgre\fP. +.sp +.ti +8 +.B --tun-csum +.ti +16 +Specify that tunnel checksums are enabled. +Only valid for \fItun-type\fP \fIgue\fP and \fIgre\fP. +.sp +.ti +8 +.B --tun-remcsum +.ti +16 +Specify that Remote Checksum Offload is enabled. +Only valid for \fItun-type\fP \fIgue\fP. +.sp \fB-m, --masquerading\fR Use masquerading (network access translation, or NAT). .sp \fBNote:\fR Regardless of the packet-forwarding mechanism specified, @@ -398,6 +451,11 @@ will include persistence engine data, if any is present, when listing connections. .TP +.B --tun-info +Output of tunneling information. The \fIlist\fP command with this +option will display the tunneling information of services and their +servers. +.TP .B --sort Sort the list of virtual services and real servers. The virtual service entries are sorted in ascending order by svc.protocol = option_to_protocol(c); parse = parse_service(optarg, &ce->svc); if (!(parse & SERVICE_ADDR)) @@ -583,7 +700,7 @@ "address[:port] specified"); break; case 'f': - set_option(options, OPT_SERVICE); + set_option(options, OPTC_SERVICE); /* * Set protocol to a sane values, even * though it is not used @@ -593,18 +710,18 @@ ce->svc.fwmark = parse_fwmark(optarg); break; case 's': - set_option(options, OPT_SCHEDULER); + set_option(options, OPTC_SCHEDULER); strncpy(ce->svc.sched_name, - optarg, IP_VS_SCHEDNAME_MAXLEN); + optarg, IP_VS_SCHEDNAME_MAXLEN - 1); break; case 'p': - set_option(options, OPT_PERSISTENT); + set_option(options, OPTC_PERSISTENT); ce->svc.flags |= IP_VS_SVC_F_PERSISTENT; ce->svc.timeout = parse_timeout(optarg, 1, MAX_TIMEOUT); break; case 'M': - set_option(options, OPT_NETMASK); + set_option(options, OPTC_NETMASK); if (ce->svc.af != AF_INET6) { parse = parse_netmask(optarg, &ce->svc.netmask); if (parse != 1) @@ -617,7 +734,7 @@ } break; case 'r': - set_option(options, OPT_SERVER); + set_option(options, OPTC_SERVER); ipvs_service_t t_dest = ce->svc; parse = parse_service(optarg, &t_dest); ce->dest.af = t_dest.af; @@ -631,84 +748,84 @@ ce->dest.port = ce->svc.port; break; case 'i': - set_option(options, OPT_FORWARD); + set_option(options, OPTC_FORWARD); ce->dest.conn_flags = IP_VS_CONN_F_TUNNEL; break; case 'g': - set_option(options, OPT_FORWARD); + set_option(options, OPTC_FORWARD); ce->dest.conn_flags = IP_VS_CONN_F_DROUTE; break; case 'm': - set_option(options, OPT_FORWARD); + set_option(options, OPTC_FORWARD); ce->dest.conn_flags = IP_VS_CONN_F_MASQ; break; case 'w': - set_option(options, OPT_WEIGHT); + set_option(options, OPTC_WEIGHT); if ((ce->dest.weight = string_to_number(optarg, 0, 65535)) == -1) fail(2, "illegal weight specified"); break; case 'x': - set_option(options, OPT_UTHRESHOLD); + set_option(options, OPTC_UTHRESHOLD); if ((ce->dest.u_threshold = string_to_number(optarg, 0, INT_MAX)) == -1) fail(2, "illegal u_threshold specified"); break; case 'y': - set_option(options, OPT_LTHRESHOLD); + set_option(options, OPTC_LTHRESHOLD); if ((ce->dest.l_threshold = string_to_number(optarg, 0, INT_MAX)) == -1) fail(2, "illegal l_threshold specified"); break; case 'c': - set_option(options, OPT_CONNECTION); + set_option(options, OPTC_CONNECTION); break; case 'n': - set_option(options, OPT_NUMERIC); + set_option(options, OPTC_NUMERIC); *format |= FMT_NUMERIC; break; case TAG_MCAST_INTERFACE: - set_option(options, OPT_MCAST); + set_option(options, OPTC_MCAST); strncpy(ce->daemon.mcast_ifn, - optarg, IP_VS_IFNAME_MAXLEN); + optarg, IP_VS_IFNAME_MAXLEN - 1); break; case 'I': - set_option(options, OPT_SYNCID); + set_option(options, OPTC_SYNCID); if ((ce->daemon.syncid = string_to_number(optarg, 0, 255)) == -1) fail(2, "illegal syncid specified"); break; case TAG_TIMEOUT: - set_option(options, OPT_TIMEOUT); + set_option(options, OPTC_TIMEOUT); break; case TAG_DAEMON: - set_option(options, OPT_DAEMON); + set_option(options, OPTC_DAEMON); break; case TAG_STATS: - set_option(options, OPT_STATS); + set_option(options, OPTC_STATS); *format |= FMT_STATS; break; case TAG_RATE: - set_option(options, OPT_RATE); + set_option(options, OPTC_RATE); *format |= FMT_RATE; break; case TAG_THRESHOLDS: - set_option(options, OPT_THRESHOLDS); + set_option(options, OPTC_THRESHOLDS); *format |= FMT_THRESHOLDS; break; case TAG_PERSISTENTCONN: - set_option(options, OPT_PERSISTENTCONN); + set_option(options, OPTC_PERSISTENTCONN); *format |= FMT_PERSISTENTCONN; break; case TAG_NO_SORT: - set_option(options, OPT_NOSORT ); + set_option(options, OPTC_NOSORT); *format |= FMT_NOSORT; break; case TAG_SORT: /* Sort is the default, this is a no-op for compatibility */ break; case 'X': - set_option(options, OPT_EXACT); + set_option(options, OPTC_EXACT); *format |= FMT_EXACT; break; case '6': @@ -720,20 +837,20 @@ } break; case 'o': - set_option(options, OPT_ONEPACKET); + set_option(options, OPTC_ONEPACKET); ce->svc.flags |= IP_VS_SVC_F_ONEPACKET; break; case TAG_PERSISTENCE_ENGINE: - set_option(options, OPT_PERSISTENCE_ENGINE); + set_option(options, OPTC_PERSISTENCE_ENGINE); strncpy(ce->svc.pe_name, optarg, IP_VS_PENAME_MAXLEN); break; case 'b': - set_option(options, OPT_SCHED_FLAGS); + set_option(options, OPTC_SCHED_FLAGS); snprintf(sched_flags_arg, sizeof(sched_flags_arg), "%s", optarg); break; case TAG_MCAST_GROUP: - set_option(options, OPT_MCAST_GROUP); + set_option(options, OPTC_MCAST_GROUP); if (strchr(optarg, ':')) { if (inet_pton(AF_INET6, optarg, &ce->daemon.mcast_group) <= 0 || @@ -753,26 +870,56 @@ } break; case TAG_MCAST_PORT: - set_option(options, OPT_MCAST_PORT); + set_option(options, OPTC_MCAST_PORT); parse = string_to_number(optarg, 1, 65535); if (parse == -1) fail(2, "illegal mcast-port specified"); ce->daemon.mcast_port = parse; break; case TAG_MCAST_TTL: - set_option(options, OPT_MCAST_TTL); + set_option(options, OPTC_MCAST_TTL); parse = string_to_number(optarg, 1, 255); if (parse == -1) fail(2, "illegal mcast-ttl specified"); ce->daemon.mcast_ttl = parse; break; case TAG_SYNC_MAXLEN: - set_option(options, OPT_SYNC_MAXLEN); + set_option(options, OPTC_SYNC_MAXLEN); parse = string_to_number(optarg, 1, 65535 - 20 - 8); if (parse == -1) fail(2, "illegal sync-maxlen specified"); ce->daemon.sync_maxlen = parse; break; + case TAG_TUN_INFO: + set_option(options, OPTC_TUN_INFO); + *format |= FMT_TUN_INFO; + break; + case TAG_TUN_TYPE: + set_option(options, OPTC_TUN_TYPE); + parse = parse_tun_type(optarg); + if (parse == -1) + fail(2, "illegal tunnel type specified"); + ce->dest.tun_type = parse; + break; + case TAG_TUN_PORT: + set_option(options, OPTC_TUN_PORT); + parse = string_to_number(optarg, 1, 65535); + if (parse == -1) + fail(2, "illegal tunnel port specified"); + ce->dest.tun_port = htons(parse); + break; + case TAG_TUN_NOCSUM: + set_option(options, OPTC_TUN_NOCSUM); + ce->dest.tun_flags |= IP_VS_TUNNEL_ENCAP_FLAG_NOCSUM; + break; + case TAG_TUN_CSUM: + set_option(options, OPTC_TUN_CSUM); + ce->dest.tun_flags |= IP_VS_TUNNEL_ENCAP_FLAG_CSUM; + break; + case TAG_TUN_REMCSUM: + set_option(options, OPTC_TUN_REMCSUM); + ce->dest.tun_flags |= IP_VS_TUNNEL_ENCAP_FLAG_REMCSUM; + break; default: fail(2, "invalid option `%s'", poptBadOption(context, POPT_BADOPTION_NOALIAS)); @@ -845,14 +992,21 @@ static int process_options(int argc, char **argv, int reading_stdin) { struct ipvs_command_entry ce; - unsigned int options = OPT_NONE; + unsigned long long options = OPT_NONE; unsigned int format = FMT_NONE; + unsigned int fwd_method; int result = 0; memset(&ce, 0, sizeof(struct ipvs_command_entry)); ce.cmd = CMD_NONE; /* Set the default weight 1 */ ce.dest.weight = 1; + /* Set the default tunnel type 0(ipip) */ + ce.dest.tun_type = 0; + /* Set the default tunnel port 0(n/a) */ + ce.dest.tun_port = 0; + /* Set the default tunnel flags 0(nocsum) */ + ce.dest.tun_flags = 0; /* Set direct routing as default forwarding method */ ce.dest.conn_flags = IP_VS_CONN_F_DROUTE; /* Set the default persistent granularity to /32 mask */ @@ -883,6 +1037,8 @@ if (ce.cmd == CMD_STARTDAEMON && strlen(ce.daemon.mcast_ifn) == 0) strcpy(ce.daemon.mcast_ifn, DEF_MCAST_IFN); + fwd_method = ce.dest.conn_flags & IP_VS_CONN_F_FWD_MASK; + if (ce.cmd == CMD_ADDDEST || ce.cmd == CMD_EDITDEST) { /* * The destination port must be equal to the service port @@ -890,15 +1046,25 @@ * Don't worry about this if fwmark is used. */ if (!ce.svc.fwmark && - (ce.dest.conn_flags == IP_VS_CONN_F_TUNNEL - || ce.dest.conn_flags == IP_VS_CONN_F_DROUTE)) + (fwd_method == IP_VS_CONN_F_TUNNEL || + fwd_method == IP_VS_CONN_F_DROUTE)) ce.dest.port = ce.svc.port; /* Tunneling allows different address family */ if (ce.dest.af != ce.svc.af && - ce.dest.conn_flags != IP_VS_CONN_F_TUNNEL) + fwd_method != IP_VS_CONN_F_TUNNEL) fail(2, "Different address family is allowed only " "for tunneling servers"); + + /* Only tunneling allows tunnel options */ + if (((options & (OPT_TUN_TYPE | OPT_TUN_PORT)) || + (options & (OPT_TUN_NOCSUM | OPT_TUN_CSUM)) || + (options & OPT_TUN_REMCSUM)) && + fwd_method != IP_VS_CONN_F_TUNNEL) + fail(2, + "Tunnel options conflict with forward method"); + + tunnel_opt_check(ce.dest.tun_type, options); } switch (ce.cmd) { @@ -1145,6 +1311,16 @@ if (strcmp(sched, "sh")) fail(2, "incompatible scheduler flag `%s'", flag); + } else if (!strcmp(flag, "mh-fallback")) { + flags |= IP_VS_SVC_F_SCHED_MH_FALLBACK; + if (strcmp(sched, "mh")) + fail(2, "incompatible scheduler flag `%s'", + flag); + } else if (!strcmp(flag, "mh-port")) { + flags |= IP_VS_SVC_F_SCHED_MH_PORT; + if (strcmp(sched, "mh")) + fail(2, "incompatible scheduler flag `%s'", + flag); } else { fail(2, "invalid scheduler flag `%s'", flag); } @@ -1153,8 +1329,24 @@ return flags; } +static int parse_tun_type(const char *tun_type) +{ + int type = -1; + + if (!strcmp(tun_type, "ipip")) + type = IP_VS_CONN_F_TUNNEL_TYPE_IPIP; + else if (!strcmp(tun_type, "gue")) + type = IP_VS_CONN_F_TUNNEL_TYPE_GUE; + else if (!strcmp(tun_type, "gre")) + type = IP_VS_CONN_F_TUNNEL_TYPE_GRE; + else + type = -1; + + return type; +} + static void -generic_opt_check(int command, int options) +generic_opt_check(int command, unsigned long long options) { int i, j; int last = 0, count = 0; @@ -1163,7 +1355,7 @@ i = command - CMD_NONE -1; for (j = 0; j < NUMBER_OF_OPT; j++) { - if (!(options & (1< 1; option >>= 1, ptr++); + int i, j, k; + int last = 0, count = 0; - return *ptr; + /* Check that tunnel types are valid with options. */ + i = tun_type; + + for (j = 0; j < NUMBER_OF_TUN_OPT; j++) { + k = tunopts[j]; + if (!(options & (1ULL << k))) { + if (tunnel_types_v_options[i][j] == '+') + fail(2, "You need to supply the '%s' " + "option for the '%s' tunnel type", + optnames[k], tunnames[i]); + } else { + if (tunnel_types_v_options[i][j] == 'x') + fail(2, "Illegal '%s' option with " + "the '%s' tunnel type", + optnames[k], tunnames[i]); + if (tunnel_types_v_options[i][j] == '1') { + count++; + if (count == 1) { + last = k; + continue; + } + fail(2, "The option '%s' conflicts with the " + "'%s' option in the '%s' tunnel type", + optnames[k], optnames[last], tunnames[i]); + } + } + } } static void @@ -1205,10 +1423,11 @@ } static void -set_option(unsigned int *options, unsigned int option) +set_option(unsigned long long *options, int optc) { + unsigned long long option = 1ULL << optc; if (*options & option) - fail(2, "multiple '%s' options specified", opt2name(option)); + fail(2, "multiple '%s' options specified", optnames[optc]); *options |= option; } @@ -1291,6 +1510,12 @@ " --gatewaying -g gatewaying (direct routing) (default)\n" " --ipip -i ipip encapsulation (tunneling)\n" " --masquerading -m masquerading (NAT)\n" + " --tun-type type one of ipip|gue|gre,\n" + " the default tunnel type is %s.\n" + " --tun-port port tunnel destination port\n" + " --tun-nocsum tunnel encapsulation without checksum\n" + " --tun-csum tunnel encapsulation with checksum\n" + " --tun-remcsum tunnel encapsulation with remote checksum\n" " --weight -w weight capacity of real server\n" " --u-threshold -x uthreshold upper threshold of connections\n" " --l-threshold -y lthreshold lower threshold of connections\n" @@ -1302,12 +1527,13 @@ " --exact expand numbers (display exact values)\n" " --thresholds output of thresholds information\n" " --persistent-conn output of persistent connection info\n" + " --tun-info output of tunnel information\n" " --nosort disable sorting output of service/server entries\n" " --sort does nothing, for backwards compatibility\n" " --ops -o one-packet scheduling\n" " --numeric -n numeric output of addresses and ports\n" " --sched-flags -b flags scheduler flags (comma-separated)\n", - DEF_SCHED); + DEF_SCHED, DEF_TUNNEL_TYPE); fprintf(stream, "Daemon Options:\n" @@ -1415,8 +1641,8 @@ unsigned int expires; unsigned short af = AF_INET; unsigned short daf = AF_INET; - char pe_name[IP_VS_PENAME_MAXLEN]; - char pe_data[IP_VS_PEDATA_MAXLEN]; + char pe_name[IP_VS_PENAME_MAXLEN + 1]; + char pe_data[IP_VS_PEDATA_MAXLEN + 1]; int n; char temp1[INET6_ADDRSTRLEN], temp2[INET6_ADDRSTRLEN], temp3[INET6_ADDRSTRLEN]; @@ -1555,6 +1781,41 @@ } +static inline char *fwd_tun_info(ipvs_dest_entry_t *e) +{ + char *info = malloc(16); + + if (!info) + return NULL; + + switch (e->conn_flags & IP_VS_CONN_F_FWD_MASK) { + case IP_VS_CONN_F_TUNNEL: + switch (e->tun_type) { + case IP_VS_CONN_F_TUNNEL_TYPE_IPIP: + snprintf(info, 16, "%s", tunnames[e->tun_type]); + break; + case IP_VS_CONN_F_TUNNEL_TYPE_GUE: + snprintf(info, 16, "%s:%d:%s", + tunnames[e->tun_type], ntohs(e->tun_port), + tunflags[e->tun_flags]); + break; + case IP_VS_CONN_F_TUNNEL_TYPE_GRE: + snprintf(info, 16, "%s:%s", + tunnames[e->tun_type], + tunflags[e->tun_flags]); + break; + default: + free(info); + return NULL; + } + break; + default: + free(info); + return NULL; + } + return info; +} + static void print_largenum(unsigned long long i, unsigned int format) { if (format & FMT_EXACT) { @@ -1589,8 +1850,11 @@ strcat(flags, "sh-fallback,"); if (se->flags & IP_VS_SVC_F_SCHED_SH_PORT) strcat(flags, "sh-port,"); - if (se->flags & IP_VS_SVC_F_SCHED3) - strcat(flags, "flag-3,"); + } else if (!strcmp(se->sched_name, "mh")) { + if (se->flags & IP_VS_SVC_F_SCHED_MH_FALLBACK) + strcat(flags, "mh-fallback,"); + if (se->flags & IP_VS_SVC_F_SCHED_MH_PORT) + strcat(flags, "mh-port,"); } else { if (se->flags & IP_VS_SVC_F_SCHED1) strcat(flags, "flag-1,"); @@ -1628,12 +1892,56 @@ " -> RemoteAddress:Port\n", "Prot LocalAddress:Port", "Weight", "PersistConn", "ActiveConn", "InActConn"); + else if ((format & FMT_TUN_INFO)) + printf("Prot LocalAddress:Port Scheduler Flags\n" + " -> RemoteAddress:Port Forward TunnelInfo Weight ActiveConn InActConn\n"); else if (!(format & FMT_RULE)) printf("Prot LocalAddress:Port Scheduler Flags\n" " -> RemoteAddress:Port Forward Weight ActiveConn InActConn\n"); } +static inline void +print_tunnel_rule(char *svc_name, char *dname, ipvs_dest_entry_t *e) +{ + switch (e->tun_type) { + case IP_VS_CONN_F_TUNNEL_TYPE_GRE: + printf("-a %s -r %s %s -w %d --tun-type %s %s\n", + svc_name, + dname, + fwd_switch(e->conn_flags), + e->weight, + tunnames[e->tun_type], + tun_flags_opts[e->tun_flags]); + break; + case IP_VS_CONN_F_TUNNEL_TYPE_GUE: + printf("-a %s -r %s %s -w %d --tun-type %s --tun-port %d %s\n", + svc_name, + dname, + fwd_switch(e->conn_flags), + e->weight, + tunnames[e->tun_type], + ntohs(e->tun_port), + tun_flags_opts[e->tun_flags]); + break; + case IP_VS_CONN_F_TUNNEL_TYPE_IPIP: + printf("-a %s -r %s %s -w %d --tun-type %s\n", + svc_name, + dname, + fwd_switch(e->conn_flags), + e->weight, + tunnames[e->tun_type]); + break; + default: + printf("-a %s -r %s %s -w %d\n", + svc_name, + dname, + fwd_switch(e->conn_flags), + e->weight); + break; + } +} + static void print_service_entry(ipvs_service_entry_t *se, unsigned int format) { @@ -1755,6 +2063,7 @@ for (i = 0; i < d->num_dests; i++) { char *dname; ipvs_dest_entry_t *e = &d->entrytable[i]; + unsigned int fwd_method = e->conn_flags & IP_VS_CONN_F_FWD_MASK; if (!(dname = addrport_to_anyname(e->af, &(e->addr), ntohs(e->port), se->protocol, format))) { @@ -1765,8 +2074,15 @@ dname[28] = '\0'; if (format & FMT_RULE) { - printf("-a %s -r %s %s -w %d\n", svc_name, dname, - fwd_switch(e->conn_flags), e->weight); + if (fwd_method == IP_VS_CONN_F_TUNNEL) { + print_tunnel_rule(svc_name, dname, e); + } else { + printf("-a %s -r %s %s -w %d\n", + svc_name, + dname, + fwd_switch(e->conn_flags), + e->weight); + } } else if (format & FMT_STATS) { printf(" -> %-28s", dname); print_largenum(e->stats64.conns, format); @@ -1791,6 +2107,15 @@ printf(" -> %-28s %-9u %-11u %-10u %-10u\n", dname, e->weight, e->persistconns, e->activeconns, e->inactconns); + } else if (format & FMT_TUN_INFO) { + char *ti = fwd_tun_info(e); + + printf(" -> %-28s %-7s %-13s %-6d %-10u %-10u\n", + dname, fwd_name(e->conn_flags), + ti ? : NA, + e->weight, e->activeconns, e->inactconns); + + free(ti); } else printf(" -> %-28s %-7s %-6d %-10u %-10u\n", dname, fwd_name(e->conn_flags), diff -Nru ipvsadm-1.29/ipvsadm.spec ipvsadm-1.31/ipvsadm.spec --- ipvsadm-1.29/ipvsadm.spec 2018-07-17 04:15:56.000000000 +0000 +++ ipvsadm-1.31/ipvsadm.spec 2019-12-24 13:27:30.000000000 +0000 @@ -2,7 +2,7 @@ Summary: Utility to administer the Linux Virtual Server Name: ipvsadm -Version: 1.29 +Version: 1.31 Release: 1 License: GPL URL: http://www.LinuxVirtualServer.org/ diff -Nru ipvsadm-1.29/libipvs/ip_vs.h ipvsadm-1.31/libipvs/ip_vs.h --- ipvsadm-1.29/libipvs/ip_vs.h 2018-07-17 04:15:56.000000000 +0000 +++ ipvsadm-1.31/libipvs/ip_vs.h 2019-12-24 13:20:30.000000000 +0000 @@ -36,6 +36,9 @@ #define IP_VS_SVC_F_SCHED_SH_FALLBACK IP_VS_SVC_F_SCHED1 /* SH fallback */ #define IP_VS_SVC_F_SCHED_SH_PORT IP_VS_SVC_F_SCHED2 /* SH use port */ +#define IP_VS_SVC_F_SCHED_MH_FALLBACK IP_VS_SVC_F_SCHED1 /* MH fallback */ +#define IP_VS_SVC_F_SCHED_MH_PORT IP_VS_SVC_F_SCHED2 /* MH use port */ + /* * IPVS sync daemon states @@ -104,6 +107,19 @@ #define IP_VS_PEDATA_MAXLEN 255 +/* Tunnel types */ +enum { + IP_VS_CONN_F_TUNNEL_TYPE_IPIP = 0, /* IPIP */ + IP_VS_CONN_F_TUNNEL_TYPE_GUE, /* GUE */ + IP_VS_CONN_F_TUNNEL_TYPE_GRE, /* GRE */ + IP_VS_CONN_F_TUNNEL_TYPE_MAX, +}; + +/* Tunnel encapsulation flags */ +#define IP_VS_TUNNEL_ENCAP_FLAG_NOCSUM (0) +#define IP_VS_TUNNEL_ENCAP_FLAG_CSUM (1 << 0) +#define IP_VS_TUNNEL_ENCAP_FLAG_REMCSUM (1 << 1) + union nf_inet_addr { __u32 all[4]; __be32 ip; @@ -144,7 +160,7 @@ __be32 netmask; /* persistent netmask */ u_int16_t af; union nf_inet_addr addr; - char pe_name[IP_VS_PENAME_MAXLEN]; + char pe_name[IP_VS_PENAME_MAXLEN + 1]; }; struct ip_vs_dest_kern { @@ -175,6 +191,11 @@ u_int32_t l_threshold; /* lower threshold */ u_int16_t af; union nf_inet_addr addr; + + /* tunnel info */ + u_int16_t tun_type; /* tunnel type */ + __be16 tun_port; /* tunnel port */ + u_int16_t tun_flags; /* tunnel flags */ }; /* @@ -267,7 +288,7 @@ u_int16_t af; union nf_inet_addr addr; - char pe_name[IP_VS_PENAME_MAXLEN]; + char pe_name[IP_VS_PENAME_MAXLEN + 1]; /* statistics, 64-bit */ struct ip_vs_stats64 stats64; @@ -310,6 +331,11 @@ /* statistics, 64-bit */ struct ip_vs_stats64 stats64; + + /* tunnel info */ + u_int16_t tun_type; /* tunnel type */ + __be16 tun_port; /* tunnel port */ + u_int16_t tun_flags; /* tunnel flags */ }; /* The argument to IP_VS_SO_GET_DESTS */ @@ -524,6 +550,12 @@ IPVS_DEST_ATTR_STATS64, /* nested attribute for dest stats */ + IPVS_DEST_ATTR_TUN_TYPE, /* tunnel type */ + + IPVS_DEST_ATTR_TUN_PORT, /* tunnel port */ + + IPVS_DEST_ATTR_TUN_FLAGS, /* tunnel flags */ + __IPVS_DEST_ATTR_MAX, }; diff -Nru ipvsadm-1.29/libipvs/libipvs.c ipvsadm-1.31/libipvs/libipvs.c --- ipvsadm-1.29/libipvs/libipvs.c 2018-07-17 04:15:56.000000000 +0000 +++ ipvsadm-1.31/libipvs/libipvs.c 2019-12-24 13:20:30.000000000 +0000 @@ -63,7 +63,7 @@ if (!msg) return NULL; - genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, flags, + genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family, 0, flags, cmd, IPVS_GENL_VERSION); return msg; @@ -74,9 +74,23 @@ return NL_OK; } +struct cb_err_data { + int err; +}; + +static int ipvs_nl_err_cb(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, + void *arg) +{ + struct cb_err_data *data = arg; + + data->err = nlerr->error; + return -nl_syserr2nlerr(nlerr->error); +} + int ipvs_nl_send_message(struct nl_msg *msg, nl_recvmsg_msg_cb_t func, void *arg) { int err = EINVAL; + struct cb_err_data err_data = { .err = 0 }; sock = nl_socket_alloc(); if (!sock) { @@ -100,12 +114,18 @@ if (nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, func, arg) != 0) goto fail_genl; + if (nl_socket_modify_err_cb(sock, NL_CB_CUSTOM, ipvs_nl_err_cb, + &err_data) != 0) + goto fail_genl; if (nl_send_auto_complete(sock, msg) < 0) goto fail_genl; - if ((err = -nl_recvmsgs_default(sock)) > 0) + if (nl_recvmsgs_default(sock) < 0) { + if (err_data.err) + err = -err_data.err; goto fail_genl; + } nlmsg_free(msg); @@ -370,6 +390,9 @@ NLA_PUT_U16(msg, IPVS_DEST_ATTR_PORT, dst->port); NLA_PUT_U32(msg, IPVS_DEST_ATTR_FWD_METHOD, dst->conn_flags & IP_VS_CONN_F_FWD_MASK); NLA_PUT_U32(msg, IPVS_DEST_ATTR_WEIGHT, dst->weight); + NLA_PUT_U8(msg, IPVS_DEST_ATTR_TUN_TYPE, dst->tun_type); + NLA_PUT_U16(msg, IPVS_DEST_ATTR_TUN_PORT, dst->tun_port); + NLA_PUT_U16(msg, IPVS_DEST_ATTR_TUN_FLAGS, dst->tun_flags); NLA_PUT_U32(msg, IPVS_DEST_ATTR_U_THRESH, dst->u_threshold); NLA_PUT_U32(msg, IPVS_DEST_ATTR_L_THRESH, dst->l_threshold); @@ -699,7 +722,7 @@ strncpy(get->entrytable[i].sched_name, nla_get_string(svc_attrs[IPVS_SVC_ATTR_SCHED_NAME]), - IP_VS_SCHEDNAME_MAXLEN); + IP_VS_SCHEDNAME_MAXLEN - 1); if (svc_attrs[IPVS_SVC_ATTR_PE_NAME]) strncpy(get->entrytable[i].pe_name, @@ -836,6 +859,9 @@ struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1]; struct nlattr *dest_attrs[IPVS_DEST_ATTR_MAX + 1]; struct nlattr *attr_addr_family = NULL; + struct nlattr *attr_tun_type = NULL; + struct nlattr *attr_tun_port = NULL; + struct nlattr *attr_tun_flags = NULL; struct ip_vs_get_dests **dp = (struct ip_vs_get_dests **)arg; struct ip_vs_get_dests *d = (struct ip_vs_get_dests *)*dp; int i = d->num_dests; @@ -868,6 +894,15 @@ d->entrytable[i].port = nla_get_u16(dest_attrs[IPVS_DEST_ATTR_PORT]); d->entrytable[i].conn_flags = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_FWD_METHOD]); d->entrytable[i].weight = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_WEIGHT]); + attr_tun_type = dest_attrs[IPVS_DEST_ATTR_TUN_TYPE]; + if (attr_tun_type) + d->entrytable[i].tun_type = nla_get_u8(attr_tun_type); + attr_tun_port = dest_attrs[IPVS_DEST_ATTR_TUN_PORT]; + if (attr_tun_port) + d->entrytable[i].tun_port = nla_get_u16(attr_tun_port); + attr_tun_flags = dest_attrs[IPVS_DEST_ATTR_TUN_FLAGS]; + if (attr_tun_flags) + d->entrytable[i].tun_flags = nla_get_u16(attr_tun_flags); d->entrytable[i].u_threshold = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_U_THRESH]); d->entrytable[i].l_threshold = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_L_THRESH]); d->entrytable[i].activeconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_ACTIVE_CONNS]); @@ -1179,7 +1214,7 @@ u[i].state = nla_get_u32(daemon_attrs[IPVS_DAEMON_ATTR_STATE]); strncpy(u[i].mcast_ifn, nla_get_string(daemon_attrs[IPVS_DAEMON_ATTR_MCAST_IFN]), - IP_VS_IFNAME_MAXLEN); + IP_VS_IFNAME_MAXLEN - 1); u[i].syncid = nla_get_u32(daemon_attrs[IPVS_DAEMON_ATTR_SYNC_ID]); a = daemon_attrs[IPVS_DAEMON_ATTR_SYNC_MAXLEN]; @@ -1245,7 +1280,8 @@ } for (i = 0; i < 2; i++) { u[i].state = dmk[i].state; - strncpy(u[i].mcast_ifn, dmk[i].mcast_ifn, IP_VS_IFNAME_MAXLEN); + strncpy(u[i].mcast_ifn, dmk[i].mcast_ifn, + IP_VS_IFNAME_MAXLEN - 1); u[i].syncid = dmk[i].syncid; } return u; diff -Nru ipvsadm-1.29/SCHEDULERS ipvsadm-1.31/SCHEDULERS --- ipvsadm-1.29/SCHEDULERS 2018-07-17 04:15:56.000000000 +0000 +++ ipvsadm-1.31/SCHEDULERS 2019-12-24 13:20:30.000000000 +0000 @@ -1 +1 @@ -rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq +rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq|fo|ovf|mh diff -Nru ipvsadm-1.29/VERSION ipvsadm-1.31/VERSION --- ipvsadm-1.29/VERSION 2018-07-17 04:15:56.000000000 +0000 +++ ipvsadm-1.31/VERSION 2019-12-24 13:20:30.000000000 +0000 @@ -1 +1 @@ -1.29 +1.31