bool test_to_array(void) { struct bib_entry *first_bib, *second_bib; struct bib_entry **array; int array_size; // Create and insert BIBs. first_bib = create_bib_entry(0, 0); if (!first_bib) { log_warning("Could not allocate the first BIB entry."); return false; } if (!bib_add(first_bib, IPPROTO_UDP)) { log_warning("Could not add the first BIB entry."); return false; } second_bib = create_bib_entry(1, 1); if (!second_bib) { log_warning("Could not allocate the second BIB entry."); return false; } if (!bib_add(second_bib, IPPROTO_UDP)) { log_warning("Could not add the second BIB entry."); return false; } // Call the function. array_size = bib_to_array(IPPROTO_UDP, &array); // Return value validations. if (array_size == -1) { log_warning("bib_to_array could not allocate the array."); goto free; } if (array_size != 2) { log_warning("Inserted 2 bibs, but the resulting array length is %d.", array_size); goto free; } // Array content validations. if (!bib_entry_equals(first_bib, array[0]) && !bib_entry_equals(first_bib, array[1])) { log_warning("The result array does not contain the first BIB entry."); goto free; } if (!bib_entry_equals(second_bib, array[0]) && !bib_entry_equals(second_bib, array[1])) { log_warning("The result array does not contain the second BIB entry."); goto free; } kfree(array); return true; free: kfree(array); return false; }
/** * Inserts a single entry, validates it, removes it, validates again. * Does not touch the session tables. */ bool simple_bib(void) { struct bib_entry *bib; bool success = true; bib = create_bib_entry(0, 0); if (!assert_not_null(bib, "Allocation of test BIB entry")) return false; success &= assert_equals_int(0, bib_add(bib, IPPROTO_TCP), "BIB insertion call"); success &= assert_bib("BIB insertion state", bib, false, true, false); if (!success) /* * Rather have a slight memory leak than corrupted memory. Because of the error, the table * might or might not have a reference to the entry, and if it does, it will try to kfree * it during bib_destroy(). Hence, better not free it here. */ return false; success &= assert_true(bib_remove(bib, IPPROTO_TCP), "BIB removal call"); success &= assert_bib("BIB removal state", bib, false, false, false); if (!success) return false; kfree(bib); return success; }
/** * Inserts a single entry, validates it, removes it, validates again. * Does not touch the session tables. */ bool simple_bib(void) { // Init struct bib_entry *bib = create_bib_entry(0, 0); if (!bib) { log_warning("Could not allocate a BIB entry."); return false; } // Add if (!bib_add(bib, IPPROTO_TCP)) { log_warning("Test 'BIB insertion' failed: Call returned false."); return false; } if (!assert_bib("BIB insertion", bib, false, true, false)) return false; // Remove if (!bib_remove(bib, IPPROTO_TCP)) { log_warning("Test 'BIB removal' failed: Call returned false."); return false; } if (!assert_bib("BIB removal", bib, false, false, false)) return false; // Quit return true; }
bool simple_bib_session(void) { struct bib_entry *bib; struct session_entry *session; bib = create_bib_entry(0, 0); if (!bib) { log_warning("Could not allocate a BIB entry."); return false; } session = create_session_entry(1, 0, 1, 0, bib, IPPROTO_TCP, 12345); if (!session) { log_warning("Could not allocate a Session entry."); return false; } // Insert the BIB entry. if (!bib_add(bib, IPPROTO_TCP)) { log_warning("Test 'BIB insertion' failed: Call returned false."); return false; } if (!assert_bib("BIB insertion", bib, false, true, false)) return false; // Insert the session entry. if (!session_add(session)) { log_warning("Test 'Session insertion' failed: Call returned false."); return false; } if (!assert_session("Session insertion", session, false, true, false)) return false; // The BIB entry has a session entry, so it shouldn't be removable. if (bib_remove(bib, IPPROTO_TCP)) { log_warning("Test 'Bib removal' failed: Removal shouldn't have succeeded."); return false; } if (!assert_bib("Bib removal (bib table)", bib, false, true, false)) return false; if (!assert_session("BIB removal (session table)", session, false, true, false)) return false; // Remove the session entry. // Because the BIB entry no longer has sessions, it should be automatically removed as well. if (!session_remove(session)) { log_warning("Test 'Session removal' failed: Call returned false."); return false; } if (!assert_bib("Session removal (bib table)", bib, false, false, false)) return false; if (!assert_session("Session removal (session table)", session, false, false, false)) return false; // Quit. return true; }
bool test_address_filtering(void) { struct bib_entry *bib; struct session_entry *session; // Init. bib = create_bib_entry(0, 0); if (!bib) { log_warning("Could not allocate a BIB entry."); return false; } session = create_session_entry(0, 0, 0, 0, bib, IPPROTO_UDP, 12345); if (!session) { log_warning("Could not allocate a Session entry."); return false; } if (!bib_add(bib, IPPROTO_UDP)) { log_warning("Could not add the BIB entry."); return false; } if (!session_add(session)) { log_warning("Could not add the session entry."); return false; } // Test the packet is allowed when the tuple and session match perfectly. if (!test_address_filtering_aux(0, 0, 0, 0, true)) return false; // Test a tuple that completely mismatches the session. if (!test_address_filtering_aux(1, 1, 1, 1, false)) return false; // Now test tuples that nearly match the session. if (!test_address_filtering_aux(0, 0, 0, 1, false)) return false; if (!test_address_filtering_aux(0, 0, 1, 0, false)) return false; if (!test_address_filtering_aux(0, 1, 0, 0, true)) return false; // The remote port is the only one that doesn't matter. if (!test_address_filtering_aux(1, 0, 0, 0, false)) return false; return true; }
static struct bib_entry *create_and_insert_bib(int ipv4_index, int ipv6_index, int l4proto) { struct bib_entry *result; int error; result = create_bib_entry(ipv4_index, ipv6_index); if (!result) { log_warning("Could not allocate a BIB entry."); return NULL; } error = bib_add(result, l4proto); if (error) { log_warning("Could not insert the BIB entry to the table; call returned %d.", error); return NULL; } return result; }
bool test_clean_old_sessions(void) { struct bib_entry *bibs[BIB_COUNT]; struct session_entry *sessions[BIB_COUNT][SESSIONS_PER_BIB]; int cbib, cses; // "BIB counter, session counter". Sorry; I use them too much. const unsigned int time_before = jiffies_to_msecs(jiffies) - 1000; const unsigned int time_after = jiffies_to_msecs(jiffies) + 1000; // Allocate. for (cbib = 0; cbib < BIB_COUNT; cbib++) { bibs[cbib] = create_bib_entry(cbib, cbib); if (!bibs[cbib]) { log_warning("Could not allocate a BIB entry %d.", cbib); return false; } } for (cbib = 0; cbib < BIB_COUNT; cbib++) { for (cses = 0; cses < SESSIONS_PER_BIB; cses++) { sessions[cbib][cses] = create_session_entry(cbib, cses + 5, cbib, cses + 5, bibs[cbib], IPPROTO_UDP, time_after); if (!sessions[cbib][cses]) { log_warning("Could not allocate a Session entry %d-%d.", cbib, cses); return false; } } } sessions[3][1]->is_static = true; // Insert to the tables. for (cbib = 0; cbib < BIB_COUNT; cbib++) { if (!bib_add(bibs[cbib], IPPROTO_UDP)) { log_warning("Could not add BIB entry %d.", cbib); return false; } } for (cbib = 0; cbib < BIB_COUNT; cbib++) { for (cses = 0; cses < SESSIONS_PER_BIB; cses++) { if (!session_add(sessions[cbib][cses])) { log_warning("Could not add session entry %d-%d.", cbib, cses); return false; } } } // 1. Nothing has expired: // Test nothing gets deleted. clean_expired_sessions(); ASSERT_SINGLE_BIB("Clean deletes nothing", 0, true, true, true, true); ASSERT_SINGLE_BIB("Clean deletes nothing", 1, true, true, true, true); ASSERT_SINGLE_BIB("Clean deletes nothing", 2, true, true, true, true); ASSERT_SINGLE_BIB("Clean deletes nothing", 3, true, true, true, true); // 2. All of a single BIB's sessions expire: // Test both BIBs and Sessions die. sessions[1][0]->dying_time = time_before; sessions[1][1]->dying_time = time_before; sessions[1][2]->dying_time = time_before; clean_expired_sessions(); ASSERT_SINGLE_BIB("Whole BIB dies", 0, true, true, true, true); ASSERT_SINGLE_BIB("Whole BIB dies", 1, false, false, false, false); ASSERT_SINGLE_BIB("Whole BIB dies", 2, true, true, true, true); ASSERT_SINGLE_BIB("Whole BIB dies", 3, true, true, true, true); // 3. Some sessions of a BIB expire: // Test only they get deleted. sessions[2][0]->dying_time = time_before; sessions[2][1]->dying_time = time_before; clean_expired_sessions(); ASSERT_SINGLE_BIB("Some sessions die", 0, true, true, true, true); ASSERT_SINGLE_BIB("Some sessions die", 1, false, false, false, false); ASSERT_SINGLE_BIB("Some sessions die", 2, true, false, false, true); ASSERT_SINGLE_BIB("Some sessions die", 3, true, true, true, true); // 4. The rest of them expire: // Test the BIB keeps keeps behaving as expected. Perhaps unnecesary. sessions[2][2]->dying_time = time_before; clean_expired_sessions(); ASSERT_SINGLE_BIB("Last session dies", 0, true, true, true, true); ASSERT_SINGLE_BIB("Last session dies", 1, false, false, false, false); ASSERT_SINGLE_BIB("Last session dies", 2, false, false, false, false); ASSERT_SINGLE_BIB("Last session dies", 3, true, true, true, true); // 5. The sessions of a static BIB expire, but one of them is static. // Test only the dynamic ones die. sessions[3][0]->dying_time = time_before; sessions[3][1]->dying_time = time_before; sessions[3][2]->dying_time = time_before; clean_expired_sessions(); ASSERT_SINGLE_BIB("Static session doesn't die", 0, true, true, true, true); ASSERT_SINGLE_BIB("Static session doesn't die", 1, false, false, false, false); ASSERT_SINGLE_BIB("Static session doesn't die", 2, false, false, false, false); ASSERT_SINGLE_BIB("Static session doesn't die", 3, true, false, true, false); // Quit. return true; }