bool validate_ipv4_hdr(struct iphdr *hdr, u16 total_len, u16 id, u16 df, u16 mf, u16 frag_off, u8 protocol, struct tuple *tuple4) { struct in_addr addr; bool success = true; success &= assert_equals_u8(4, hdr->version, "IPv4hdr-Version"); success &= assert_equals_u8(5, hdr->ihl, "IPv4hdr-IHL"); success &= assert_equals_u8(0, hdr->tos, "IPv4hdr-TOS"); success &= assert_equals_u16(total_len, be16_to_cpu(hdr->tot_len), "IPv4hdr-total length"); success &= assert_equals_u16(id, be16_to_cpu(hdr->id), "IPv4hdr-ID"); success &= assert_equals_u16(df, be16_to_cpu(hdr->frag_off) & IP_DF, "IPv4hdr-DF"); success &= assert_equals_u16(mf, be16_to_cpu(hdr->frag_off) & IP_MF, "IPv4hdr-MF"); success &= assert_equals_u16(frag_off, get_fragment_offset_ipv4(hdr), "IPv4hdr-Frag offset"); /* success &= assert_equals_u8(, hdr->ttl, "IPv4 header - TTL"); */ success &= assert_equals_u8(protocol, hdr->protocol, "IPv4hdr-protocol"); addr.s_addr = hdr->saddr; success &= assert_equals_ipv4(&tuple4->src.addr4.l3, &addr, "IPv4hdr-src address"); addr.s_addr = hdr->daddr; success &= assert_equals_ipv4(&tuple4->dst.addr4.l3, &addr, "IPv4hdr-dst address"); return success; }
static bool test_4to6(l4_protocol l4_proto) { struct tuple incoming, outgoing; bool success = true; incoming.src.addr.ipv4 = remote_ipv4; incoming.dst.addr.ipv4 = local_ipv4; incoming.src.l4_id = 123; /* Whatever */ incoming.dst.l4_id = 80; /* Lookup will use this. */ incoming.l3_proto = L3PROTO_IPV4; incoming.l4_proto = l4_proto; if (l4_proto != L4PROTO_ICMP) { success &= assert_equals_int(VER_CONTINUE, tuple5(&incoming, &outgoing), "Function5 call"); success &= assert_equals_u16(123, outgoing.src.l4_id, "Source port"); success &= assert_equals_u16(1500, outgoing.dst.l4_id, "Destination port"); } else { success &= assert_equals_int(VER_CONTINUE, tuple3(&incoming, &outgoing), "Function3 call"); success &= assert_equals_u16(1500, outgoing.icmp_id, "ICMP ID"); } success &= assert_equals_ipv6(&local_ipv6, &outgoing.src.addr.ipv6, "Source address"); success &= assert_equals_ipv6(&remote_ipv6, &outgoing.dst.addr.ipv6, "Destination address"); success &= assert_equals_u16(L3PROTO_IPV6, outgoing.l3_proto, "Layer-3 protocol"); success &= assert_equals_u8(l4_proto, outgoing.l4_proto, "Layer-4 protocol"); return success; }
static bool test_function_icmp4_minimum_mtu(void) { bool success = true; success &= assert_equals_u16(2, be16_to_cpu(icmp4_minimum_mtu(2, 4, 6)), "First is min"); success &= assert_equals_u16(8, be16_to_cpu(icmp4_minimum_mtu(10, 8, 12)), "Second is min"); success &= assert_equals_u16(14, be16_to_cpu(icmp4_minimum_mtu(16, 18, 14)), "Third is min"); return success; }
static bool test_function_build_ipv4_frag_off_field(void) { bool success = true; success &= assert_equals_u16(0x400F, be16_to_cpu(build_ipv4_frag_off_field(1, 0, 120)), "Simple 1"); success &= assert_equals_u16(0x202B, be16_to_cpu(build_ipv4_frag_off_field(0, 1, 344)), "Simple 2"); return success; }
bool validate_frag_hdr(struct frag_hdr *hdr, u16 frag_offset, u16 mf, __u8 nexthdr) { bool success = true; success &= assert_equals_u8(nexthdr, hdr->nexthdr, "Fraghdr-nexthdr"); success &= assert_equals_u8(0, hdr->reserved, "Fraghdr-nexthdr"); success &= assert_equals_u16(frag_offset, get_fragment_offset_ipv6(hdr), "Fraghdr-frag offset"); success &= assert_equals_u16(mf, is_more_fragments_set_ipv6(hdr), "Fraghdr-MF"); success &= assert_equals_u16(4321, be32_to_cpu(hdr->identification), "Fraghdr-ID"); return success; }
bool test_allocate_ipv4_transport_address_digger( void ) { struct in_addr expected_addr; struct tuple tuple; struct ipv4_tuple_address new_ipv4_transport_address; bool success = true; bib_init(); pool4_init(true); success &= inject_bib_entry( IPPROTO_ICMP ); success &= inject_bib_entry( IPPROTO_TCP ); success &= init_tuple_for_test_ipv6(&tuple, IPPROTO_UDP); success &= str_to_addr4_verbose(IPV4_ALLOCATED_ADDR, &expected_addr); if (!success) return false; success &= assert_true( allocate_ipv4_transport_address_digger(&tuple, IPPROTO_UDP, &new_ipv4_transport_address), "Check that we can allocate a brand new IPv4 transport address for UDP."); success &= assert_true( ipv4_addr_equals(&new_ipv4_transport_address.address, &expected_addr) , "Check that the allocated IPv4 address is correct for UDP."); success &= assert_equals_u16( IPV4_ALLOCATED_PORT_DIGGER, new_ipv4_transport_address.l4_id, "Check that the allocated IPv4 port is correct for UDP."); pool4_destroy(); bib_destroy(); return success; }
static bool assert_tuple_addr(struct in_addr *expected_address, __u16 expected_port, struct ipv4_tuple_address *actual, char *test_name) { bool success = true; success &= assert_equals_ipv4(expected_address, &actual->address, test_name); success &= assert_equals_u16(expected_port, actual->l4_id, test_name); return success; }
static bool test_function_generate_ipv4_id_dofrag(void) { struct frag_hdr fragment_hdr; bool success = true; fragment_hdr.identification = 0; success &= assert_equals_u16(0, be16_to_cpu(generate_ipv4_id_dofrag(&fragment_hdr)), "Simplest id"); fragment_hdr.identification = cpu_to_be32(0x0000abcd); success &= assert_equals_u16(0xabcd, be16_to_cpu(generate_ipv4_id_dofrag(&fragment_hdr)), "No overflow"); fragment_hdr.identification = cpu_to_be32(0x12345678); success &= assert_equals_u16(0x5678, be16_to_cpu(generate_ipv4_id_dofrag(&fragment_hdr)), "Overflow"); return success; }
static bool test_function_is_more_fragments_set(void) { struct iphdr hdr; bool success = true; hdr.frag_off = cpu_to_be16(0x0000); success &= assert_equals_u16(0, is_more_fragments_set_ipv4(&hdr), "All zeroes"); hdr.frag_off = cpu_to_be16(0x2000); success &= assert_equals_u16(1, is_more_fragments_set_ipv4(&hdr), "All zeroes except MF"); hdr.frag_off = cpu_to_be16(0xFFFF); success &= assert_equals_u16(1, is_more_fragments_set_ipv4(&hdr), "All ones"); hdr.frag_off = cpu_to_be16(0xDFFF); success &= assert_equals_u16(0, is_more_fragments_set_ipv4(&hdr), "All ones except MF"); return success; }
bool validate_icmp4_hdr(struct icmphdr *hdr, u16 id, struct tuple *tuple4) { bool success = true; success &= assert_equals_u8(ICMP_ECHO, hdr->type, "ICMP4hdr-type"); success &= assert_equals_u8(0, hdr->code, "ICMP4hdr-code"); success &= assert_equals_u16(tuple4->src.addr4.l4, be16_to_cpu(hdr->un.echo.id), "ICMP4id"); return success; }
bool validate_icmp6_hdr(struct icmp6hdr *hdr, u16 id, struct tuple *tuple6) { bool success = true; success &= assert_equals_u8(ICMPV6_ECHO_REQUEST, hdr->icmp6_type, "ICMP6hdr-type"); success &= assert_equals_u8(0, hdr->icmp6_code, "ICMP6hdr-code"); success &= assert_equals_u16(tuple6->src.addr6.l4, be16_to_cpu(hdr->icmp6_identifier), "ICMP6hdr id"); return success; }
bool validate_udp_hdr(struct udphdr *hdr, u16 payload_len, struct tuple *tuple) { bool success = true; switch (tuple->l3_proto) { case L3PROTO_IPV6: success &= assert_equals_u16(tuple->src.addr6.l4, be16_to_cpu(hdr->source), "UDP6hdr-src"); success &= assert_equals_u16(tuple->dst.addr6.l4, be16_to_cpu(hdr->dest), "UDP6hdr-dst"); break; case L3PROTO_IPV4: success &= assert_equals_u16(tuple->src.addr4.l4, be16_to_cpu(hdr->source), "UDP4hdr-src"); success &= assert_equals_u16(tuple->dst.addr4.l4, be16_to_cpu(hdr->dest), "UDP4hdr-dst"); break; default: log_err("L3 proto is not IPv6 or IPv4."); success = false; } success &= assert_equals_u16(sizeof(*hdr) + payload_len, be16_to_cpu(hdr->len), "UDPhdr-len"); return success; }
static bool test_function_generate_df_flag(void) { struct ipv6hdr hdr; bool success = true; hdr.payload_len = cpu_to_be16(4); /* packet length is 44. */ success &= assert_equals_u16(1, generate_df_flag(&hdr), "Length < 88 bytes"); hdr.payload_len = cpu_to_be16(48); /* packet length is 88. */ success &= assert_equals_u16(1, generate_df_flag(&hdr), "Length = 88 bytes"); hdr.payload_len = cpu_to_be16(500); /* packet length is 540. */ success &= assert_equals_u16(0, generate_df_flag(&hdr), "88 < Len < 1280"); hdr.payload_len = cpu_to_be16(1240); /* packet length is 1280. */ success &= assert_equals_u16(0, generate_df_flag(&hdr), "Len = 1280"); hdr.payload_len = cpu_to_be16(4000); /* packet length is 4040. */ success &= assert_equals_u16(1, generate_df_flag(&hdr), "Len > 1280"); return success; }
static bool test_4to6(l4_protocol l4_proto) { struct tuple in, out; int field = 0; bool success = true; if (is_error(init_ipv4_tuple(&in, remote4, 80, local4, 5678, l4_proto))) return false; success &= assert_equals_int(VER_CONTINUE, compute_out_tuple(&in, &out, NULL), "Call"); success &= assert_equals_int(L3PROTO_IPV6, out.l3_proto, "l3 proto"); success &= assert_equals_int(l4_proto, out.l4_proto, "l4 proto"); success &= assert_equals_ipv6_str(local6, &out.src.addr6.l3, "src addr"); if (l4_proto == L4PROTO_ICMP) success &= assert_equals_u16(1234, out.src.addr6.l4, "src port (icmp id)"); else success &= assert_equals_u16(80, out.src.addr6.l4, "src port"); success &= assert_equals_ipv6_str(remote6, &out.dst.addr6.l3, "dst addr"); success &= assert_equals_u16(1234, out.dst.addr6.l4, "dst port"); success &= assert_equals_int(0, field, "unchanged field"); return success; }
bool test_transport_address_ipv4( void ) { struct in_addr addr; struct ipv4_tuple_address ta; bool success = true; if (!str_to_addr4_verbose(IPV4_TRANSPORT_ADDR, &addr)) return false; transport_address_ipv4( addr, IPV4_TRANSPORT_PORT, &ta ); success &= assert_equals_ipv4(&ta.address, &addr, "Check that the address part of an IPv4 transport address is correct."); success &= assert_equals_u16(ta.l4_id, IPV4_TRANSPORT_PORT, "Check that the port part of an IPv4 transport address is correct."); return success; }
bool validate_ipv6_hdr(struct ipv6hdr *hdr, u16 payload_len, u8 nexthdr, struct tuple *tuple6) { bool success = true; success &= assert_equals_u8(6, hdr->version, "IPv6hdr-version"); success &= assert_equals_u8(0, hdr->priority, "IPv6hdr-priority"); success &= assert_equals_u8(0, hdr->flow_lbl[0], "IPv6hdr-flow lbl[0]"); success &= assert_equals_u8(0, hdr->flow_lbl[1], "IPv6hdr-flow lbl[1]"); success &= assert_equals_u8(0, hdr->flow_lbl[2], "IPv6hdr-flow lbl[2]"); success &= assert_equals_u16(payload_len, be16_to_cpu(hdr->payload_len), "IPv6hdr-payload len"); success &= assert_equals_u8(nexthdr, hdr->nexthdr, "IPv6hdr-nexthdr"); /* success &= assert_equals_u8(, hdr->hop_limit, "IPv6hdr-hop limit"); */ success &= assert_equals_ipv6(&tuple6->src.addr6.l3, &hdr->saddr, "IPv6hdr-src address"); success &= assert_equals_ipv6(&tuple6->dst.addr6.l3, &hdr->daddr, "IPv6hdr-dst address"); return success; }
bool test_transport_address_ipv6( void ) { struct in6_addr addr6; struct ipv6_tuple_address ta; bool success = true; /* Build an IPv6 transport address from address & port */ if (!str_to_addr6_verbose(IPV6_TRANSPORT_ADDR, &addr6)) return false; transport_address_ipv6( addr6, IPV6_TRANSPORT_PORT, &ta ); success &= assert_equals_ipv6(&ta.address, &addr6 , "Check that the address part of an IPv6 transport address is correct."); success &= assert_equals_u16( ta.l4_id, IPV6_TRANSPORT_PORT , "Check that the port part of an IPv6 transport address is correct."); return success; }
bool test_allocate_ipv4_transport_address( void ) { u_int8_t protocols[] = { IPPROTO_ICMP, IPPROTO_TCP, IPPROTO_UDP }; __u16 expected_ports[] = { IPV6_ALLOCATE_PORT, IPV6_ALLOCATE_PORT, IPV6_ALLOCATE_PORT }; struct in_addr expected_addr; struct tuple tuple; struct ipv4_tuple_address new_ipv4_transport_address; bool success = true; int i; success &= pool6_init(); success &= pool4_init(true); success &= bib_init(); success &= str_to_addr4_verbose(IPV4_ALLOCATED_ADDR, &expected_addr); success &= inject_bib_entry( IPPROTO_ICMP ); success &= inject_bib_entry( IPPROTO_TCP ); success &= inject_bib_entry( IPPROTO_UDP ); if (!success) return false; for (i = 0; i < ARRAY_SIZE(protocols); i++) { init_tuple_for_test_ipv6(&tuple, protocols[i]); success &= assert_true(allocate_ipv4_transport_address(&tuple, protocols[i], &new_ipv4_transport_address), "Check that we can allocate a brand new IPv4 transport address."); success &= assert_equals_ipv4(&expected_addr , &new_ipv4_transport_address.address, "Check that the allocated IPv4 address is correct."); success &= assert_equals_u16( expected_ports[i], new_ipv4_transport_address.l4_id, "Check that the allocated IPv4 port is correct."); } bib_destroy(); pool4_destroy(); pool6_destroy(); return success; }
static bool test_4to6(bool (*function)(struct tuple *, struct tuple *), u_int8_t in_l4_protocol, u_int8_t out_l4_protocol) { struct tuple incoming, outgoing; bool success = true; incoming.src.addr.ipv4 = remote_ipv4; incoming.dst.addr.ipv4 = local_ipv4; incoming.src.l4_id = 123; // Whatever incoming.dst.l4_id = 80; // Lookup will use this. incoming.l3_proto = PF_INET; incoming.l4_proto = in_l4_protocol; success &= assert_true(function(&incoming, &outgoing), "Function call"); success &= assert_equals_ipv6(&local_ipv6, &outgoing.src.addr.ipv6, "Source address"); success &= assert_equals_ipv6(&remote_ipv6, &outgoing.dst.addr.ipv6, "Destination address"); success &= assert_equals_u16(PF_INET6, outgoing.l3_proto, "Layer-3 protocol"); success &= assert_equals_u8(out_l4_protocol, outgoing.l4_proto, "Layer-4 protocol"); // TODO (test) need to test ports? return success; }
static bool test_hairpin(l4_protocol l4_proto, skb_creator create_skb_fn) { struct sk_buff *skb_in = NULL; struct sk_buff *skb_out = NULL; struct sk_buff *skb_tmp = NULL; struct bib_entry *static_bib = NULL; struct bib_entry *dynamic_bib = NULL; struct session_entry *static_session = NULL; struct session_entry *dynamic_session = NULL; struct tuple tuple6; bool success = true; static_bib = bib_create_str(SERVER_ADDR6, SERVER_PORT6, NAT64_POOL4, SERVER_PORT6, l4_proto); dynamic_bib = bib_create_str(CLIENT_ADDR, CLIENT_PORT, NAT64_POOL4, DYNAMIC_BIB_IPV4_PORT, l4_proto); static_session = session_create_str( SERVER_ADDR6, SERVER_PORT6, SERVER_HAIRPIN_ADDR, DYNAMIC_BIB_IPV4_PORT, NAT64_POOL4, SERVER_PORT6, NAT64_POOL4, DYNAMIC_BIB_IPV4_PORT, l4_proto); dynamic_session = session_create_str(CLIENT_ADDR, CLIENT_PORT, SERVER_HAIRPIN_ADDR, SERVER_PORT6, NAT64_POOL4, DYNAMIC_BIB_IPV4_PORT, NAT64_POOL4, SERVER_PORT6, l4_proto); if (!static_bib || !dynamic_bib || !static_session || !dynamic_session) goto fail; /* Send the request. */ if (is_error(init_ipv6_tuple(&tuple6, CLIENT_ADDR, CLIENT_PORT, SERVER_HAIRPIN_ADDR, SERVER_PORT6, l4_proto))) goto fail; if (is_error(create_skb_fn(&tuple6, &skb_in, 40, 32))) goto fail; success &= send(skb_in); success &= BIB_ASSERT(l4_proto, static_bib, dynamic_bib); success &= SESSION_ASSERT(l4_proto, static_session, dynamic_session); skb_out = skb_tmp = get_sent_skb(); success &= assert_not_null(skb_out, "Request packet"); if (!success) goto fail; do { success &= assert_equals_ipv6_str(SERVER_HAIRPIN_ADDR, &ipv6_hdr(skb_tmp)->saddr, "out src"); success &= assert_equals_ipv6_str(SERVER_ADDR6, &ipv6_hdr(skb_tmp)->daddr, "out dst"); skb_tmp = skb_tmp->next; } while (skb_tmp); switch (l4_proto) { case L4PROTO_UDP: success &= assert_equals_u16(DYNAMIC_BIB_IPV4_PORT, be16_to_cpu(udp_hdr(skb_out)->source), "out's src port"); success &= assert_equals_u16(SERVER_PORT6, be16_to_cpu(udp_hdr(skb_out)->dest), "out's dst port"); break; case L4PROTO_TCP: success &= assert_equals_u16(DYNAMIC_BIB_IPV4_PORT, be16_to_cpu(tcp_hdr(skb_out)->source), "out's src port"); success &= assert_equals_u16(SERVER_PORT6, be16_to_cpu(tcp_hdr(skb_out)->dest), "out's dst port"); break; case L4PROTO_ICMP: case L4PROTO_OTHER: log_err("Test is not designed for protocol %d.", l4_proto); success = false; break; } if (!success) goto fail; kfree_skb(skb_out); /* Send the response. */ if (is_error(init_ipv6_tuple(&tuple6, SERVER_ADDR6, SERVER_PORT6, SERVER_HAIRPIN_ADDR, DYNAMIC_BIB_IPV4_PORT, l4_proto))) goto fail; if (is_error(create_skb_fn(&tuple6, &skb_in, 100, 32))) goto fail; success &= send(skb_in); /* The module should have reused the entries, so the database shouldn't have changed. */ success &= BIB_ASSERT(l4_proto, static_bib, dynamic_bib); success &= SESSION_ASSERT(l4_proto, static_session, dynamic_session); skb_out = skb_tmp = get_sent_skb(); success &= assert_not_null(skb_out, "Response packet"); if (!success) goto fail; do { success &= assert_equals_ipv6_str(SERVER_HAIRPIN_ADDR, &ipv6_hdr(skb_out)->saddr, "out src"); success &= assert_equals_ipv6_str(CLIENT_ADDR, &ipv6_hdr(skb_out)->daddr, "out dst"); skb_tmp = skb_tmp->next; } while (skb_tmp); switch (l4_proto) { case L4PROTO_UDP: success &= assert_equals_u16(SERVER_PORT6, be16_to_cpu(udp_hdr(skb_out)->source), "out's src port"); success &= assert_equals_u16(CLIENT_PORT, be16_to_cpu(udp_hdr(skb_out)->dest), "out's dst port"); break; case L4PROTO_TCP: success &= assert_equals_u16(SERVER_PORT6, be16_to_cpu(tcp_hdr(skb_out)->source), "out's src port"); success &= assert_equals_u16(CLIENT_PORT, be16_to_cpu(tcp_hdr(skb_out)->dest), "out's dst port"); break; case L4PROTO_ICMP: case L4PROTO_OTHER: log_err("Test is not designed for protocol %d.", l4_proto); success = false; break; } kfree_skb(skb_out); session_return(dynamic_session); session_return(static_session); bib_kfree(dynamic_bib); bib_kfree(static_bib); return success; fail: kfree_skb(skb_out); if (dynamic_session) session_return(dynamic_session); if (static_session) session_return(static_session); if (dynamic_bib) bib_kfree(dynamic_bib); if (static_bib) bib_kfree(static_bib); return false; }
bool validate_tcp_hdr(struct tcphdr *hdr, struct tuple *tuple) { bool success = true; switch (tuple->l3_proto) { case L3PROTO_IPV6: success &= assert_equals_u16(tuple->src.addr6.l4, be16_to_cpu(hdr->source), "TCP6hdr-src"); success &= assert_equals_u16(tuple->dst.addr6.l4, be16_to_cpu(hdr->dest), "TCP6hdr-dst"); break; case L3PROTO_IPV4: success &= assert_equals_u16(tuple->src.addr4.l4, be16_to_cpu(hdr->source), "TCP4hdr-src"); success &= assert_equals_u16(tuple->dst.addr4.l4, be16_to_cpu(hdr->dest), "TCP4hdr-dst"); break; default: log_err("L3 proto is not IPv6 or IPv4."); success = false; } success &= assert_equals_u32(4669, be32_to_cpu(hdr->seq), "TCPhdr-seq"); success &= assert_equals_u32(6576, be32_to_cpu(hdr->ack_seq), "TCPhdr-ack seq"); success &= assert_equals_u16(5, hdr->doff, "TCPhdr-data offset"); success &= assert_equals_u16(0, hdr->res1, "TCPhdr-reserved"); success &= assert_equals_u16(0, hdr->cwr, "TCPhdr-cwr"); success &= assert_equals_u16(0, hdr->ece, "TCPhdr-ece"); success &= assert_equals_u16(0, hdr->urg, "TCPhdr-urg"); success &= assert_equals_u16(0, hdr->ack, "TCPhdr-ack"); success &= assert_equals_u16(0, hdr->psh, "TCPhdr-psh"); success &= assert_equals_u16(0, hdr->rst, "TCPhdr-rst"); success &= assert_equals_u16(1, hdr->syn, "TCPhdr-syn"); success &= assert_equals_u16(0, hdr->fin, "TCPhdr-fin"); success &= assert_equals_u16(3233, be16_to_cpu(hdr->window), "TCPhdr-window"); success &= assert_equals_u16(9865, be16_to_cpu(hdr->urg_ptr), "TCPhdr-urgent ptr"); return success; }
/** * Only UDP and its lower even range of ports is tested here. */ static bool test_return_function(void) { struct ipv4_transport_addr tuple_addr; __u16 l4_id; bool success = true; int addr_ctr, port_ctr; /* Try to return the entire pool, even though we haven't borrowed anything. */ for (addr_ctr = 0; addr_ctr < ARRAY_SIZE(expected_ips); addr_ctr++) { tuple_addr.l3 = expected_ips[addr_ctr]; for (port_ctr = 0; port_ctr < 1024; port_ctr += 2) { tuple_addr.l4 = port_ctr; success &= assert_equals_int(-EINVAL, pool4_return(L4PROTO_UDP, &tuple_addr), "Returning first"); } } /* Borrow the entire pool. */ for (addr_ctr = 0; addr_ctr < ARRAY_SIZE(expected_ips); addr_ctr++) { tuple_addr.l3 = expected_ips[addr_ctr]; for (port_ctr = 2; port_ctr < 1024; port_ctr += 2) { tuple_addr.l4 = port_ctr; success &= assert_equals_int(0, pool4_get_match(L4PROTO_UDP, &tuple_addr, &l4_id), "Borrow everything-result"); success &= assert_false(ports[addr_ctr][l4_id], "Borrow everything-port"); ports[addr_ctr][l4_id] = true; } success &= assert_equals_int(-ESRCH, pool4_get_match(L4PROTO_UDP, &tuple_addr, &l4_id), "Pool should be exhausted 1"); } if (!success) return success; /* Return something from the first address. */ tuple_addr.l3 = expected_ips[0]; tuple_addr.l4 = 1000; success &= assert_equals_int(0, pool4_return(L4PROTO_UDP, &tuple_addr), "Return 0-1000 1"); if (!success) return success; /* Re-borrow it, assert it's the same one. */ success &= assert_equals_int(0, pool4_get_match(L4PROTO_UDP, &tuple_addr, &l4_id), "Borrow 0-1000"); success &= assert_equals_u16(1000, l4_id, "Confirm 0-1000"); success &= assert_equals_int(-ESRCH, pool4_get_match(L4PROTO_UDP, &tuple_addr, &l4_id), "Reborrow 0-1000"); if (!success) return success; /* Do the same to the second address. */ tuple_addr.l3 = expected_ips[1]; tuple_addr.l4 = 1000; success &= assert_equals_int(0, pool4_return(L4PROTO_UDP, &tuple_addr), "Return 1-1000"); if (!success) return success; success &= assert_equals_int(0, pool4_get_match(L4PROTO_UDP, &tuple_addr, &l4_id), "Borrow 1-1000"); success &= assert_equals_u16(1000, l4_id, "Confirm 1-1000"); success &= assert_equals_int(-ESRCH, pool4_get_match(L4PROTO_UDP, &tuple_addr, &l4_id), "Reborrow 1-1000"); if (!success) return success; /* Return some more stuff at once. */ tuple_addr.l3 = expected_ips[0]; tuple_addr.l4 = 46; success &= assert_equals_int(0, pool4_return(L4PROTO_UDP, &tuple_addr), "Return 0-46"); tuple_addr.l4 = 1000; success &= assert_equals_int(0, pool4_return(L4PROTO_UDP, &tuple_addr), "Return 0-1000 2"); tuple_addr.l3 = expected_ips[1]; tuple_addr.l4 = 0; success &= assert_equals_int(0, pool4_return(L4PROTO_UDP, &tuple_addr), "Return 1-0"); if (!success) return success; /* Reborrow it. */ tuple_addr.l3 = expected_ips[0]; tuple_addr.l4 = 24; success &= assert_equals_int(0, pool4_get_match(L4PROTO_UDP, &tuple_addr, &l4_id), "Borrow 0-24"); success &= assert_true(l4_id == 46 || l4_id == 1000, "Confirm 0-24"); tuple_addr.l4 = 100; success &= assert_equals_int(0, pool4_get_match(L4PROTO_UDP, &tuple_addr, &l4_id), "Borrow 1-100"); success &= assert_true(l4_id == 46 || l4_id == 1000, "Confirm 1-100"); tuple_addr.l3 = expected_ips[1]; tuple_addr.l4 = 56; success &= assert_equals_int(0, pool4_get_match(L4PROTO_UDP, &tuple_addr, &l4_id), "Reborrow 2-56"); success &= assert_equals_u16(0, l4_id, "Confirm 2-56"); success &= assert_equals_int(-ESRCH, pool4_get_match(L4PROTO_UDP, &tuple_addr, &l4_id), "Pool should be exhausted 2"); if (!success) return success; /* Now return everything. */ for (addr_ctr = 0; addr_ctr < ARRAY_SIZE(expected_ips); addr_ctr++) { tuple_addr.l3 = expected_ips[addr_ctr]; for (port_ctr = 2; port_ctr < 1024; port_ctr += 2) { tuple_addr.l4 = port_ctr; success &= assert_equals_int(0, pool4_return(L4PROTO_UDP, &tuple_addr), "Returning everything"); } } success &= assert_equals_int(-EINVAL, pool4_return(L4PROTO_UDP, &tuple_addr), "Return fail"); return success; }