Index: head/tests/sys/net/routing/rtsock_common.h =================================================================== --- head/tests/sys/net/routing/rtsock_common.h +++ head/tests/sys/net/routing/rtsock_common.h @@ -71,6 +71,8 @@ void rtsock_validate_message(char *buffer, ssize_t len); void rtsock_add_rtm_sa(struct rt_msghdr *rtm, int addr_type, struct sockaddr *sa); +void file_append_line(char *fname, char *text); + static int _rtm_seq = 42; @@ -151,34 +153,43 @@ return (1); } -static int -iface_create_cloned(char *ifname_ptr) +static char * +iface_create(char *ifname_orig) { struct ifreq ifr; int s; - char prefix[IFNAMSIZ]; + char prefix[IFNAMSIZ], ifname[IFNAMSIZ], *result; char *src, *dst; - for (src = ifname_ptr, dst = prefix; *src && isalpha(*src); src++) + for (src = ifname_orig, dst = prefix; *src && isalpha(*src); src++) *dst++ = *src; *dst = '\0'; if (_enforce_cloner_loaded(prefix) == 0) - return (0); + return (NULL); memset(&ifr, 0, sizeof(struct ifreq)); s = socket(AF_LOCAL, SOCK_DGRAM, 0); - strlcpy(ifr.ifr_name, ifname_ptr, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, ifname_orig, sizeof(ifr.ifr_name)); RLOG("creating iface %s %s", prefix, ifr.ifr_name); if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) err(1, "SIOCIFCREATE2"); - strlcpy(ifname_ptr, ifr.ifr_name, IFNAMSIZ); - RLOG("created interface %s", ifname_ptr); + strlcpy(ifname, ifr.ifr_name, IFNAMSIZ); + RLOG("created interface %s", ifname); - return (1); + result = strdup(ifname); + + file_append_line(IFACES_FNAME, ifname); + if (strstr(ifname, "epair") == ifname) { + /* call returned epairXXXa, need to add epairXXXb */ + ifname[strlen(ifname) - 1] = 'b'; + file_append_line(IFACES_FNAME, ifname); + } + + return (result); } static int @@ -357,16 +368,19 @@ } void -vnet_switch(char *vnet_name, char *ifname) +vnet_switch(char *vnet_name, char **ifnames, int count) { char buf[512], cmd[512], *line; FILE *fp; - int jid, ret; + int jid, len, ret; - RLOG("switching to vnet %s with interface %s", vnet_name, ifname); - snprintf(cmd, sizeof(cmd), - "/usr/sbin/jail -i -c name=%s persist vnet vnet.interface=%s", - vnet_name, ifname); + RLOG("switching to vnet %s with interface(s) %s", vnet_name, ifnames[0]); + len = snprintf(cmd, sizeof(cmd), + "/usr/sbin/jail -i -c name=%s persist vnet", vnet_name); + for (int i = 0; i < count && len < sizeof(cmd); i++) { + len += snprintf(&cmd[len], sizeof(cmd) - len, + " vnet.interface=%s", ifnames[i]); + } RLOG("jail cmd: \"%s\"\n", cmd); fp = popen(cmd, "r"); @@ -384,8 +398,11 @@ file_append_line(JAILS_FNAME, vnet_name); /* Wait while interface appearsh inside vnet */ - if (!vnet_wait_interface(vnet_name, ifname)) { - atf_tc_fail("unable to move interface %s to jail %s", ifname, vnet_name); + for (int i = 0; i < count; i++) { + if (vnet_wait_interface(vnet_name, ifnames[i])) + continue; + atf_tc_fail("unable to move interface %s to jail %s", + ifnames[i], vnet_name); } if (jail_attach(jid) == -1) { @@ -396,7 +413,16 @@ RLOG("attached to the jail"); } +void +vnet_switch_one(char *vnet_name, char *ifname) +{ + char *ifnames[1]; + ifnames[0] = ifname; + vnet_switch(vnet_name, ifnames, 1); +} + + #define SA_F_IGNORE_IFNAME 0x01 #define SA_F_IGNORE_IFTYPE 0x02 #define SA_F_IGNORE_MEMCMP 0x04 @@ -699,15 +725,19 @@ rtsock_read_rtm_reply(int fd, char *buffer, size_t buflen, int seq) { struct rt_msghdr *rtm; + int found = 0; while (true) { rtm = rtsock_read_rtm(fd, buffer, buflen); - if (rtm->rtm_pid != getpid()) - continue; - if (rtm->rtm_seq != seq) - continue; - - return (rtm); + if (rtm->rtm_pid == getpid() && rtm->rtm_seq == seq) + found = 1; + if (found) + RLOG("--- MATCHED RTSOCK MESSAGE ---"); + else + RLOG("--- SKIPPED RTSOCK MESSAGE ---"); + rtsock_print_rtm(rtm); + if (found) + return (rtm); } /* NOTREACHED */ Index: head/tests/sys/net/routing/rtsock_config.h =================================================================== --- head/tests/sys/net/routing/rtsock_config.h +++ head/tests/sys/net/routing/rtsock_config.h @@ -32,6 +32,10 @@ #include "params.h" +struct rtsock_config_options { + int num_interfaces; /* number of interfaces to create */ +}; + struct rtsock_test_config { int ifindex; char net4_str[INET_ADDRSTRLEN]; @@ -48,31 +52,30 @@ int plen6; char *remote_lladdr; char *ifname; + char **ifnames; bool autocreated_interface; int rtsock_fd; + int num_interfaces; }; struct rtsock_test_config * -config_setup_base(const atf_tc_t *tc) +config_setup(const atf_tc_t *tc, struct rtsock_config_options *co) { + struct rtsock_config_options default_co; struct rtsock_test_config *c; - - c = calloc(1, sizeof(struct rtsock_test_config)); - c->rtsock_fd = -1; - - return c; -} - -struct rtsock_test_config * -config_setup(const atf_tc_t *tc) -{ - struct rtsock_test_config *c; char buf[64], *s; const char *key; int mask; - c = config_setup_base(tc); + if (co == NULL) { + bzero(&default_co, sizeof(default_co)); + co = &default_co; + co->num_interfaces = 1; + } + c = calloc(1, sizeof(struct rtsock_test_config)); + c->rtsock_fd = -1; + key = atf_tc_get_config_var_wd(tc, "rtsock.v4prefix", "192.0.2.0/24"); strlcpy(buf, key, sizeof(buf)); if ((s = strchr(buf, '/')) == NULL) @@ -123,27 +126,17 @@ inet_ntop(AF_INET6, &c->net6.sin6_addr, c->net6_str, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, &c->addr6.sin6_addr, c->addr6_str, INET6_ADDRSTRLEN); - c->ifname = strdup("epair"); - c->autocreated_interface = true; + if (co->num_interfaces > 0) { + c->ifnames = calloc(co->num_interfaces, sizeof(char *)); + for (int i = 0; i < co->num_interfaces; i++) + c->ifnames[i] = iface_create("epair"); - if (c->autocreated_interface && (if_nametoindex(c->ifname) == 0)) - { - /* create our own interface */ - char new_ifname[IFNAMSIZ]; - strlcpy(new_ifname, c->ifname, sizeof(new_ifname)); - int ret = iface_create_cloned(new_ifname); - ATF_REQUIRE_MSG(ret != 0, "%s interface creation failed: %s", new_ifname, - strerror(errno)); - c->ifname = strdup(new_ifname); - file_append_line(IFACES_FNAME, new_ifname); - if (strstr(new_ifname, "epair") == new_ifname) { - /* call returned epairXXXa, need to add epairXXXb */ - new_ifname[strlen(new_ifname) - 1] = 'b'; - file_append_line(IFACES_FNAME, new_ifname); - } + c->ifname = c->ifnames[0]; + c->ifindex = if_nametoindex(c->ifname); + ATF_REQUIRE_MSG(c->ifindex != 0, "interface %s not found", + c->ifname); } - c->ifindex = if_nametoindex(c->ifname); - ATF_REQUIRE_MSG(c->ifindex != 0, "inteface %s not found", c->ifname); + c->num_interfaces = co->num_interfaces; c->remote_lladdr = strdup(atf_tc_get_config_var_wd(tc, "rtsock.remote_lladdr", "00:00:5E:00:53:42")); Index: head/tests/sys/net/routing/test_rtsock_l3.c =================================================================== --- head/tests/sys/net/routing/test_rtsock_l3.c +++ head/tests/sys/net/routing/test_rtsock_l3.c @@ -43,7 +43,7 @@ snprintf(vnet_name, sizeof(vnet_name), "vt-%s", atf_tc_get_ident(tc)); RLOG("jumping to %s", vnet_name); - vnet_switch(vnet_name, c->ifname); + vnet_switch(vnet_name, c->ifnames, c->num_interfaces); /* Update ifindex cache */ c->ifindex = if_nametoindex(c->ifname); @@ -55,7 +55,7 @@ struct rtsock_test_config *c; int ret; - c = config_setup(tc); + c = config_setup(tc, NULL); jump_vnet(c, tc); @@ -89,7 +89,7 @@ struct rtsock_test_config *c; int ret; - c = config_setup(tc); + c = config_setup(tc, NULL); jump_vnet(c, tc); @@ -353,8 +353,12 @@ ATF_TC_BODY(rtm_get_v4_empty_dst_failure, tc) { DECLARE_TEST_VARS; + struct rtsock_config_options co; - c = config_setup_base(tc); + bzero(&co, sizeof(co)); + co.num_interfaces = 0; + + c = config_setup(tc,&co); c->rtsock_fd = rtsock_setup_socket(); rtsock_prepare_route_message(rtm, RTM_GET, NULL, @@ -486,6 +490,133 @@ CLEANUP_AFTER_TEST; } +RTM_DECLARE_ROOT_TEST(rtm_change_v4_gw_success, + "Tests IPv4 gateway change"); + +ATF_TC_BODY(rtm_change_v4_gw_success, tc) +{ + DECLARE_TEST_VARS; + struct rtsock_config_options co; + + bzero(&co, sizeof(co)); + co.num_interfaces = 2; + + c = config_setup(tc, &co); + jump_vnet(c, tc); + + ret = iface_turn_up(c->ifnames[0]); + ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifnames[0]); + ret = iface_turn_up(c->ifnames[1]); + ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifnames[1]); + + ret = iface_setup_addr(c->ifnames[0], c->addr4_str, c->plen4); + ATF_REQUIRE_MSG(ret == 0, "ifconfig failed"); + + /* Use 198.51.100.0/24 "TEST-NET-2" for the second interface */ + ret = iface_setup_addr(c->ifnames[1], "198.51.100.1", 24); + ATF_REQUIRE_MSG(ret == 0, "ifconfig failed"); + + c->rtsock_fd = rtsock_setup_socket(); + + /* Create IPv4 subnetwork with smaller prefix */ + struct sockaddr_in mask4; + struct sockaddr_in net4; + struct sockaddr_in gw4; + prepare_v4_network(c, &net4, &mask4, &gw4); + + prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4, + (struct sockaddr *)&mask4, (struct sockaddr *)&gw4); + + rtsock_send_rtm(c->rtsock_fd, rtm); + rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq); + + verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4, + (struct sockaddr *)&mask4, (struct sockaddr *)&gw4); + + /* Change gateway to the one on desiding on the other interface */ + inet_pton(AF_INET, "198.51.100.2", &gw4.sin_addr.s_addr); + prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4, + (struct sockaddr *)&mask4, (struct sockaddr *)&gw4); + rtsock_send_rtm(c->rtsock_fd, rtm); + + rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq); + + verify_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4, + (struct sockaddr *)&mask4, (struct sockaddr *)&gw4); + + verify_route_message_extra(rtm, if_nametoindex(c->ifnames[1]), + RTF_DONE | RTF_GATEWAY | RTF_STATIC); + + /* Verify the change has actually taken place */ + prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net4, + (struct sockaddr *)&mask4, NULL); + + rtsock_send_rtm(c->rtsock_fd, rtm); + + /* + * RTM_GET: len 200, pid: 3894, seq 44, errno 0, flags: + * sockaddrs: 0x7 + * af=inet len=16 addr=192.0.2.0 hd={x10, x02, x00{2}, xC0, x00, x02, x00{9}} + * af=inet len=16 addr=198.51.100.2 hd={x10, x02, x00{2}, xC6, x33, x64, x02, x00{8}} + * af=inet len=16 addr=255.255.255.128 hd={x10, x02, xFF, xFF, xFF, xFF, xFF, x80, x00{8}} + */ + + rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq); + verify_route_message_extra(rtm, if_nametoindex(c->ifnames[1]), + RTF_UP | RTF_DONE | RTF_GATEWAY | RTF_STATIC); + +} + +RTM_DECLARE_ROOT_TEST(rtm_change_v4_mtu_success, + "Tests IPv4 path mtu change"); + +ATF_TC_BODY(rtm_change_v4_mtu_success, tc) +{ + DECLARE_TEST_VARS; + + unsigned long test_mtu = 1442; + + c = presetup_ipv4(tc); + + /* Create IPv4 subnetwork with smaller prefix */ + struct sockaddr_in mask4; + struct sockaddr_in net4; + struct sockaddr_in gw4; + prepare_v4_network(c, &net4, &mask4, &gw4); + + prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4, + (struct sockaddr *)&mask4, (struct sockaddr *)&gw4); + + rtsock_send_rtm(c->rtsock_fd, rtm); + rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq); + + /* Change MTU */ + prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4, + (struct sockaddr *)&mask4, NULL); + rtm->rtm_inits |= RTV_MTU; + rtm->rtm_rmx.rmx_mtu = test_mtu; + + rtsock_send_rtm(c->rtsock_fd, rtm); + rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq); + + verify_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net4, + (struct sockaddr *)&mask4, NULL); + + RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_rmx.rmx_mtu == test_mtu, + "expected mtu: %lu, got %lu", test_mtu, rtm->rtm_rmx.rmx_mtu); + + /* Verify the change has actually taken place */ + prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net4, + (struct sockaddr *)&mask4, NULL); + + rtsock_send_rtm(c->rtsock_fd, rtm); + rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq); + + RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_rmx.rmx_mtu == test_mtu, + "expected mtu: %lu, got %lu", test_mtu, rtm->rtm_rmx.rmx_mtu); +} + + ATF_TC_WITH_CLEANUP(rtm_add_v6_gu_gw_gu_direct_success); ATF_TC_HEAD(rtm_add_v6_gu_gw_gu_direct_success, tc) { @@ -578,6 +709,136 @@ CLEANUP_AFTER_TEST; } +RTM_DECLARE_ROOT_TEST(rtm_change_v6_gw_success, + "Tests IPv6 gateway change"); + +ATF_TC_BODY(rtm_change_v6_gw_success, tc) +{ + DECLARE_TEST_VARS; + struct rtsock_config_options co; + + bzero(&co, sizeof(co)); + co.num_interfaces = 2; + + c = config_setup(tc, &co); + jump_vnet(c, tc); + + ret = iface_turn_up(c->ifnames[0]); + ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifnames[0]); + ret = iface_turn_up(c->ifnames[1]); + ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifnames[1]); + + ret = iface_enable_ipv6(c->ifnames[0]); + ATF_REQUIRE_MSG(ret == 0, "Unable to enable IPv6 on %s", c->ifnames[0]); + ret = iface_enable_ipv6(c->ifnames[1]); + ATF_REQUIRE_MSG(ret == 0, "Unable to enable IPv6 on %s", c->ifnames[1]); + + ret = iface_setup_addr(c->ifnames[0], c->addr6_str, c->plen6); + ATF_REQUIRE_MSG(ret == 0, "ifconfig failed"); + + ret = iface_setup_addr(c->ifnames[1], "2001:DB8:4242::1", 64); + ATF_REQUIRE_MSG(ret == 0, "ifconfig failed"); + + c->rtsock_fd = rtsock_setup_socket(); + + /* Create IPv6 subnetwork with smaller prefix */ + struct sockaddr_in6 mask6; + struct sockaddr_in6 net6; + struct sockaddr_in6 gw6; + prepare_v6_network(c, &net6, &mask6, &gw6); + + prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6, + (struct sockaddr *)&mask6, (struct sockaddr *)&gw6); + + rtsock_send_rtm(c->rtsock_fd, rtm); + rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq); + + verify_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6, + (struct sockaddr *)&mask6, (struct sockaddr *)&gw6); + + /* Change gateway to the one on residing on the other interface */ + inet_pton(AF_INET6, "2001:DB8:4242::4242", &gw6.sin6_addr); + prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6, + (struct sockaddr *)&mask6, (struct sockaddr *)&gw6); + rtsock_send_rtm(c->rtsock_fd, rtm); + + rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq); + + verify_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6, + (struct sockaddr *)&mask6, (struct sockaddr *)&gw6); + + verify_route_message_extra(rtm, if_nametoindex(c->ifnames[1]), + RTF_DONE | RTF_GATEWAY | RTF_STATIC); + + /* Verify the change has actually taken place */ + prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net6, + (struct sockaddr *)&mask6, NULL); + + rtsock_send_rtm(c->rtsock_fd, rtm); + + /* + * RTM_GET: len 248, pid: 2268, seq 44, errno 0, flags: + * sockaddrs: 0x7 + * af=inet6 len=28 addr=2001:db8:: hd={x1C, x1C, x00{6}, x20, x01, x0D, xB8, x00{16}} + * af=inet6 len=28 addr=2001:db8:4242::4242 hd={x1C, x1C, x00{6}, x20, x01, x0D, xB8, x42, x42, x00{8}, x42, x42, x00{4}} + * af=inet6 len=28 addr=ffff:ffff:8000:: hd={x1C, x1C, xFF, xFF, xFF, xFF, xFF, xFF, xFF, xFF, xFF, xFF, x80, x00{15}} + */ + + rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq); + verify_route_message_extra(rtm, if_nametoindex(c->ifnames[1]), + RTF_UP | RTF_DONE | RTF_GATEWAY | RTF_STATIC); +} + +RTM_DECLARE_ROOT_TEST(rtm_change_v6_mtu_success, + "Tests IPv6 path mtu change"); + +ATF_TC_BODY(rtm_change_v6_mtu_success, tc) +{ + DECLARE_TEST_VARS; + + unsigned long test_mtu = 1442; + + c = presetup_ipv6(tc); + + /* Create IPv6 subnetwork with smaller prefix */ + struct sockaddr_in6 mask6; + struct sockaddr_in6 net6; + struct sockaddr_in6 gw6; + prepare_v6_network(c, &net6, &mask6, &gw6); + + prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6, + (struct sockaddr *)&mask6, (struct sockaddr *)&gw6); + + /* Send route add */ + rtsock_send_rtm(c->rtsock_fd, rtm); + rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq); + + /* Change MTU */ + prepare_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6, + (struct sockaddr *)&mask6, NULL); + rtm->rtm_inits |= RTV_MTU; + rtm->rtm_rmx.rmx_mtu = test_mtu; + + rtsock_send_rtm(c->rtsock_fd, rtm); + rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq); + + verify_route_message(rtm, RTM_CHANGE, (struct sockaddr *)&net6, + (struct sockaddr *)&mask6, NULL); + + RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_rmx.rmx_mtu == test_mtu, + "expected mtu: %lu, got %lu", test_mtu, rtm->rtm_rmx.rmx_mtu); + + /* Verify the change has actually taken place */ + prepare_route_message(rtm, RTM_GET, (struct sockaddr *)&net6, + (struct sockaddr *)&mask6, NULL); + + rtsock_send_rtm(c->rtsock_fd, rtm); + rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq); + + RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_rmx.rmx_mtu == test_mtu, + "expected mtu: %lu, got %lu", test_mtu, rtm->rtm_rmx.rmx_mtu); +} + ATF_TC_WITH_CLEANUP(rtm_add_v4_temporal1_success); ATF_TC_HEAD(rtm_add_v4_temporal1_success, tc) { @@ -1012,6 +1273,10 @@ ATF_TP_ADD_TC(tp, rtm_del_v4_prefix_nogw_success); ATF_TP_ADD_TC(tp, rtm_add_v6_gu_gw_gu_direct_success); ATF_TP_ADD_TC(tp, rtm_del_v6_gu_prefix_nogw_success); + ATF_TP_ADD_TC(tp, rtm_change_v4_gw_success); + ATF_TP_ADD_TC(tp, rtm_change_v4_mtu_success); + ATF_TP_ADD_TC(tp, rtm_change_v6_gw_success); + ATF_TP_ADD_TC(tp, rtm_change_v6_mtu_success); /* ifaddr tests */ ATF_TP_ADD_TC(tp, rtm_add_v6_gu_ifa_hostroute_success); ATF_TP_ADD_TC(tp, rtm_add_v6_gu_ifa_prefixroute_success); Index: head/tests/sys/net/routing/test_rtsock_lladdr.c =================================================================== --- head/tests/sys/net/routing/test_rtsock_lladdr.c +++ head/tests/sys/net/routing/test_rtsock_lladdr.c @@ -38,7 +38,7 @@ snprintf(vnet_name, sizeof(vnet_name), "vt-%s", atf_tc_get_ident(tc)); RLOG("jumping to %s", vnet_name); - vnet_switch(vnet_name, c->ifname); + vnet_switch_one(vnet_name, c->ifname); /* Update ifindex cache */ c->ifindex = if_nametoindex(c->ifname); @@ -50,7 +50,7 @@ struct rtsock_test_config *c; int ret; - c = config_setup(tc); + c = config_setup(tc, NULL); jump_vnet(c, tc); @@ -70,7 +70,7 @@ struct rtsock_test_config *c; int ret; - c = config_setup(tc); + c = config_setup(tc, NULL); jump_vnet(c, tc);