On Fri, 31 Jan 2025 20:39:33 +0100 Stefano Brivio <sbrivio(a)redhat.com> wrote:What clearly needs changes:Maybe something less elegant but actually functional like: --- static int migrate_data_v1(int fd, struct ctx *c, bool target) { struct iovec context[] { /* All these need to be network endian */ c->hash_secret, sizeof(c->hash_secret), c->ipv4.addr_seen, sizeof(c->ipv4.addr_seen), c->ipv6.addr_seen, sizeof(c->ipv6.addr_seen), c->ipv6.addr_ll_seen, sizeof(c->ipv6.addr_ll_seen), /* Leave NDP's next_ra alone, start from 0 */ &log_written /* Drop static */ sizeof(log_written), }; int rc; if (target) rc = read_remainder(fd, context, ARRAY_SIZE(context), 0); else rc = write_remainder(fd, context, ARRAY_SIZE(context), 0); if (rc) return errno; if (target) return flow_migrate_data_target_v1(fd, c); return flow_migrate_data_source_v1(fd, c); } --- and: --- struct tcp_flow_transfer_v1 { struct flow_common f; uint8_t retrans; uint16_t ws_from_tap; /* All BE */ uint16_t ws_to_tap; uint16_t tap_mss; ... } __attribute__((packed)); union flow_transfer_v1 { struct tcp_flow_transfer_v1 tcp; ... }; int flow_migrate_data_source_v1(int fd, struct ctx *c) { for_each_active_flow(flowtab) { union flow_transfer_v1 d; switch (flow->f.type) { case FLOW_TCP: d.tcp.f = flow->f; d.tcp.retrans = flow->tcp.retrans; d.tcp.ws_from_tap = htons(d.tcp.ws_from_tap); ...; /* Fetch window stuff, socket must be in repair mode */ send(...); } int flow_migrate_data_target_v1(int fd, struct ctx *c) { ... } And I'm not sure about "[PATCH 0/2] Fancier version handling for migration": perhaps we could switch to something radically easier from the beginning. I mean, as we have to drop the declarative approach altogether, at least let's minimise LoCs... -- Stefano