/** * The return function cannot be tested on its own, so here's also the rest of the get_any test. * * Purpose is to test get returns address/ports in the expected order, given different combinations * of return calls. * We only use the lower even range of ports, since the rest was tested during * test_get_any_function(). */ static bool test_return_function(void) { bool success = true; int i; memset(&results1, 0, sizeof(results1)); memset(&results2, 0, sizeof(results2)); // Borrow the entire first address. for (i = 0; i < 1024; i += 2) { success &= assert_true(pool4_get_any(IPPROTO_UDP, i, &results1[i]), "Borrow Addr1-res"); success &= assert_tuple_addr(&expected_ips[0], i, &results1[i], "Borrow Addr1-out"); } // Borrow the first port of the second address. success &= assert_true(pool4_get_any(IPPROTO_UDP, 0, &results2[0]), "Borrow Addr2-res-port0"); success &= assert_tuple_addr(&expected_ips[1], 0, &results2[0], "Borrow Addr2-out-port0"); // Return the last one. success &= assert_true(pool4_return(IPPROTO_UDP, &results2[0]), "Return Addr2-port0"); if (!success) return success; // Reborrow it. success &= assert_true(pool4_get_any(IPPROTO_UDP, 0, &results2[0]), "Reborrow Addr2-res-port0"); success &= assert_tuple_addr(&expected_ips[1], 0, &results2[0], "Reborrow Addr2-out-port0"); if (!success) return success; // Return some more stuff. success &= assert_true(pool4_return(IPPROTO_UDP, &results1[46]), "Return Addr1-port46"); success &= assert_true(pool4_return(IPPROTO_UDP, &results1[1000]), "Return Addr1-port1000"); success &= assert_true(pool4_return(IPPROTO_UDP, &results2[0]), "ReReturn Addr2-port0"); if (!success) return success; // Reborrow it. success &= assert_true(pool4_get_any(IPPROTO_UDP, 24, &results1[46]), "Reborrow Addr1-res-port46"); success &= assert_true(pool4_get_any(IPPROTO_UDP, 1010, &results1[1000]), "Reborrow Addr1-res-port1000"); success &= assert_true(pool4_get_any(IPPROTO_UDP, 56, &results2[0]), "ReReborrow Addr2-res-port0"); success &= assert_tuple_addr(&expected_ips[0], 46, &results1[46], "Reborrow Addr1-out-port46"); success &= assert_tuple_addr(&expected_ips[0], 1000, &results1[1000], "Reborrow Addr1-out-port1000"); success &= assert_tuple_addr(&expected_ips[1], 0, &results2[0], "ReReborrow Addr2-out-port0"); return success; }
int add_static_route(struct request_bib *req) { struct bib_entry *bib = NULL; int error; error = pool4_get(req->l4_proto, &req->add.addr4); if (error) { log_err("The IPv4 address and port could not be reserved from the pool. " "Maybe the IPv4 address you provided does not belong to the pool. " "Or maybe they're being used by some other BIB entry?"); return error; } bib = bib_create(&req->add.addr4, &req->add.addr6, true, req->l4_proto); if (!bib) { log_err("Could not allocate the BIB entry."); error = -ENOMEM; goto bib_error; } error = bibdb_add(bib); if (error) { log_err("The BIB entry could not be added to the database. Maybe an entry with the " "same IPv4 and/or IPv6 transport address already exists?"); bib_kfree(bib); goto bib_error; } /* * We do not call bib_return(bib) here, because we want the entry to hold a fake user so the * timer doesn't delete it. */ return 0; bib_error: pool4_return(req->l4_proto, &req->add.addr4); return error; }
/** * Only UDP and its lower even range of ports is tested here. */ static bool test_return_function(void) { struct ipv4_tuple_address query, result; 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++) { result.address = expected_ips[addr_ctr]; for (port_ctr = 0; port_ctr < 1024; port_ctr += 2) { result.l4_id = port_ctr; success &= assert_false(pool4_return(IPPROTO_UDP, &result), ""); } } /* Borrow the entire pool. */ for (addr_ctr = 0; addr_ctr < ARRAY_SIZE(expected_ips); addr_ctr++) { for (port_ctr = 0; port_ctr < 1024; port_ctr += 2) { success &= assert_true(pool4_get_any(IPPROTO_UDP, port_ctr, &result), "Borrow-result"); success &= assert_equals_ipv4(&expected_ips[addr_ctr], &result.address, "Borrow-addr"); success &= assert_false(ports[addr_ctr][result.l4_id], "Borrow-port"); ports[addr_ctr][result.l4_id] = true; } } success &= assert_false(pool4_get_any(IPPROTO_UDP, 0, &result), "Pool should be exhausted."); if (!success) return success; /* Return something from the first address. */ result.address = expected_ips[0]; result.l4_id = 1000; success &= assert_true(pool4_return(IPPROTO_UDP, &result), "Return"); ports[0][result.l4_id] = false; if (!success) return success; /* Re-borrow it, assert it's the same one. */ success &= assert_true(pool4_get_any(IPPROTO_UDP, 0, &result), ""); success &= assert_equals_ipv4(&expected_ips[0], &result.address, ""); success &= assert_false(ports[0][result.l4_id], ""); ports[0][result.l4_id] = true; success &= assert_false(pool4_get_any(IPPROTO_UDP, 0, &result), ""); if (!success) return success; /* * Do the same to the second address. Use get_similar() instead of get_any() to add some quick * noise. */ result.address = expected_ips[1]; result.l4_id = 1000; success &= assert_true(pool4_return(IPPROTO_UDP, &result), "Return"); ports[1][result.l4_id] = false; if (!success) return success; query.address = expected_ips[1]; query.l4_id = 0; success &= assert_true(pool4_get_similar(IPPROTO_UDP, &query, &result), ""); success &= assert_equals_ipv4(&expected_ips[1], &result.address, ""); success &= assert_false(ports[1][result.l4_id], ""); ports[1][result.l4_id] = true; success &= assert_false(pool4_get_similar(IPPROTO_UDP, &query, &result), ""); if (!success) return success; /* Return some more stuff at once. */ result.address = expected_ips[0]; result.l4_id = 46; success &= assert_true(pool4_return(IPPROTO_UDP, &result), "Return Addr1-port46"); ports[0][46] = false; result.l4_id = 1000; success &= assert_true(pool4_return(IPPROTO_UDP, &result), "Return Addr1-port1000"); ports[0][1000] = false; result.address = expected_ips[1]; result.l4_id = 0; success &= assert_true(pool4_return(IPPROTO_UDP, &result), "ReReturn Addr2-port0"); ports[1][0] = false; if (!success) return success; /* Reborrow it. */ success &= assert_true(pool4_get_any(IPPROTO_UDP, 24, &result), "Reborrow Addr1-res-port24"); success &= assert_equals_ipv4(&expected_ips[0], &result.address, ""); success &= assert_false(ports[0][result.l4_id], ""); ports[0][result.l4_id] = true; query.address = expected_ips[0]; query.l4_id = 100; success &= assert_true(pool4_get_similar(IPPROTO_UDP, &query, &result), "Reborrow Addr1-res-port100"); success &= assert_equals_ipv4(&expected_ips[0], &result.address, ""); success &= assert_false(ports[0][result.l4_id], ""); ports[0][result.l4_id] = true; success &= assert_true(pool4_get_any(IPPROTO_UDP, 56, &result), "ReReborrow Addr2-res-port56"); success &= assert_equals_ipv4(&expected_ips[1], &result.address, ""); success &= assert_false(ports[1][result.l4_id], ""); ports[1][result.l4_id] = true; success &= assert_false(pool4_get_any(IPPROTO_UDP, 12, &result), ""); if (!success) return success; /* Now return everything. */ for (addr_ctr = 0; addr_ctr < ARRAY_SIZE(expected_ips); addr_ctr++) { result.address = expected_ips[addr_ctr]; for (port_ctr = 0; port_ctr < 1024; port_ctr += 2) { result.l4_id = port_ctr; success &= assert_true(pool4_return(IPPROTO_UDP, &result), ""); ports[addr_ctr][port_ctr] = false; } } success &= assert_false(pool4_return(IPPROTO_UDP, &result), ""); 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; }
static bool test_get_similar_function(void) { struct ipv4_tuple_address query; struct ipv4_tuple_address null_result; bool success = true; int i; memset(&results1, 0, sizeof(results1)); memset(&results2, 0, sizeof(results2)); // Borrow the entire first address. query.address = expected_ips[0]; query.l4_id = 24; for (i = 0; i < 1024; i += 2) { success &= assert_true(pool4_get_similar(IPPROTO_UDP, &query, &results1[i]), "Borrow Addr1-res"); success &= assert_tuple_addr(&expected_ips[0], i, &results1[i], "Borrow Addr1-out"); } success &= assert_false(pool4_get_similar(IPPROTO_UDP, &query, &null_result), "Borrow Addr1-Exhausted (1)"); success &= assert_false(pool4_get_similar(IPPROTO_UDP, &query, &null_result), "Borrow Addr1-Exhausted (2)"); if (!success) return success; // Borrow some from the second address. query.address = expected_ips[1]; query.l4_id = 888; for (i = 0; i < 512; i += 2) { success &= assert_true(pool4_get_similar(IPPROTO_UDP, &query, &results2[i]), "Borrow Addr2-res"); success &= assert_tuple_addr(&expected_ips[1], i, &results2[i], "Borrow Addr2-out"); } if (!success) return success; // Now return stuff in some disorganized manner. success &= assert_true(pool4_return(IPPROTO_UDP, &results2[64]), "Return Addr2-port64"); success &= assert_true(pool4_return(IPPROTO_UDP, &results1[128]), "Return Addr1-port128"); success &= assert_true(pool4_return(IPPROTO_UDP, &results1[32]), "Return Addr2-port32"); success &= assert_true(pool4_return(IPPROTO_UDP, &results2[256]), "Return Addr1-port256"); // Reborrow it. query.l4_id = 334; query.address = expected_ips[0]; success &= assert_true(pool4_get_similar(IPPROTO_UDP, &query, &results1[128]), "Get-Return mix (res), 128"); query.address = expected_ips[1]; success &= assert_true(pool4_get_similar(IPPROTO_UDP, &query, &results2[64]), "Get-Return mix, (res) 64"); query.address = expected_ips[0]; success &= assert_true(pool4_get_similar(IPPROTO_UDP, &query, &results1[32]), "Get-Return mix, (res) 32"); query.address = expected_ips[1]; success &= assert_true(pool4_get_similar(IPPROTO_UDP, &query, &results2[256]), "Get-Return mix, (res) 256"); query.address = expected_ips[0]; success &= assert_false(pool4_get_similar(IPPROTO_UDP, &query, &null_result), "Borrow Addr1-Exhausted (3)"); success &= assert_tuple_addr(&expected_ips[0], 128, &results1[128], "Get-Return mix (out), 128"); success &= assert_tuple_addr(&expected_ips[1], 64, &results2[64], "Get-Return mix (out), 64"); success &= assert_tuple_addr(&expected_ips[0], 32, &results1[32], "Get-Return mix (out), 32"); success &= assert_tuple_addr(&expected_ips[1], 256, &results2[256], "Get-Return mix (out), 256"); return success; }
int delete_static_route(struct request_bib *req) { struct bib_entry *bib; struct session_entry *session; int error = 0; spin_lock_bh(&bib_session_lock); switch (req->remove.l3_proto) { case L3PROTO_IPV6: error = bib_get_by_ipv6(&req->remove.ipv6, req->l4_proto, &bib); if (error) goto end; break; case L3PROTO_IPV4: error = bib_get_by_ipv4(&req->remove.ipv4, req->l4_proto, &bib); if (error) goto end; break; default: log_err(ERR_L3PROTO, "Unsupported network protocol: %u.", req->remove.l3_proto); error = -EINVAL; goto end; } if (!bib) { log_err(ERR_BIB_NOT_FOUND, "Could not find the BIB entry requested by the user."); error = -ENOENT; goto end; } /* * I'm tempted to assert that the entry is static here. Would that serve a purpose? * Nah. */ while (!list_empty(&bib->sessions)) { session = container_of(bib->sessions.next, struct session_entry, bib_list_hook); error = session_remove(session); if (error) { log_err(ERR_UNKNOWN_ERROR, "Session [%pI6c#%u, %pI6c#%u, %pI4#%u, %pI4#%u] refused to die.", &session->ipv6.remote.address, session->ipv6.remote.l4_id, &session->ipv6.local.address, session->ipv6.local.l4_id, &session->ipv4.local.address, session->ipv4.local.l4_id, &session->ipv4.remote.address, session->ipv4.remote.l4_id); goto end; } list_del(&session->bib_list_hook); list_del(&session->expire_list_hook); session_kfree(session); } error = bib_remove(bib, req->l4_proto); if (error) { log_err(ERR_UNKNOWN_ERROR, "Remove bib entry call ended with error code %d, " "despite validations.", error); goto end; } pool4_return(req->l4_proto, &bib->ipv4); bib_kfree(bib); /* Fall through. */ end: spin_unlock_bh(&bib_session_lock); return error; }