Added the following two options: --gue-port with adding and editing destinations for tunneling servers. --gue with listing services. Signed-off-by: Jacky Hu <hengqing.hu@xxxxxxxxx> --- ipvsadm.c | 109 +++++++++++++++++++++++++++++++++++++--------- libipvs/ip_vs.h | 16 +++++++ libipvs/libipvs.c | 3 +- 3 files changed, 106 insertions(+), 22 deletions(-) diff --git a/ipvsadm.c b/ipvsadm.c index 0cb2b68..a3d77d1 100644 --- a/ipvsadm.c +++ b/ipvsadm.c @@ -187,7 +187,9 @@ static const char* cmdnames[] = { #define OPT_MCAST_PORT 0x02000000 #define OPT_MCAST_TTL 0x04000000 #define OPT_SYNC_MAXLEN 0x08000000 -#define NUMBER_OF_OPT 28 +#define OPT_GUE_PORT 0x10000000 +#define OPT_GUE 0x20000000 +#define NUMBER_OF_OPT 30 static const char* optnames[] = { "numeric", @@ -218,6 +220,8 @@ static const char* optnames[] = { "mcast-port", "mcast-ttl", "sync-maxlen", + "gue-port", + "gue", }; /* @@ -230,21 +234,21 @@ static const char* optnames[] = { */ static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = { - /* -n -c svc -s -p -M -r fwd -w -x -y -mc tot dmn -st -rt thr -pc srt sid -ex ops -pe -b grp port ttl size */ -/*ADD*/ {'x', 'x', '+', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', ' ', ' ', 'x', 'x', 'x', 'x'}, -/*EDIT*/ {'x', 'x', '+', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', ' ', ' ', 'x', 'x', 'x', 'x'}, -/*DEL*/ {'x', 'x', '+', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, -/*FLUSH*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, -/*LIST*/ {' ', '1', '1', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', '1', '1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, -/*ADDSRV*/ {'x', 'x', '+', 'x', 'x', 'x', '+', ' ', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, -/*DELSRV*/ {'x', 'x', '+', 'x', 'x', 'x', '+', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, -/*EDITSRV*/ {'x', 'x', '+', 'x', 'x', 'x', '+', ' ', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, -/*TIMEOUT*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, -/*STARTD*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', 'x', 'x', 'x', 'x', ' ', ' ', ' ', ' '}, -/*STOPD*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, -/*RESTORE*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, -/*SAVE*/ {' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, -/*ZERO*/ {'x', 'x', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, + /* -n -c svc -s -p -M -r fwd -w -x -y -mc tot dmn -st -rt thr -pc srt sid -ex ops -pe -b grp port ttl size gue-port gue */ +/*ADD*/ {'x', 'x', '+', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x'}, +/*EDIT*/ {'x', 'x', '+', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x'}, +/*DEL*/ {'x', 'x', '+', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, +/*FLUSH*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, +/*LIST*/ {' ', '1', '1', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', '1', '1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' '}, +/*ADDSRV*/ {'x', 'x', '+', 'x', 'x', 'x', '+', ' ', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', 'x'}, +/*DELSRV*/ {'x', 'x', '+', 'x', 'x', 'x', '+', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, +/*EDITSRV*/ {'x', 'x', '+', 'x', 'x', 'x', '+', ' ', ' ', ' ', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', 'x'}, +/*TIMEOUT*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, +/*STARTD*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', 'x', 'x', 'x', 'x', ' ', ' ', ' ', ' ', 'x', 'x'}, +/*STOPD*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, +/*RESTORE*/ {'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, +/*SAVE*/ {' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, +/*ZERO*/ {'x', 'x', ' ', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'}, }; /* printing format flags */ @@ -257,6 +261,7 @@ static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = #define FMT_PERSISTENTCONN 0x0020 #define FMT_NOSORT 0x0040 #define FMT_EXACT 0x0080 +#define FMT_GUE 0x0100 #define SERVICE_NONE 0x0000 #define SERVICE_ADDR 0x0001 @@ -300,6 +305,8 @@ enum { TAG_MCAST_PORT, TAG_MCAST_TTL, TAG_SYNC_MAXLEN, + TAG_GUE_PORT, + TAG_GUE, }; /* various parsing helpers & parsing functions */ @@ -419,6 +426,7 @@ parse_options(int argc, char **argv, struct ipvs_command_entry *ce, unsigned int *options, unsigned int *format) { int c, parse; + u_int16_t gue_port; poptContext context; char *optarg = NULL, sched_flags_arg[128]; struct poptOption options_table[] = { @@ -495,6 +503,9 @@ parse_options(int argc, char **argv, struct ipvs_command_entry *ce, TAG_MCAST_TTL, NULL, NULL }, { "sync-maxlen", '\0', POPT_ARG_STRING, &optarg, TAG_SYNC_MAXLEN, NULL, NULL }, + { "gue-port", '\0', POPT_ARG_STRING, &optarg, TAG_GUE_PORT, + NULL, NULL }, + { "gue", '\0', POPT_ARG_NONE, NULL, TAG_GUE, NULL, NULL }, { NULL, 0, 0, NULL, 0, NULL, NULL } }; @@ -773,6 +784,23 @@ parse_options(int argc, char **argv, struct ipvs_command_entry *ce, fail(2, "illegal sync-maxlen specified"); ce->daemon.sync_maxlen = parse; break; + case TAG_GUE_PORT: + set_option(options, OPT_GUE_PORT); + parse = string_to_number(optarg, 1, 65535); + if (parse == -1) + fail(2, "illegal gue port specified"); + gue_port = (u_int16_t) parse; + ce->dest.conn_flags = ( + (gue_port & 0xFFFE) << 16 | + (gue_port & 1) << 14 | + IP_VS_CONN_F_GUE | + ce->dest.conn_flags + ); + break; + case TAG_GUE: + set_option(options, OPT_GUE); + *format |= FMT_GUE; + break; default: fail(2, "invalid option `%s'", poptBadOption(context, POPT_BADOPTION_NOALIAS)); @@ -847,6 +875,7 @@ static int process_options(int argc, char **argv, int reading_stdin) struct ipvs_command_entry ce; unsigned int options = OPT_NONE; unsigned int format = FMT_NONE; + unsigned int fwd_method; int result = 0; memset(&ce, 0, sizeof(struct ipvs_command_entry)); @@ -883,6 +912,8 @@ static int process_options(int argc, char **argv, int reading_stdin) 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 +921,21 @@ static int process_options(int argc, char **argv, int reading_stdin) * 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 gue encapsulation */ + if ((options & OPT_GUE_PORT) && + fwd_method != IP_VS_CONN_F_TUNNEL) + fail(2, + "GUE encapsulation is allowed only for tunneling servers"); } switch (ce.cmd) { @@ -1301,6 +1338,7 @@ static void usage_exit(const char *program, const int exit_status) " --gatewaying -g gatewaying (direct routing) (default)\n" " --ipip -i ipip encapsulation (tunneling)\n" " --masquerading -m masquerading (NAT)\n" + " --gue-port port enable gue encapsulation with destination port\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" @@ -1312,6 +1350,7 @@ static void usage_exit(const char *program, const int exit_status) " --exact expand numbers (display exact values)\n" " --thresholds output of thresholds information\n" " --persistent-conn output of persistent connection info\n" + " --gue output of gue encapsulation info (destination port)\n" " --nosort disable sorting output of service/server entries\n" " --sort does nothing, for backwards compatibility\n" " --ops -o one-packet scheduling\n" @@ -1548,6 +1587,14 @@ static inline char *fwd_name(unsigned flags) return fwd; } +static inline u_int16_t fwd_gue_port(unsigned int flags) +{ + u_int16_t gue_port; + + gue_port = ((flags >> 16) & 0xFFFE) | ((flags >> 14) & 1); + return gue_port; +} + static inline char *fwd_switch(unsigned flags) { char *swt = NULL; @@ -1641,6 +1688,9 @@ static void print_title(unsigned int format) " -> RemoteAddress:Port\n", "Prot LocalAddress:Port", "Weight", "PersistConn", "ActiveConn", "InActConn"); + else if ((format & FMT_GUE)) + printf("Prot LocalAddress:Port Scheduler Flags\n" + " -> RemoteAddress:Port Forward GUE Weight ActiveConn InActConn\n"); else if (!(format & FMT_RULE)) printf("Prot LocalAddress:Port Scheduler Flags\n" " -> RemoteAddress:Port Forward Weight ActiveConn InActConn\n"); @@ -1778,8 +1828,20 @@ print_service_entry(ipvs_service_entry_t *se, unsigned int format) 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 (e->conn_flags & IP_VS_CONN_F_GUE) { + printf("-a %s -r %s %s -w %d --gue-port %d\n", + svc_name, + dname, + fwd_switch(e->conn_flags), + e->weight, + fwd_gue_port(e->conn_flags)); + } 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); @@ -1804,6 +1866,11 @@ print_service_entry(ipvs_service_entry_t *se, unsigned int format) printf(" -> %-28s %-9u %-11u %-10u %-10u\n", dname, e->weight, e->persistconns, e->activeconns, e->inactconns); + } else if (format & FMT_GUE) { + printf(" -> %-28s %-7s %-5d %-6d %-10u %-10u\n", + dname, fwd_name(e->conn_flags), + fwd_gue_port(e->conn_flags), + e->weight, e->activeconns, e->inactconns); } else printf(" -> %-28s %-7s %-6d %-10u %-10u\n", dname, fwd_name(e->conn_flags), diff --git a/libipvs/ip_vs.h b/libipvs/ip_vs.h index ad0141c..6c7f6ee 100644 --- a/libipvs/ip_vs.h +++ b/libipvs/ip_vs.h @@ -101,6 +101,22 @@ #define IP_VS_CONN_F_TEMPLATE 0x1000 /* template, not connection */ #define IP_VS_CONN_F_ONE_PACKET 0x2000 /* forward only one packet */ +/* tunneling with gue */ +#define IP_VS_CONN_F_GUE 0x0008 + +/* gue destination port bit 0 */ +#define IP_VS_CONN_F_GUE_PORT_LSB 0x4000 + +/* gue destination port bit 1-15 */ +#define IP_VS_CONN_F_GUE_PORT_MSB 0xFFFFE0000 + +/* Connection flags from destination that can be changed by user space */ +#define IP_VS_CONN_F_DEST_MASK (IP_VS_CONN_F_FWD_MASK | \ + IP_VS_CONN_F_GUE | \ + IP_VS_CONN_F_GUE_PORT_MSB | \ + IP_VS_CONN_F_GUE_PORT_LSB | \ + 0) + #define IP_VS_SCHEDNAME_MAXLEN 16 #define IP_VS_PENAME_MAXLEN 16 #define IP_VS_IFNAME_MAXLEN 16 diff --git a/libipvs/libipvs.c b/libipvs/libipvs.c index 9be7700..a2d0018 100644 --- a/libipvs/libipvs.c +++ b/libipvs/libipvs.c @@ -388,7 +388,8 @@ static int ipvs_nl_fill_dest_attr(struct nl_msg *msg, ipvs_dest_t *dst) NLA_PUT_U16(msg, IPVS_DEST_ATTR_ADDR_FAMILY, dst->af); NLA_PUT(msg, IPVS_DEST_ATTR_ADDR, sizeof(dst->addr), &(dst->addr)); 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_FWD_METHOD, + dst->conn_flags & IP_VS_CONN_F_DEST_MASK); NLA_PUT_U32(msg, IPVS_DEST_ATTR_WEIGHT, dst->weight); NLA_PUT_U32(msg, IPVS_DEST_ATTR_U_THRESH, dst->u_threshold); NLA_PUT_U32(msg, IPVS_DEST_ATTR_L_THRESH, dst->l_threshold); -- 2.21.0