/** * 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; }
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; }
/* * The main function. */ static int main_wrapped(int argc, char **argv) { struct arguments args; int error; error = parse_args(argc, argv, &args); if (error) return error; switch (args.mode) { case MODE_POOL6: switch (args.op) { case OP_DISPLAY: return pool6_display(); case OP_COUNT: return pool6_count(); case OP_ADD: if (!args.db.pool6.prefix_set) { log_err("Please enter the prefix to be added (--prefix)."); return -EINVAL; } return pool6_add(&args.db.pool6.prefix); case OP_REMOVE: if (!args.db.pool6.prefix_set) { log_err("Please enter the prefix to be removed (--prefix)."); return -EINVAL; } return pool6_remove(&args.db.pool6.prefix, args.db.quick); case OP_FLUSH: return pool6_flush(args.db.quick); default: log_err("Unknown operation for IPv6 pool mode: %u.", args.op); return -EINVAL; } break; case MODE_POOL4: switch (args.op) { case OP_DISPLAY: return pool4_display(); case OP_COUNT: return pool4_count(); case OP_ADD: if (!args.db.pool4.addr_set) { log_err("Please enter the address to be added (--address)."); return -EINVAL; } return pool4_add(&args.db.pool4.addr); case OP_REMOVE: if (!args.db.pool4.addr_set) { log_err("Please enter the address to be removed (--address)."); return -EINVAL; } return pool4_remove(&args.db.pool4.addr, args.db.quick); case OP_FLUSH: return pool4_flush(args.db.quick); default: log_err("Unknown operation for IPv4 pool mode: %u.", args.op); return -EINVAL; } break; case MODE_BIB: switch (args.op) { case OP_DISPLAY: return bib_display(args.db.tables.tcp, args.db.tables.udp, args.db.tables.icmp, args.db.tables.numeric_hostname, args.db.tables.csv_format); case OP_COUNT: return bib_count(args.db.tables.tcp, args.db.tables.udp, args.db.tables.icmp); case OP_ADD: error = 0; if (!args.db.tables.bib.addr6_set) { log_err("Missing IPv6 address#port (--bib6)."); error = -EINVAL; } if (!args.db.tables.bib.addr4_set) { log_err("Missing IPv4 address#port (--bib4)."); error = -EINVAL; } if (error) return error; return bib_add(args.db.tables.tcp, args.db.tables.udp, args.db.tables.icmp, &args.db.tables.bib.addr6, &args.db.tables.bib.addr4); case OP_REMOVE: if (!args.db.tables.bib.addr6_set && !args.db.tables.bib.addr4_set) { log_err("I need the IPv4 transport address and/or the IPv6 transport address of " "the entry you want to remove."); return -EINVAL; } return bib_remove(args.db.tables.tcp, args.db.tables.udp, args.db.tables.icmp, args.db.tables.bib.addr6_set, &args.db.tables.bib.addr6, args.db.tables.bib.addr4_set, &args.db.tables.bib.addr4); default: log_err("Unknown operation for session mode: %u.", args.op); return -EINVAL; } break; case MODE_SESSION: switch (args.op) { case OP_DISPLAY: return session_display(args.db.tables.tcp, args.db.tables.udp, args.db.tables.icmp, args.db.tables.numeric_hostname, args.db.tables.csv_format); case OP_COUNT: return session_count(args.db.tables.tcp, args.db.tables.udp, args.db.tables.icmp); default: log_err("Unknown operation for session mode: %u.", args.op); return -EINVAL; } break; #ifdef BENCHMARK case MODE_LOGTIME: switch (args.op) { case OP_DISPLAY: return logtime_display(); break; default: log_err("Unknown operation for log time mode: %u.", args.op); break; } break; #endif case MODE_GENERAL: switch (args.op) { case OP_DISPLAY: return general_display(); case OP_UPDATE: error = general_update(args.general.module, args.general.type, args.general.size, args.general.data); free(args.general.data); return error; default: log_err("Unknown operation for general mode: %u.", args.op); return -EINVAL; } } log_err("Unknown configuration mode: %u", args.mode); return -EINVAL; }