/* * Check that rte_lpm_add fails gracefully for incorrect user input arguments */ int32_t test3(void) { struct rte_lpm *lpm = NULL; uint32_t ip = IPv4(0, 0, 0, 0); uint8_t depth = 24, next_hop = 100; int32_t status = 0; /* rte_lpm_add: lpm == NULL */ status = rte_lpm_add(NULL, ip, depth, next_hop); TEST_LPM_ASSERT(status < 0); /*Create vaild lpm to use in rest of test. */ lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, MAX_RULES, 0); TEST_LPM_ASSERT(lpm != NULL); /* rte_lpm_add: depth < 1 */ status = rte_lpm_add(lpm, ip, 0, next_hop); TEST_LPM_ASSERT(status < 0); /* rte_lpm_add: depth > MAX_DEPTH */ status = rte_lpm_add(lpm, ip, (MAX_DEPTH + 1), next_hop); TEST_LPM_ASSERT(status < 0); rte_lpm_free(lpm); return PASS; }
/* * Add two rules, lookup to hit the more specific one, lookup to hit the less * specific one delete the less specific rule and lookup previous values again; * add a more specific rule than the existing rule, lookup again * * */ int32_t test11(void) { struct rte_lpm *lpm = NULL; uint32_t ip; uint8_t depth, next_hop_add, next_hop_return; int32_t status = 0; lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, MAX_RULES, 0); TEST_LPM_ASSERT(lpm != NULL); ip = IPv4(128, 0, 0, 0); depth = 24; next_hop_add = 100; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); ip = IPv4(128, 0, 0, 10); depth = 32; next_hop_add = 101; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); ip = IPv4(128, 0, 0, 0); next_hop_add = 100; status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); ip = IPv4(128, 0, 0, 0); depth = 24; status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); ip = IPv4(128, 0, 0, 10); depth = 32; status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); rte_lpm_free(lpm); return PASS; }
int control_add_ipv4_local_entry(struct in_addr* nexthop, struct in_addr* saddr, uint8_t depth, uint32_t port_id, int32_t socket_id) { int s; uint16_t nexthop_id; s = neighbor4_lookup_nexthop(neighbor4_struct[socket_id], nexthop, &nexthop_id); if (s < 0) { s = neighbor4_add_nexthop(neighbor4_struct[socket_id], nexthop, &nexthop_id, NEI_ACTION_KNI); if (s < 0) { RTE_LOG( ERR, PKTJ_CTRL1, "failed to add a nexthop during route adding...\n"); return -1; } } neighbor4_set_port(neighbor4_struct[socket_id], nexthop_id, port_id); s = rte_lpm_add(ipv4_pktj_lookup_struct[socket_id], rte_be_to_cpu_32(saddr->s_addr), depth, nexthop_id); if (s < 0) { RTE_LOG( ERR, PKTJ_CTRL1, "failed to add a route in lpm during route adding...\n"); return -1; } neighbor4_refcount_incr(neighbor4_struct[socket_id], nexthop_id); return nexthop_id; }
static void app_init_lpm_tables(void) { unsigned socket, lcore; /* Init the LPM tables */ for (socket = 0; socket < APP_MAX_SOCKETS; socket ++) { char name[32]; uint32_t rule; if (app_is_socket_used(socket) == 0) { continue; } struct rte_lpm_config lpm_config; lpm_config.max_rules = APP_MAX_LPM_RULES; lpm_config.number_tbl8s = 256; lpm_config.flags = 0; snprintf(name, sizeof(name), "lpm_table_%u", socket); printf("Creating the LPM table for socket %u ...\n", socket); app.lpm_tables[socket] = rte_lpm_create( name, socket, &lpm_config); if (app.lpm_tables[socket] == NULL) { rte_panic("Unable to create LPM table on socket %u\n", socket); } for (rule = 0; rule < app.n_lpm_rules; rule ++) { int ret; ret = rte_lpm_add(app.lpm_tables[socket], app.lpm_rules[rule].ip, app.lpm_rules[rule].depth, app.lpm_rules[rule].if_out); if (ret < 0) { rte_panic("Unable to add entry %u (%x/%u => %u) to the LPM table on socket %u (%d)\n", (unsigned) rule, (unsigned) app.lpm_rules[rule].ip, (unsigned) app.lpm_rules[rule].depth, (unsigned) app.lpm_rules[rule].if_out, socket, ret); } } } for (lcore = 0; lcore < APP_MAX_LCORES; lcore ++) { if (app.lcore_params[lcore].type != e_APP_LCORE_WORKER) { continue; } socket = rte_lcore_to_socket_id(lcore); app.lcore_params[lcore].worker.lpm_table = app.lpm_tables[socket]; } }
void rt_init(struct socket_ctx *ctx, int socket_id, unsigned ep) { char name[PATH_MAX]; unsigned i; int ret; struct rte_lpm *lpm; struct ipv4_route *rt; char a, b, c, d; unsigned nb_routes; struct rte_lpm_config conf = { 0 }; if (ctx == NULL) rte_exit(EXIT_FAILURE, "NULL context.\n"); if (ctx->rt_ipv4 != NULL) rte_exit(EXIT_FAILURE, "Routing Table for socket %u already " "initialized\n", socket_id); printf("Creating Routing Table (RT) context with %u max routes\n", RT_IPV4_MAX_RULES); if (ep == 0) { rt = rt_ipv4_ep0; nb_routes = RTE_DIM(rt_ipv4_ep0); } else if (ep == 1) { rt = rt_ipv4_ep1; nb_routes = RTE_DIM(rt_ipv4_ep1); } else rte_exit(EXIT_FAILURE, "Invalid EP value %u. Only 0 or 1 " "supported.\n", ep); /* create the LPM table */ snprintf(name, sizeof(name), "%s_%u", "rt_ipv4", socket_id); conf.max_rules = RT_IPV4_MAX_RULES; conf.number_tbl8s = RTE_LPM_TBL8_NUM_ENTRIES; lpm = rte_lpm_create(name, socket_id, &conf); if (lpm == NULL) rte_exit(EXIT_FAILURE, "Unable to create LPM table " "on socket %d\n", socket_id); /* populate the LPM table */ for (i = 0; i < nb_routes; i++) { ret = rte_lpm_add(lpm, rt[i].ip, rt[i].depth, rt[i].if_out); if (ret < 0) rte_exit(EXIT_FAILURE, "Unable to add entry num %u to " "LPM table on socket %d\n", i, socket_id); uint32_t_to_char(rt[i].ip, &a, &b, &c, &d); printf("LPM: Adding route %hhu.%hhu.%hhu.%hhu/%hhu (%hhu)\n", a, b, c, d, rt[i].depth, rt[i].if_out); } ctx->rt_ipv4 = (struct rt_ctx *)lpm; }
/* * Fore TBL8 extension exhaustion. Add 256 rules that require a tbl8 extension. * No more tbl8 extensions will be allowed. Now add one more rule that required * a tbl8 extension and get fail. * */ int32_t test14(void) { /* We only use depth = 32 in the loop below so we must make sure * that we have enough storage for all rules at that depth*/ struct rte_lpm *lpm = NULL; uint32_t ip; uint8_t depth, next_hop_add, next_hop_return; int32_t status = 0; /* Add enough space for 256 rules for every depth */ lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, 256 * 32, 0); TEST_LPM_ASSERT(lpm != NULL); depth = 32; next_hop_add = 100; ip = IPv4(0, 0, 0, 0); /* Add 256 rules that require a tbl8 extension */ for (; ip <= IPv4(0, 0, 255, 0); ip += 256) { status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); } /* All tbl8 extensions have been used above. Try to add one more and * we get a fail */ ip = IPv4(1, 0, 0, 0); depth = 32; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status < 0); rte_lpm_free(lpm); return PASS; }
int lpm_entry_add(unsigned int ip, int depth, int next_hop, int socketid) { int ret = -1; /* populate the LPM table */ ret = rte_lpm_add(ipv4_l3fwd_lpm_lookup_struct[socketid], ip, depth, next_hop); if (ret < 0) { rte_exit(EXIT_FAILURE, "Unable to add entry to the l3fwd LPM table on socket %d\n", socketid); } printf("LPM: Adding route 0x%08x / %d (%d)\n", (unsigned)ip, depth, next_hop); return 1; }
int32_t test12(void) { __m128i ipx4; uint16_t hop[4]; struct rte_lpm *lpm = NULL; uint32_t ip, i; uint8_t depth, next_hop_add, next_hop_return; int32_t status = 0; lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, MAX_RULES, 0); TEST_LPM_ASSERT(lpm != NULL); ip = IPv4(128, 0, 0, 0); depth = 32; next_hop_add = 100; for (i = 0; i < 1000; i++) { status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); ipx4 = _mm_set_epi32(ip, ip + 1, ip, ip - 1); rte_lpm_lookupx4(lpm, ipx4, hop, UINT16_MAX); TEST_LPM_ASSERT(hop[0] == UINT16_MAX); TEST_LPM_ASSERT(hop[1] == next_hop_add); TEST_LPM_ASSERT(hop[2] == UINT16_MAX); TEST_LPM_ASSERT(hop[3] == next_hop_add); status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); } rte_lpm_free(lpm); return PASS; }
/* * test failure condition of overloading the tbl8 so no more will fit * Check we get an error return value in that case */ int32_t test16(void) { uint32_t ip; struct rte_lpm *lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, 256 * 32, 0); /* ip loops through all possibilities for top 24 bits of address */ for (ip = 0; ip < 0xFFFFFF; ip++){ /* add an entry within a different tbl8 each time, since * depth >24 and the top 24 bits are different */ if (rte_lpm_add(lpm, (ip << 8) + 0xF0, 30, 0) < 0) break; } if (ip != RTE_LPM_TBL8_NUM_GROUPS) { printf("Error, unexpected failure with filling tbl8 groups\n"); printf("Failed after %u additions, expected after %u\n", (unsigned)ip, (unsigned)RTE_LPM_TBL8_NUM_GROUPS); } rte_lpm_free(lpm); return 0; }
/* * - Add rule that covers a TBL24 range previously invalid & lookup (& delete & * lookup) * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup) * - Add rule that extends a TBL24 valid entry & lookup for both rules (& * delete & lookup) * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup) * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup) * - Delete a rule that is not present in the TBL24 & lookup * - Delete a rule that is not present in the TBL8 & lookup * */ int32_t test10(void) { struct rte_lpm *lpm = NULL; uint32_t ip; uint8_t depth, next_hop_add, next_hop_return; int32_t status = 0; /* Add rule that covers a TBL24 range previously invalid & lookup * (& delete & lookup) */ lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, MAX_RULES, RTE_LPM_HEAP); TEST_LPM_ASSERT(lpm != NULL); ip = IPv4(128, 0, 0, 0); depth = 16; next_hop_add = 100; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); rte_lpm_delete_all(lpm); ip = IPv4(128, 0, 0, 0); depth = 25; next_hop_add = 100; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); rte_lpm_delete_all(lpm); /* Add rule that extends a TBL24 valid entry & lookup for both rules * (& delete & lookup) */ ip = IPv4(128, 0, 0, 0); depth = 24; next_hop_add = 100; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); ip = IPv4(128, 0, 0, 10); depth = 32; next_hop_add = 101; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); ip = IPv4(128, 0, 0, 0); next_hop_add = 100; status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); ip = IPv4(128, 0, 0, 0); depth = 24; status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); ip = IPv4(128, 0, 0, 10); depth = 32; status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); rte_lpm_delete_all(lpm); /* Add rule that updates the next hop in TBL24 & lookup * (& delete & lookup) */ ip = IPv4(128, 0, 0, 0); depth = 24; next_hop_add = 100; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); next_hop_add = 101; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); rte_lpm_delete_all(lpm); /* Add rule that updates the next hop in TBL8 & lookup * (& delete & lookup) */ ip = IPv4(128, 0, 0, 0); depth = 32; next_hop_add = 100; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); next_hop_add = 101; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); rte_lpm_delete_all(lpm); /* Delete a rule that is not present in the TBL24 & lookup */ ip = IPv4(128, 0, 0, 0); depth = 24; status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status < 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); rte_lpm_delete_all(lpm); /* Delete a rule that is not present in the TBL8 & lookup */ ip = IPv4(128, 0, 0, 0); depth = 32; status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status < 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); rte_lpm_free(lpm); return PASS; }
/* * - Add & lookup to hit invalid TBL24 entry * - Add & lookup to hit valid TBL24 entry not extended * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry * */ int32_t test9(void) { struct rte_lpm *lpm = NULL; uint32_t ip, ip_1, ip_2; uint8_t depth, depth_1, depth_2, next_hop_add, next_hop_add_1, next_hop_add_2, next_hop_return; int32_t status = 0; /* Add & lookup to hit invalid TBL24 entry */ ip = IPv4(128, 0, 0, 0); depth = 24; next_hop_add = 100; lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, MAX_RULES, 0); TEST_LPM_ASSERT(lpm != NULL); status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); rte_lpm_delete_all(lpm); /* Add & lookup to hit valid TBL24 entry not extended */ ip = IPv4(128, 0, 0, 0); depth = 23; next_hop_add = 100; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); depth = 24; next_hop_add = 101; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); depth = 24; status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); depth = 23; status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); rte_lpm_delete_all(lpm); /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8 * entry */ ip = IPv4(128, 0, 0, 0); depth = 32; next_hop_add = 100; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); ip = IPv4(128, 0, 0, 5); depth = 32; next_hop_add = 101; status = rte_lpm_add(lpm, ip, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); ip = IPv4(128, 0, 0, 0); depth = 32; next_hop_add = 100; status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); status = rte_lpm_delete(lpm, ip, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); rte_lpm_delete_all(lpm); /* Add & lookup to hit valid extended TBL24 entry with valid TBL8 * entry */ ip_1 = IPv4(128, 0, 0, 0); depth_1 = 25; next_hop_add_1 = 101; ip_2 = IPv4(128, 0, 0, 5); depth_2 = 32; next_hop_add_2 = 102; next_hop_return = 0; status = rte_lpm_add(lpm, ip_1, depth_1, next_hop_add_1); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip_1, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); status = rte_lpm_add(lpm, ip_2, depth_2, next_hop_add_2); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip_2, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2)); status = rte_lpm_delete(lpm, ip_2, depth_2); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip_2, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1)); status = rte_lpm_delete(lpm, ip_1, depth_1); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip_1, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); rte_lpm_free(lpm); return PASS; }
/* * Use rte_lpm_add to add rules which effect only the second half of the lpm * table. Use all possible depths ranging from 1..32. Set the next hop = to the * depth. Check lookup hit for on every add and check for lookup miss on the * first half of the lpm table after each add. Finally delete all rules going * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each * delete. The lookup should return the next_hop_add value related to the * previous depth value (i.e. depth -1). */ int32_t test8(void) { __m128i ipx4; uint16_t hop[4]; struct rte_lpm *lpm = NULL; uint32_t ip1 = IPv4(127, 255, 255, 255), ip2 = IPv4(128, 0, 0, 0); uint8_t depth, next_hop_add, next_hop_return; int32_t status = 0; lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, MAX_RULES, 0); TEST_LPM_ASSERT(lpm != NULL); /* Loop with rte_lpm_add. */ for (depth = 1; depth <= 32; depth++) { /* Let the next_hop_add value = depth. Just for change. */ next_hop_add = depth; status = rte_lpm_add(lpm, ip2, depth, next_hop_add); TEST_LPM_ASSERT(status == 0); /* Check IP in first half of tbl24 which should be empty. */ status = rte_lpm_lookup(lpm, ip1, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); status = rte_lpm_lookup(lpm, ip2, &next_hop_return); TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); ipx4 = _mm_set_epi32(ip2, ip1, ip2, ip1); rte_lpm_lookupx4(lpm, ipx4, hop, UINT16_MAX); TEST_LPM_ASSERT(hop[0] == UINT16_MAX); TEST_LPM_ASSERT(hop[1] == next_hop_add); TEST_LPM_ASSERT(hop[2] == UINT16_MAX); TEST_LPM_ASSERT(hop[3] == next_hop_add); } /* Loop with rte_lpm_delete. */ for (depth = 32; depth >= 1; depth--) { next_hop_add = (uint8_t) (depth - 1); status = rte_lpm_delete(lpm, ip2, depth); TEST_LPM_ASSERT(status == 0); status = rte_lpm_lookup(lpm, ip2, &next_hop_return); if (depth != 1) { TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add)); } else { TEST_LPM_ASSERT(status == -ENOENT); } status = rte_lpm_lookup(lpm, ip1, &next_hop_return); TEST_LPM_ASSERT(status == -ENOENT); ipx4 = _mm_set_epi32(ip1, ip1, ip2, ip2); rte_lpm_lookupx4(lpm, ipx4, hop, UINT16_MAX); if (depth != 1) { TEST_LPM_ASSERT(hop[0] == next_hop_add); TEST_LPM_ASSERT(hop[1] == next_hop_add); } else { TEST_LPM_ASSERT(hop[0] == UINT16_MAX); TEST_LPM_ASSERT(hop[1] == UINT16_MAX); } TEST_LPM_ASSERT(hop[2] == UINT16_MAX); TEST_LPM_ASSERT(hop[3] == UINT16_MAX); } rte_lpm_free(lpm); return PASS; }
/* * Test for overwriting of tbl8: * - add rule /32 and lookup * - add new rule /24 and lookup * - add third rule /25 and lookup * - lookup /32 and /24 rule to ensure the table has not been overwritten. */ int32_t test17(void) { struct rte_lpm *lpm = NULL; const uint32_t ip_10_32 = IPv4(10, 10, 10, 2); const uint32_t ip_10_24 = IPv4(10, 10, 10, 0); const uint32_t ip_20_25 = IPv4(10, 10, 20, 2); const uint8_t d_ip_10_32 = 32, d_ip_10_24 = 24, d_ip_20_25 = 25; const uint8_t next_hop_ip_10_32 = 100, next_hop_ip_10_24 = 105, next_hop_ip_20_25 = 111; uint8_t next_hop_return = 0; int32_t status = 0; lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, MAX_RULES, 0); TEST_LPM_ASSERT(lpm != NULL); if ((status = rte_lpm_add(lpm, ip_10_32, d_ip_10_32, next_hop_ip_10_32)) < 0) return -1; status = rte_lpm_lookup(lpm, ip_10_32, &next_hop_return); uint8_t test_hop_10_32 = next_hop_return; TEST_LPM_ASSERT(status == 0); TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32); if ((status = rte_lpm_add(lpm, ip_10_24, d_ip_10_24, next_hop_ip_10_24)) < 0) return -1; status = rte_lpm_lookup(lpm, ip_10_24, &next_hop_return); uint8_t test_hop_10_24 = next_hop_return; TEST_LPM_ASSERT(status == 0); TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24); if ((status = rte_lpm_add(lpm, ip_20_25, d_ip_20_25, next_hop_ip_20_25)) < 0) return -1; status = rte_lpm_lookup(lpm, ip_20_25, &next_hop_return); uint8_t test_hop_20_25 = next_hop_return; TEST_LPM_ASSERT(status == 0); TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25); if (test_hop_10_32 == test_hop_10_24) { printf("Next hop return equal\n"); return -1; } if (test_hop_10_24 == test_hop_20_25){ printf("Next hop return equal\n"); return -1; } status = rte_lpm_lookup(lpm, ip_10_32, &next_hop_return); TEST_LPM_ASSERT(status == 0); TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32); status = rte_lpm_lookup(lpm, ip_10_24, &next_hop_return); TEST_LPM_ASSERT(status == 0); TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24); rte_lpm_free(lpm); return PASS; }
static int rte_table_lpm_entry_add( void *table, void *key, void *entry, int *key_found, void **entry_ptr) { struct rte_table_lpm *lpm = (struct rte_table_lpm *) table; struct rte_table_lpm_key *ip_prefix = (struct rte_table_lpm_key *) key; uint32_t nht_pos, nht_pos0_valid; int status; uint8_t nht_pos0 = 0; /* Check input parameters */ if (lpm == NULL) { RTE_LOG(ERR, TABLE, "%s: table parameter is NULL\n", __func__); return -EINVAL; } if (ip_prefix == NULL) { RTE_LOG(ERR, TABLE, "%s: ip_prefix parameter is NULL\n", __func__); return -EINVAL; } if (entry == NULL) { RTE_LOG(ERR, TABLE, "%s: entry parameter is NULL\n", __func__); return -EINVAL; } if ((ip_prefix->depth == 0) || (ip_prefix->depth > 32)) { RTE_LOG(ERR, TABLE, "%s: invalid depth (%d)\n", __func__, ip_prefix->depth); return -EINVAL; } /* Check if rule is already present in the table */ status = rte_lpm_is_rule_present(lpm->lpm, ip_prefix->ip, ip_prefix->depth, &nht_pos0); nht_pos0_valid = status > 0; /* Find existing or free NHT entry */ if (nht_find_existing(lpm, entry, &nht_pos) == 0) { uint8_t *nht_entry; if (nht_find_free(lpm, &nht_pos) == 0) { RTE_LOG(ERR, TABLE, "%s: NHT full\n", __func__); return -1; } nht_entry = &lpm->nht[nht_pos * lpm->entry_size]; memcpy(nht_entry, entry, lpm->entry_size); } /* Add rule to low level LPM table */ if (rte_lpm_add(lpm->lpm, ip_prefix->ip, ip_prefix->depth, (uint8_t) nht_pos) < 0) { RTE_LOG(ERR, TABLE, "%s: LPM rule add failed\n", __func__); return -1; } /* Commit NHT changes */ lpm->nht_users[nht_pos]++; lpm->nht_users[nht_pos0] -= nht_pos0_valid; *key_found = nht_pos0_valid; *entry_ptr = (void *) &lpm->nht[nht_pos * lpm->entry_size]; return 0; }
static int neighbor4(neighbor_action_t action, __s32 port_id, struct in_addr* addr, struct ether_addr* lladdr, __u8 flags, __rte_unused __u16 vlan_id, void* args) { // if port_id is not handled // ignore, return immediatly // if neighbor add // lookup neighbor // if exists // update lladdr, set flag as REACHABLE/STALE/DELAY // else // // This should not happen // insert new nexthop // set insert date=now, refcount = 0, flag=REACHABLE/STALE/DELAY // if neighbor delete // lookup neighbor // if exists // if refcount != 0 // set nexthop as invalid // else // set flag empty // else // do nothing // // this should not happen struct control_handle* handle = args; assert(handle != NULL); int s; uint16_t nexthop_id; uint32_t find_id; int32_t socket_id = handle->socket_id; char ipbuf[INET_ADDRSTRLEN]; assert(neighbor4_struct != NULL); if (addr == NULL) return -1; inet_ntop(AF_INET, addr, ipbuf, INET_ADDRSTRLEN); if (action == NEIGHBOR_ADD) { if (lladdr == NULL) return -1; char ibuf[IFNAMSIZ]; unsigned kni_vlan; if_indextoname(port_id, ibuf); s = sscanf(ibuf, "dpdk%10u.%10u", &port_id, &kni_vlan); if (s <= 0) { RTE_LOG(ERR, PKTJ_CTRL1, "received a neighbor " "announce for an unmanaged " "iface %s\n", ibuf); return -1; } s = neighbor4_lookup_nexthop(neighbor4_struct[socket_id], addr, &nexthop_id); if (s < 0) { if (flags != NUD_NONE && flags != NUD_NOARP && flags != NUD_STALE) { RTE_LOG(ERR, PKTJ_CTRL1, "failed to change state in neighbor4 " "table (state %d, %s)...\n", flags, ipbuf); return -1; } { RTE_LOG(DEBUG, PKTJ_CTRL1, "adding ipv4 neighbor %s with port %s " "vlan_id %d...\n", ipbuf, ibuf, kni_vlan); } s = neighbor4_add_nexthop(neighbor4_struct[socket_id], addr, &nexthop_id, NEI_ACTION_FWD); if (s < 0) { RTE_LOG(ERR, PKTJ_CTRL1, "failed to add a " "nexthop in neighbor " "table...\n"); return -1; } if (rte_lpm_lookup(ipv4_pktj_lookup_struct[socket_id], rte_be_to_cpu_32(addr->s_addr), &find_id) == 0) { s = rte_lpm_add( ipv4_pktj_lookup_struct[socket_id], rte_be_to_cpu_32(addr->s_addr), 32, nexthop_id); if (s < 0) { lpm4_stats[socket_id].nb_add_ko++; RTE_LOG(ERR, PKTJ_CTRL1, "failed to add a route in " "lpm during neighbor " "adding...\n"); return -1; } lpm4_stats[socket_id].nb_add_ok++; } } if (flags == NUD_FAILED) { neighbor4_set_action(neighbor4_struct[socket_id], nexthop_id, NEI_ACTION_KNI); } else { neighbor4_set_action(neighbor4_struct[socket_id], nexthop_id, NEI_ACTION_FWD); } RTE_LOG(DEBUG, PKTJ_CTRL1, "set neighbor4 with port_id %d state %d\n", port_id, flags); neighbor4_set_lladdr_port(neighbor4_struct[socket_id], nexthop_id, &ports_eth_addr[port_id], lladdr, port_id, kni_vlan); neighbor4_set_state(neighbor4_struct[socket_id], nexthop_id, flags); } if (action == NEIGHBOR_DELETE) { if (flags != NUD_FAILED && flags != NUD_STALE) { RTE_LOG( DEBUG, PKTJ_CTRL1, "neighbor4 delete ope failed, bad NUD state: %d \n", flags); return -1; } RTE_LOG(DEBUG, PKTJ_CTRL1, "deleting ipv4 neighbor...\n"); s = neighbor4_lookup_nexthop(neighbor4_struct[socket_id], addr, &nexthop_id); if (s < 0) { RTE_LOG(ERR, PKTJ_CTRL1, "failed to find a nexthop to " "delete in neighbor " "table...\n"); return 0; } neighbor4_delete(neighbor4_struct[socket_id], nexthop_id); // FIXME not thread safe if (neighbor4_struct[socket_id] ->entries.t4[nexthop_id] .neighbor.refcnt == 0) { s = rte_lpm_delete(ipv4_pktj_lookup_struct[socket_id], rte_be_to_cpu_32(addr->s_addr), 32); if (s < 0) { lpm4_stats[socket_id].nb_del_ko++; RTE_LOG(ERR, PKTJ_CTRL1, "failed to delete route...\n"); return -1; } lpm4_stats[socket_id].nb_del_ok++; } } RTE_LOG(DEBUG, PKTJ_CTRL1, "neigh %s ope success\n", ipbuf); return 0; }
static int route4(__rte_unused struct rtmsg* route, route_action_t action, struct in_addr* addr, uint8_t depth, struct in_addr* nexthop, uint8_t type, void* args) { // If route add // lookup next hop in neighbor table ipv4 // if not lookup // create next hop, with flag invalid and addr = nexthop // nexthopid = last id // // register new route in lpm, with nexthop id // increment refcount in neighbor // If route delete // lookup next hop in neighbor table ipv4 // if not lookup // then WTF TABLE CORRUPTED // remove route from lpm // decrement refcount in neighbor // if refcount reached 0 // then flag entry empty struct control_handle* handle = args; assert(handle != NULL); uint16_t nexthop_id; int s; int32_t socket_id = handle->socket_id; struct in_addr blackhole_addr4 = {rte_be_to_cpu_32(INADDR_ANY)}; if (type == RTN_BLACKHOLE) { nexthop = &blackhole_addr4; } if (action == ROUTE_ADD) { RTE_LOG(DEBUG, PKTJ_CTRL1, "adding an ipv4 route...\n"); // lookup nexthop s = neighbor4_lookup_nexthop(neighbor4_struct[socket_id], nexthop, &nexthop_id); if (s < 0) { s = neighbor4_add_nexthop(neighbor4_struct[socket_id], nexthop, &nexthop_id, NEI_ACTION_FWD); if (s < 0) { RTE_LOG(ERR, PKTJ_CTRL1, "failed to add a " "nexthop during " "route adding...\n"); return -1; } } s = rte_lpm_add(ipv4_pktj_lookup_struct[socket_id], rte_be_to_cpu_32(addr->s_addr), depth, nexthop_id); if (s < 0) { lpm4_stats[socket_id].nb_add_ko++; RTE_LOG(ERR, PKTJ_CTRL1, "failed to add a route in " "lpm during route " "adding...\n"); return -1; } neighbor4_refcount_incr(neighbor4_struct[socket_id], nexthop_id); lpm4_stats[socket_id].nb_add_ok++; } if (action == ROUTE_DELETE) { RTE_LOG(DEBUG, PKTJ_CTRL1, "deleting an ipv4 route...\n"); // lookup nexthop s = neighbor4_lookup_nexthop(neighbor4_struct[socket_id], nexthop, &nexthop_id); if (s < 0) { RTE_LOG(ERR, PKTJ_CTRL1, "failed to find nexthop " "during route deletion...\n"); return -1; } s = rte_lpm_delete(ipv4_pktj_lookup_struct[socket_id], rte_be_to_cpu_32(addr->s_addr), depth); if (s < 0) { lpm4_stats[socket_id].nb_del_ko++; RTE_LOG(ERR, PKTJ_CTRL1, "failed to delete route...\n"); return -1; } neighbor4_refcount_decr(neighbor4_struct[socket_id], nexthop_id); lpm4_stats[socket_id].nb_del_ok++; } RTE_LOG(DEBUG, PKTJ_CTRL1, "route ope success\n"); return 0; }
int32_t perf_test(void) { struct rte_lpm *lpm = NULL; uint64_t begin, total_time, lpm_used_entries = 0; unsigned i, j; uint8_t next_hop_add = 0xAA, next_hop_return = 0; int status = 0; uint64_t cache_line_counter = 0; int64_t count = 0; rte_srand(rte_rdtsc()); printf("No. routes = %u\n", (unsigned) NUM_ROUTE_ENTRIES); print_route_distribution(large_route_table, (uint32_t) NUM_ROUTE_ENTRIES); lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, 1000000, 0); TEST_LPM_ASSERT(lpm != NULL); /* Measue add. */ begin = rte_rdtsc(); for (i = 0; i < NUM_ROUTE_ENTRIES; i++) { if (rte_lpm_add(lpm, large_route_table[i].ip, large_route_table[i].depth, next_hop_add) == 0) status++; } /* End Timer. */ total_time = rte_rdtsc() - begin; printf("Unique added entries = %d\n", status); /* Obtain add statistics. */ for (i = 0; i < RTE_LPM_TBL24_NUM_ENTRIES; i++) { if (lpm->tbl24[i].valid) lpm_used_entries++; if (i % 32 == 0){ if ((uint64_t)count < lpm_used_entries) { cache_line_counter++; count = lpm_used_entries; } } } printf("Used table 24 entries = %u (%g%%)\n", (unsigned) lpm_used_entries, (lpm_used_entries * 100.0) / RTE_LPM_TBL24_NUM_ENTRIES); printf("64 byte Cache entries used = %u (%u bytes)\n", (unsigned) cache_line_counter, (unsigned) cache_line_counter * 64); printf("Average LPM Add: %g cycles\n", (double)total_time / NUM_ROUTE_ENTRIES); /* Measure single Lookup */ total_time = 0; count = 0; for (i = 0; i < ITERATIONS; i ++) { static uint32_t ip_batch[BATCH_SIZE]; for (j = 0; j < BATCH_SIZE; j ++) ip_batch[j] = rte_rand(); /* Lookup per batch */ begin = rte_rdtsc(); for (j = 0; j < BATCH_SIZE; j ++) { if (rte_lpm_lookup(lpm, ip_batch[j], &next_hop_return) != 0) count++; } total_time += rte_rdtsc() - begin; } printf("Average LPM Lookup: %.1f cycles (fails = %.1f%%)\n", (double)total_time / ((double)ITERATIONS * BATCH_SIZE), (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE)); /* Measure bulk Lookup */ total_time = 0; count = 0; for (i = 0; i < ITERATIONS; i ++) { static uint32_t ip_batch[BATCH_SIZE]; uint16_t next_hops[BULK_SIZE]; /* Create array of random IP addresses */ for (j = 0; j < BATCH_SIZE; j ++) ip_batch[j] = rte_rand(); /* Lookup per batch */ begin = rte_rdtsc(); for (j = 0; j < BATCH_SIZE; j += BULK_SIZE) { unsigned k; rte_lpm_lookup_bulk(lpm, &ip_batch[j], next_hops, BULK_SIZE); for (k = 0; k < BULK_SIZE; k++) if (unlikely(!(next_hops[k] & RTE_LPM_LOOKUP_SUCCESS))) count++; } total_time += rte_rdtsc() - begin; } printf("BULK LPM Lookup: %.1f cycles (fails = %.1f%%)\n", (double)total_time / ((double)ITERATIONS * BATCH_SIZE), (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE)); /* Measure LookupX4 */ total_time = 0; count = 0; for (i = 0; i < ITERATIONS; i++) { static uint32_t ip_batch[BATCH_SIZE]; uint16_t next_hops[4]; /* Create array of random IP addresses */ for (j = 0; j < BATCH_SIZE; j++) ip_batch[j] = rte_rand(); /* Lookup per batch */ begin = rte_rdtsc(); for (j = 0; j < BATCH_SIZE; j += RTE_DIM(next_hops)) { unsigned k; __m128i ipx4; ipx4 = _mm_loadu_si128((__m128i *)(ip_batch + j)); ipx4 = *(__m128i *)(ip_batch + j); rte_lpm_lookupx4(lpm, ipx4, next_hops, UINT16_MAX); for (k = 0; k < RTE_DIM(next_hops); k++) if (unlikely(next_hops[k] == UINT16_MAX)) count++; } total_time += rte_rdtsc() - begin; } printf("LPM LookupX4: %.1f cycles (fails = %.1f%%)\n", (double)total_time / ((double)ITERATIONS * BATCH_SIZE), (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE)); /* Delete */ status = 0; begin = rte_rdtsc(); for (i = 0; i < NUM_ROUTE_ENTRIES; i++) { /* rte_lpm_delete(lpm, ip, depth) */ status += rte_lpm_delete(lpm, large_route_table[i].ip, large_route_table[i].depth); } total_time += rte_rdtsc() - begin; printf("Average LPM Delete: %g cycles\n", (double)total_time / NUM_ROUTE_ENTRIES); rte_lpm_delete_all(lpm); rte_lpm_free(lpm); return PASS; }
int add_staticroute(struct route_table *route_table){ char str[60]; char *network, *netmask, *nexthop; struct in_addr addr; uint32_t ipaddr; uint8_t depth; uint8_t key; FILE *fp = fopen("./routes.txt","r"); if(fp==NULL){ printf("cannot open a file\n"); return 1; } printf("file open\n"); fgets(str,20,fp); while(str[0] == '\n') fgets(str, 20, fp); if(strcmp(str,"interface\n") != 0){ printf("invalid file format\n"); return 1; } printf("reading interface\n"); int i; for(i=0; i<4 ;i++){ fgets(str, 50, fp); network = strtok(str," "); //ignore portXX network = strtok(NULL," "); inet_aton(network,&addr); netmask = strtok(NULL, " "); netmask = strtok(netmask, "\n"); inet_aton(network,&addr); port2ip[i][0] = ntohl(addr.s_addr); inet_aton(netmask,&addr); port2ip[i][1] = ntohl(addr.s_addr); } fgets(str,20,fp); while(str[0] == '\n') fgets(str, 20, fp); if(strcmp(str,"route\n") != 0){ printf("invalid file format\n"); return 1; } printf("reading route\n"); while(fgets(str,60,fp) != NULL){ network = strtok(str," "); netmask = strtok(NULL, " "); nexthop = strtok(NULL, " "); nexthop = strtok(nexthop, "\n"); printf("network : %s\n", network); printf("netmask : %s\n", netmask); printf("nexthop : %s\n", nexthop); //make hash of nexthop inet_aton(nexthop,&addr); ipaddr = ntohl(addr.s_addr); key = rte_hash_add_key(route_table->key2nexthop, &ipaddr); //get depth from netmask inet_aton(netmask,&addr); ipaddr = ntohl(addr.s_addr); // int i; // for(i=31; i>=0; i--) // if(ipaddr & (0x00000001 << i) == 0) break; // depth = 32-(i+1); depth = 24; //add route to lpm inet_aton(network,&addr); ipaddr = ntohl(addr.s_addr); if(rte_lpm_add(route_table->lpm, ipaddr, depth, key) <= 0) printf("lpm_add failed\n\n"); } fclose(fp); return 0; }