[5/6] ip xfrm state: fixup hard/soft timeouts/limits while save

Submitted by Pavel Tikhomirov on Sept. 2, 2016, 9:02 a.m.

Details

Message ID 1472806946-16575-6-git-send-email-ptikhomirov@virtuozzo.com
State Rejected
Series "ip: add save/restore to xfrm tables"
Headers show

Commit Message

Pavel Tikhomirov Sept. 2, 2016, 9:02 a.m.
introduce "fixlimits" option of "ip xfrm state save",
if have these option we will change the limits saved to
dump file according to the real passed time/bytes/packets
since the state add-time.

For instance, we have a process in container which set
xfrm state 10sec ago with a timeout of 30sec and now we
do C/R for the whole container. As the process in question
knows nothing about C/R, after restore it might expect that
xfrm state dissappears in 30-10=20sec, so we need to set
timeout to 20. If difference is <=0 set 1 at least to do
not lose the limit completely.

Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
---
 ip/xfrm_state.c    | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 man/man8/ip-xfrm.8 | 10 ++++++-
 2 files changed, 95 insertions(+), 3 deletions(-)

Patch hide | download patch | download mbox

diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
index 56d9f22..6c55b3e 100644
--- a/ip/xfrm_state.c
+++ b/ip/xfrm_state.c
@@ -32,6 +32,7 @@ 
 #include "xfrm.h"
 #include "ip_common.h"
 #include <errno.h>
+#include <time.h>
 
 /* #define NLMSG_DELETEALL_BUF_SIZE (4096-512) */
 #define NLMSG_DELETEALL_BUF_SIZE 8192
@@ -66,7 +67,8 @@  static void usage(void)
 	fprintf(stderr, "Usage: ip xfrm state { delete | get } ID [ mark MARK [ mask MASK ] ]\n");
 	fprintf(stderr, "Usage: ip xfrm state { deleteall | list } [ ID ] [ mode MODE ] [ reqid REQID ]\n");
 	fprintf(stderr, "        [ flag FLAG-LIST ]\n");
-	fprintf(stderr, "Usage: ip xfrm state { save | restore }\n");
+	fprintf(stderr, "Usage: ip xfrm state save [ fixlimits ]\n");
+	fprintf(stderr, "Usage: ip xfrm state restore\n");
 	fprintf(stderr, "Usage: ip xfrm state flush [ proto XFRM-PROTO ]\n");
 	fprintf(stderr, "Usage: ip xfrm state count\n");
 	fprintf(stderr, "ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ]\n");
@@ -1077,10 +1079,89 @@  static int xfrm_state_keep(const struct sockaddr_nl *who,
 
 static __u32 state_dump_magic = 0x71706987;
 
+static inline void fixup_lft_limit(__u64 *lft_limit, __u64 lft_cur)
+{
+	if (lft_cur < *lft_limit)
+		/*
+		 * Limit is not yet hit, decrease it by
+		 * current lifetime
+		 */
+		*lft_limit -= lft_cur;
+	else
+		/*
+		 * Limit is already hit or almost hit, set it
+		 * to 1 to hit it imediately after restore
+		 */
+		*lft_limit = 1;
+}
+
+static int fixup_lifetime(struct xfrm_lifetime_cur *curlft, struct xfrm_lifetime_cfg *lft)
+{
+	unsigned long now;
+	__u64 time_since_add, time_since_use;
+
+	now = time(NULL);
+	if (now < 0) {
+		fprintf(stderr, "Failed to get current time\n");
+		return -1;
+	}
+	time_since_add = now - curlft->add_time;
+	time_since_use = now - (curlft->use_time ? : curlft->add_time);
+
+	/* Fixup expire timeouts */
+	if (lft->hard_add_expires_seconds)
+		fixup_lft_limit(&lft->hard_add_expires_seconds, time_since_add);
+	if (lft->hard_use_expires_seconds)
+		fixup_lft_limit(&lft->hard_use_expires_seconds, time_since_use);
+	if (lft->soft_add_expires_seconds)
+		fixup_lft_limit(&lft->soft_add_expires_seconds, time_since_add);
+	if (lft->soft_use_expires_seconds)
+		fixup_lft_limit(&lft->soft_use_expires_seconds, time_since_use);
+
+	/* Fixup expire limits */
+	if (lft->hard_byte_limit != XFRM_INF)
+		fixup_lft_limit(&lft->hard_byte_limit, curlft->bytes);
+	if (lft->hard_packet_limit != XFRM_INF)
+		fixup_lft_limit(&lft->hard_packet_limit, curlft->packets);
+	if (lft->soft_byte_limit != XFRM_INF)
+		fixup_lft_limit(&lft->soft_byte_limit, curlft->bytes);
+	if (lft->soft_packet_limit != XFRM_INF)
+		fixup_lft_limit(&lft->soft_packet_limit, curlft->packets);
+
+	return 0;
+}
+
+static int save_state(const struct sockaddr_nl *who, struct nlmsghdr *n,
+		void *arg)
+{
+	struct xfrm_usersa_info *xsinfo;
+	int len = n->nlmsg_len;
+
+	if (n->nlmsg_type != XFRM_MSG_NEWSA) {
+		fprintf(stderr, "BUG: wrong nlmsg_type: %08x\n",
+			n->nlmsg_type);
+		return -1;
+	}
+
+	xsinfo = NLMSG_DATA(n);
+	len -= NLMSG_SPACE(sizeof(*xsinfo));
+
+	if (len < 0) {
+		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+		return -1;
+	}
+
+	if (fixup_lifetime(&xsinfo->curlft, &xsinfo->lft))
+		return -1;
+
+	return save_nlmsg(who, n, arg);
+}
+
 static int xfrm_state_list_deleteall_or_save(int argc, char **argv, int deleteall, int save)
 {
 	char *idp = NULL;
 	struct rtnl_handle rth;
+	int fixlimits = 0;
 
 	if (argc > 0)
 		filter.use = 1;
@@ -1105,6 +1186,9 @@  static int xfrm_state_list_deleteall_or_save(int argc, char **argv, int deleteal
 
 			filter.state_flags_mask = XFRM_FILTER_MASK_FULL;
 
+		} else if (strcmp(*argv, "fixlimits") == 0) {
+			fixlimits = 1;
+
 		} else {
 			if (idp)
 				invarg("unknown", *argv);
@@ -1179,7 +1263,7 @@  static int xfrm_state_list_deleteall_or_save(int argc, char **argv, int deleteal
 		if (save) {
 			if (dump_write_magic(state_dump_magic))
 				return -1;
-			rtnl_filter = save_nlmsg;
+			rtnl_filter = fixlimits ? save_state : save_nlmsg;
 		}
 
 		struct xfrm_address_filter addrfilter = {
diff --git a/man/man8/ip-xfrm.8 b/man/man8/ip-xfrm.8
index f5b8290..2fd088d 100644
--- a/man/man8/ip-xfrm.8
+++ b/man/man8/ip-xfrm.8
@@ -104,7 +104,7 @@  ip-xfrm \- transform configuration
 .BR "ip xfrm state count"
 
 .ti -8
-.BR "ip xfrm state save"
+.BR "ip xfrm state save" " [ " fixlimits " ]"
 
 .ti -8
 .BR "ip xfrm state restore"
@@ -550,6 +550,14 @@  encapsulates packets with protocol
 .RI "using source port " SPORT ", destination port "  DPORT
 .RI ", and original address " OADDR "."
 
+.P
+If the
+.BI fixlimits
+option is set on save, change entry
+.I LIMITs
+saved to dump file according to the real time/bytes/packets passed
+since entry add-time.
+
 .sp
 .PP
 .TS