2 // Copyright (c) 2017 Intel Corporation
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
17 #include "l3fwd_common.h"
18 #include "interface.h"
20 #include "l3fwd_lpm4.h"
21 #include "l3fwd_lpm6.h"
23 #include "lib_icmpv6.h"
26 /* Declare Global variables */
29 void *lpm4_table; /**< lpm4_table handler */
31 /*Hash table for L2 adjacency */
32 struct rte_hash *l2_adj_hash_handle; /**< l2 adjacency hash table handler */
33 struct rte_hash *fib_path_hash_handle; /**< fib path hash table handler */
35 l3_stats_t stats; /**< L3 statistics */
37 /* Global load balancing hash table for ECMP*/
38 uint8_t nh_links[MAX_SUPPORTED_FIB_PATHS][HASH_BUCKET_SIZE] = /**< Round Robin Hash entries for ECMP only*/
40 /* 1 path, No Load balancing is required */
44 {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
45 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
46 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
47 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1},
50 {0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0,
51 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1,
52 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2,
53 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0},
56 {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
57 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
58 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,
59 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3},
62 {0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0,
63 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1,
64 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2,
65 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3},
68 {0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3,
69 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1,
70 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5,
71 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3},
74 {0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1,
75 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3,
76 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5,
77 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0},
80 {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
81 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
82 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
83 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7}
87 #define META_DATA_OFFSET 128
89 #define RTE_PKTMBUF_HEADROOM 128 /* where is this defined ? */
90 #define ETHERNET_START (META_DATA_OFFSET + RTE_PKTMBUF_HEADROOM)
91 #define ETH_HDR_SIZE 14
92 #define IP_START (ETHERNET_START + ETH_HDR_SIZE)
93 #define TCP_START (IP_START + 20)
95 static void print_pkt(struct rte_mbuf *pkt)
99 uint8_t *rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, ETHERNET_START);
101 printf("Meta-data:\n");
102 for (i = 0; i < size; i++) {
103 printf("%02x ", rd[i]);
108 printf("IP and TCP/UDP headers:\n");
109 rd = RTE_MBUF_METADATA_UINT8_PTR(pkt, IP_START);
110 for (i = 0; i < 40; i++) {
111 printf("%02x ", rd[i]);
118 static struct ip_protocol_type *proto_type[2];
122 /* Initiliaze LPMv4 params */
123 struct rte_table_lpm_params lpm_params = {
125 .n_rules = IPV4_L3FWD_LPM_MAX_RULES,
126 .number_tbl8s = IPV4_L3FWD_LPM_NUMBER_TBL8S,
128 .entry_unique_size = sizeof(struct fib_info),
132 /* Create LPMv4 tables */
134 rte_table_lpm_ops.f_create(&lpm_params, rte_socket_id(),
135 sizeof(struct fib_info));
136 if (lpm4_table == NULL) {
137 printf("Failed to create LPM IPV4 table\n");
141 /*Initialize L2 ADJ hash params */
142 struct rte_hash_parameters l2_adj_ipv4_params = {
143 .name = "l2_ADJ_HASH",
145 .key_len = sizeof(struct l2_adj_key_ipv4),
146 .hash_func = rte_jhash,
147 .hash_func_init_val = 0,
150 /* Create IPv4 L2 Adj Hash tables */
151 l2_adj_hash_handle = rte_hash_create(&l2_adj_ipv4_params);
153 if (l2_adj_hash_handle == NULL) {
154 printf("L2 ADJ rte_hash_create failed\n");
157 printf("l2_adj_hash_handle %p\n\n", (void *)l2_adj_hash_handle);
160 /*Initialize Fib PAth hassh params */
161 struct rte_hash_parameters fib_path_ipv4_params = {
162 .name = "FIB_PATH_HASH",
164 .key_len = sizeof(struct fib_path_key_ipv4),
165 .hash_func = rte_jhash,
166 .hash_func_init_val = 0,
169 /* Create FIB PATH Hash tables */
170 fib_path_hash_handle = rte_hash_create(&fib_path_ipv4_params);
172 if (fib_path_hash_handle == NULL) {
173 printf("FIB path rte_hash_create failed\n");
179 int lpm4_table_route_add(struct routing_info *data)
182 struct routing_info *fib = data;
183 struct rte_table_lpm_key lpm_key = {
184 .ip = fib->dst_ip_addr,
188 static int Total_route_count;
189 struct fib_info entry;
190 entry.dst_ip_addr = rte_bswap32(fib->dst_ip_addr);
191 entry.depth = fib->depth;
192 entry.fib_nh_size = fib->fib_nh_size; /**< For Single Path, greater then 1 for Multipath(ECMP)*/
195 if (entry.fib_nh_size == 0 || entry.fib_nh_size > MAX_FIB_PATHS)
197 if (entry.fib_nh_size != 1) /**< For Single FIB_PATH */
200 printf("Route can't be configured!!, entry.fib_nh_size = %d\n",
204 /* Populate L2 adj and precomputes l2 encap string */
206 for (i = 0; i < entry.fib_nh_size; i++)
208 for (i = 0; i < 1; i++)
211 struct fib_path *fib_path_addr = NULL;
214 populate_fib_path(fib->nh_ip_addr[i], fib->out_port[i]);
217 entry.path[i] = fib_path_addr;
218 printf("Fib info for the Dest IP");
219 printf(" : %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32
221 " => fib_path Addr: %p, l2_adj Addr: %p\n",
222 (fib->dst_ip_addr & 0xFF000000) >> 24,
223 (fib->dst_ip_addr & 0x00FF0000) >> 16,
224 (fib->dst_ip_addr & 0x0000FF00) >> 8,
225 (fib->dst_ip_addr & 0x000000FF), fib->depth,
227 (void *)entry.path[i]->l2_adj_ptr);
229 printf("Fib info for the Dest IP :\
230 %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 "/%" PRIu8 " => fib_path Addr: NULL \n", (fib->dst_ip_addr & 0xFF000000) >> 24, (fib->dst_ip_addr & 0x00FF0000) >> 16, (fib->dst_ip_addr & 0x0000FF00) >> 8, (fib->dst_ip_addr & 0x000000FF), fib->depth);
231 entry.path[i] = NULL; /**< setting all other fib_paths to NULL */
238 rte_table_lpm_ops.f_add(lpm4_table, (void *)&lpm_key, &entry,
239 &key_found, &entry_ptr);
242 printf("Failed to Add IP route\n");
246 printf("Total Routed Added : %u, Key_found: %d\n", Total_route_count,
248 printf("Adding Route to LPM table...\n");
250 printf("Iterate with Cuckoo Hash table\n");
251 iterate_cuckoo_hash_table();
255 int lpm4_table_route_delete(uint32_t dst_ip, uint8_t depth)
258 struct rte_table_lpm_key lpm_key = {
266 entry = rte_zmalloc(NULL, 512, RTE_CACHE_LINE_SIZE);
268 /* Deleting a IP route from LPMv4 table */
270 rte_table_lpm_ops.f_delete(lpm4_table, &lpm_key, &key_found, entry);
273 printf("Failed to Delete IP route from LPMv4 table\n");
277 printf("Deleted route from LPM table (IPv4 Address = %"
278 PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32
279 "/%u , key_found = %d\n", (lpm_key.ip & 0xFF000000) >> 24,
280 (lpm_key.ip & 0x00FF0000) >> 16, (lpm_key.ip & 0x0000FF00) >> 8,
281 (lpm_key.ip & 0x000000FF), lpm_key.depth, key_found);
283 /* Deleting a L2 Adj entry if refcount is 1, Else decrement Refcount */
284 remove_fib_l2_adj_entry(entry);
286 printf("Iterate with Cuckoo Hash table\n");
287 iterate_cuckoo_hash_table();
292 lpm4_table_lookup(struct rte_mbuf **pkts_burst, uint16_t nb_pkts,
294 l2_phy_interface_t *port_ptr[RTE_PORT_IN_BURST_SIZE_MAX],
298 struct routing_table_entry *ipv4_entries[RTE_PORT_IN_BURST_SIZE_MAX];
299 uint64_t lookup_hit_mask_ipv4 = 0;
301 uint64_t pkts_key_mask = pkts_mask;
302 uint64_t lookup_miss_mask_ipv4 = pkts_mask;
304 static uint64_t sent_count;
305 static uint64_t rcvd_count;
306 rcvd_count += nb_pkts;
309 (" Received IPv4 nb_pkts: %u, Rcvd_count: %lu\n, pkts_mask: %p\n",
310 nb_pkts, rcvd_count, (void *)pkts_mask);
312 uint32_t dst_addr_offset =
313 MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST;
315 for (; pkts_key_mask;) {
316 /**< Populate key offset in META DATA for all valid pkts */
317 uint8_t pos = (uint8_t) __builtin_ctzll(pkts_key_mask);
318 uint64_t pkt_mask = 1LLU << pos;
319 pkts_key_mask &= ~pkt_mask;
320 struct rte_mbuf *mbuf = pkts_burst[pos];
321 uint32_t *lpm_key = NULL;
322 uint32_t *dst_addr = NULL;
323 lpm_key = (uint32_t *) RTE_MBUF_METADATA_UINT8_PTR(mbuf, 128);
325 (uint32_t *) RTE_MBUF_METADATA_UINT8_PTR(mbuf,
327 *lpm_key = *dst_addr;
330 printf("Rcvd Pakt (IPv4 Address = %"
331 PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32 ")\n",
332 (rte_cpu_to_be_32(*lpm_key) & 0xFF000000) >> 24,
333 (rte_cpu_to_be_32(*lpm_key) & 0x00FF0000) >> 16,
334 (rte_cpu_to_be_32(*lpm_key) & 0x0000FF00) >> 8,
335 (rte_cpu_to_be_32(*lpm_key) & 0x000000FF));
339 /* Lookup for IP route in LPM table */
341 printf("\nIPV4 Lookup Mask Before = %p\n",
342 (void *)lookup_hit_mask_ipv4);
344 rte_table_lpm_ops.f_lookup(lpm4_table, pkts_burst, pkts_mask,
345 &lookup_hit_mask_ipv4,
346 (void **)ipv4_entries);
349 printf("LPM Lookup failed for IP route\n");
353 lookup_miss_mask_ipv4 = lookup_miss_mask_ipv4 & (~lookup_hit_mask_ipv4);
356 ("AFTER lookup_hit_mask_ipv4 = %p, lookup_miss_mask_ipv4 =%p\n",
357 (void *)lookup_hit_mask_ipv4,
358 (void *)lookup_miss_mask_ipv4);
361 for (; lookup_miss_mask_ipv4;) {
362 /**< Drop packets for lookup_miss_mask */
363 uint8_t pos = (uint8_t) __builtin_ctzll(lookup_miss_mask_ipv4);
364 uint64_t pkt_mask = 1LLU << pos;
365 lookup_miss_mask_ipv4 &= ~pkt_mask;
366 rte_pktmbuf_free(pkts_burst[pos]);
367 pkts_burst[pos] = NULL;
368 stats.nb_l3_drop_pkt++; /**< Peg the L3 Drop counter */
370 printf("\n DROP PKT IPV4 Lookup_miss_Mask = %p\n",
371 (void *)lookup_miss_mask_ipv4);
374 *hit_mask = lookup_hit_mask_ipv4;
375 for (; lookup_hit_mask_ipv4;) {
376 /**< Process the packets for lookup_hit_mask*/
377 uint8_t pos = (uint8_t) __builtin_ctzll(lookup_hit_mask_ipv4);
378 uint64_t pkt_mask = 1LLU << pos;
379 lookup_hit_mask_ipv4 &= ~pkt_mask;
380 struct rte_mbuf *pkt = pkts_burst[pos];
382 struct fib_info *entry = (struct fib_info *)ipv4_entries[pos];
386 uint8_t ecmp_path = 0;
387 ecmp_path = ip_hash_load_balance(pkts_burst[pos]);
388 uint8_t selected_path = 0;
389 struct fib_path *fib_path = NULL;
390 if (((entry->fib_nh_size != 0)
391 && (entry->fib_nh_size - 1) < MAX_SUPPORTED_FIB_PATHS)
392 && ((ecmp_path != 0) && (ecmp_path - 1) < HASH_BUCKET_SIZE))
394 nh_links[entry->fib_nh_size - 1][ecmp_path - 1];
395 if (selected_path < MAX_FIB_PATHS)
396 fib_path = entry->path[selected_path];
399 ("Total supported Path :%u, Hashed ECMP Key : %u, selected Fib_path: %u\n",
400 entry->fib_nh_size, ecmp_path, selected_path);
403 struct fib_path *fib_path = entry->path[0];
406 if (fib_path == NULL) {
407 rte_pktmbuf_free(pkt);
408 pkts_burst[pos] = NULL;
409 stats.nb_l3_drop_pkt++; /**< Peg the L3 Drop counter */
410 *hit_mask &= ~pkt_mask; /**< Remove this pkt from port Mask */
413 ("Fib_path is NULL, ARP has not resolved, DROPPED UNKNOWN PKT\n");
417 if (fib_path->l2_adj_ptr->flags == L2_ADJ_UNRESOLVED) {
418 if (fib_path->l2_adj_ptr->phy_port->ipv4_list != NULL)
419 request_arp(fib_path->l2_adj_ptr->phy_port->
420 pmdid, fib_path->nh_ip);
422 rte_pktmbuf_free(pkts_burst[pos]);
423 pkts_burst[pos] = NULL;
424 *hit_mask &= ~pkt_mask; /**< Remove this pkt from port Mask */
427 ("L2_ADJ_UNRESOLVED, DROPPED UNKNOWN PKT\n");
431 /* extract ip headers and MAC */
433 RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM);
435 RTE_MBUF_METADATA_UINT8_PTR(pkt, MBUF_HDR_ROOM + 6);
438 ("MAC BEFORE- DST MAC %02x:%02x:%02x:%02x:%02x:%02x, \
439 SRC MAC %02x:%02x:%02x:%02x:%02x:%02x \n",
440 eth_dest[0], eth_dest[1], eth_dest[2], eth_dest[3], eth_dest[4], eth_dest[5], eth_src[0], eth_src[1],
441 eth_src[2], eth_src[3], eth_src[4], eth_src[5]);
443 /* Rewrite the packet with L2 string */
444 memcpy(eth_dest, fib_path->l2_adj_ptr->l2_string, sizeof(struct ether_addr) * 2); // For MAC
447 for (k = 0; k < 14; k++) {
449 fib_path->l2_adj_ptr->l2_string[k]);
453 ("MAC AFTER DST MAC %02x:%02x:%02x:%02x:%02x:%02x, \
454 SRC MAC %02x:%02x:%02x:%02x:%02x:%02x\n", eth_dest[0], eth_dest[1], eth_dest[2], eth_dest[3], eth_dest[4], eth_dest[5], eth_src[0], eth_src[1], eth_src[2], eth_src[3], eth_src[4], eth_src[5]);
456 port_ptr[pos] = fib_path->l2_adj_ptr->phy_port;
458 printf("l3fwd_lookup API!!!!\n");
463 stats.nb_tx_l3_pkt++;
466 ("Successfully sent to port %u, sent_count : %lu\n\r",
467 fib_path->out_port, sent_count);
472 int is_valid_ipv4_pkt(struct ipv4_hdr *pkt, uint32_t link_len)
474 if (link_len < sizeof(struct ipv4_hdr))
476 if (((pkt->version_ihl) >> 4) != 4)
478 if ((pkt->version_ihl & 0xf) < 5)
480 if (rte_cpu_to_be_16(pkt->total_length) < sizeof(struct ipv4_hdr))
486 get_dest_mac_for_nexthop(uint32_t next_hop_ip,
487 uint8_t out_phy_port, struct ether_addr *hw_addr)
489 struct arp_entry_data *arp_data = NULL;
490 struct arp_key_ipv4 arp_key;
491 arp_key.port_id = out_phy_port;
492 arp_key.ip = next_hop_ip;
494 arp_data = retrieve_arp_entry(arp_key);
495 if (arp_data == NULL) {
496 printf("ARP entry is not found for ip %x, port %d\n",
497 next_hop_ip, out_phy_port);
500 ether_addr_copy(&arp_data->eth_addr, hw_addr);
504 struct l2_adj_entry *retrieve_l2_adj_entry(struct l2_adj_key_ipv4 l2_adj_key)
506 struct l2_adj_entry *ret_l2_adj_data = NULL;
507 l2_adj_key.filler1 = 0;
508 l2_adj_key.filler2 = 0;
509 l2_adj_key.filler3 = 0;
512 rte_hash_lookup_data(l2_adj_hash_handle, &l2_adj_key,
513 (void **)&ret_l2_adj_data);
517 ("L2 Adj hash lookup failed ret %d, EINVAL %d, ENOENT %d\n",
518 ret, EINVAL, ENOENT);
524 ("L2 Adj hash lookup Success, Entry Already Exist ret %d, EINVAL %d, ENOENT %d\n",
525 ret, EINVAL, ENOENT);
527 return ret_l2_adj_data;
531 void remove_fib_l2_adj_entry(void *entry)
533 struct fib_info entry1;
534 memcpy(&entry1, entry, sizeof(struct fib_info));
536 struct fib_path *fib_path_addr = entry1.path[0]; /**< For Single path */
537 if (fib_path_addr->refcount > 1) {
539 (" BEFORE fib_path entry, nh_ip %x, port %d, refcount %d\n",
540 fib_path_addr->nh_ip, fib_path_addr->out_port,
541 fib_path_addr->refcount);
542 fib_path_addr->refcount--; /**< Just decrement the refcount this entry is still referred*/
543 printf("AFTER fib_path entry, nh_ip %x, port %d, refcount %d\n",
544 fib_path_addr->nh_ip, fib_path_addr->out_port,
545 fib_path_addr->refcount);
547 /**< Refcount is 1 so delete both fib_path and l2_adj_entry */
549 struct l2_adj_entry *adj_addr = NULL;
550 adj_addr = fib_path_addr->l2_adj_ptr;
552 if (adj_addr != NULL) {
553 /** < l2_adj_entry is has some entry in hash table*/
554 struct l2_adj_key_ipv4 l2_adj_key = {
555 .Next_hop_ip = fib_path_addr->nh_ip,
556 .out_port_id = fib_path_addr->out_port,
560 (" l2_adj_entry is removed for ip %x, port %d, refcount %d\n",
561 l2_adj_key.Next_hop_ip, l2_adj_key.out_port_id,
565 rte_hash_del_key(l2_adj_hash_handle, &l2_adj_key);
566 rte_free(adj_addr); /**< free the memory which was allocated for Hash entry */
570 struct fib_path_key_ipv4 path_key = {
571 .nh_ip = fib_path_addr->nh_ip,
572 .out_port = fib_path_addr->out_port,
576 ("fib_path entry is removed for ip %x, port %d, refcount %d\n",
577 fib_path_addr->nh_ip, fib_path_addr->out_port,
578 fib_path_addr->refcount);
579 rte_hash_del_key(fib_path_hash_handle, &path_key);
580 rte_free(fib_path_addr); /**< Free the memory which was allocated for Hash entry*/
581 fib_path_addr = NULL;
585 struct l2_adj_entry *populate_l2_adj(uint32_t ipaddr, uint8_t portid)
588 struct l2_adj_key_ipv4 l2_adj_key;
589 l2_adj_key.out_port_id = portid;
590 l2_adj_key.Next_hop_ip = ipaddr;
591 l2_adj_key.filler1 = 0;
592 l2_adj_key.filler2 = 0;
593 l2_adj_key.filler3 = 0;
595 struct ether_addr eth_dst;
596 struct l2_adj_entry *adj_data = NULL;
598 /* Populate L2 adj if the MAC Address is already present in L2 Adj HAsh Table */
599 adj_data = retrieve_l2_adj_entry(l2_adj_key);
601 if (adj_data) { /**< L2 Adj Entry Exists*/
604 ("l2_adj_entry exists ip%x, port %d, Refcnt :%u Address :%p\n",
605 l2_adj_key.Next_hop_ip, l2_adj_key.out_port_id,
606 adj_data->refcount, adj_data);
607 ether_addr_copy(&adj_data->eth_addr, ð_dst);
608 adj_data->refcount++;
610 ("l2_adj_entry UPDATED Refcount for NH ip%x, port %d, Refcnt :%u Address :%p\n",
611 l2_adj_key.Next_hop_ip, l2_adj_key.out_port_id,
612 adj_data->refcount, adj_data);
616 struct ether_addr eth_src;
617 l2_phy_interface_t *port;
618 //uint16_t ether_type = 0x0800;
619 port = ifm_get_port(portid);
622 memcpy(ð_src, &port->macaddr, sizeof(struct ether_addr));
623 unsigned char *p = (unsigned char *)eth_src.addr_bytes;
624 printf("S-MAC %x:%x:%x:%x:%x:%x\n\r", p[0], p[1], p[2], p[3],
628 RTE_CACHE_LINE_ROUNDUP(sizeof(struct l2_adj_entry));
629 adj_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
630 if (adj_data == NULL) {
631 printf("L2 Adjacency memory allocation failed !\n");
635 adj_data->out_port_id = portid;
636 adj_data->Next_hop_ip = ipaddr;
637 adj_data->refcount++;
639 adj_data->phy_port = port;
640 memset(&adj_data->eth_addr, 0, sizeof(struct ether_addr));
641 memset(&adj_data->l2_string, 0, 256);
643 /**< Store the received MAC Address in L2 Adj HAsh Table */
644 rte_hash_add_key_data(l2_adj_hash_handle, &l2_adj_key,
648 ("L2 adj data stored in l2_adj_entry hash table,Addr:%p\n",
653 printf("\n PORT %u IS DOWN...\n", portid);
657 /* Query ARP to get L2 Adj */
658 if (get_dest_mac_for_nexthop(ipaddr, portid, ð_dst)) {
659 unsigned char *p = (unsigned char *)eth_dst.addr_bytes;
661 ("ARP resolution success and stored in l2_adj_entry hash table:D-MAC %x:%x:%x:%x:%x:%x\n\r",
662 p[0], p[1], p[2], p[3], p[4], p[5]);
664 memcpy(adj_data->l2_string, ð_dst, sizeof(struct ether_addr)); //** < Precompute the L2 String encap*/
665 memcpy(&adj_data->l2_string[6], ð_src,
666 sizeof(struct ether_addr));
667 //memcpy(&adj_data->l2_string[12], ðer_type, 2);
669 ether_addr_copy(ð_dst, &adj_data->eth_addr);
670 adj_data->flags = L2_ADJ_RESOLVED;
672 adj_data->flags = L2_ADJ_UNRESOLVED;
674 (" ARP resolution Failed !! , unable to write in l2_adj_entry\n");
679 struct fib_path *populate_fib_path(uint32_t nh_ip, uint8_t portid)
682 struct fib_path_key_ipv4 path_key;
683 path_key.out_port = portid;
684 path_key.nh_ip = nh_ip;
685 path_key.filler1 = 0;
686 path_key.filler2 = 0;
687 path_key.filler3 = 0;
689 struct fib_path *fib_data = NULL;
691 /* Populate fib_path */
692 fib_data = retrieve_fib_path_entry(path_key);
694 if (fib_data) {/**< fib_path entry already exists */
696 /* Already present in FIB_PATH cuckoo HAsh Table */
698 ("fib_path_entry already exists for NextHop ip: %x, port %d\n, Refcount %u Addr:%p\n",
699 fib_data->nh_ip, fib_data->out_port, fib_data->refcount,
701 fib_data->refcount++;
702 fib_data->l2_adj_ptr->refcount++;
704 ("fib_path Refcount Updated NextHop :%x , port %u, Refcount %u\n\r",
705 fib_data->nh_ip, fib_data->out_port, fib_data->refcount);
708 printf("fib_path entry Doesn't Exists.......\n");
712 struct l2_adj_entry *l2_adj_ptr = NULL;
713 l2_adj_ptr = populate_l2_adj(nh_ip, portid);
717 uint32_t size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct fib_path));
718 fib_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
720 fib_data->out_port = portid;
721 fib_data->nh_ip = nh_ip;
722 fib_data->refcount++;
723 fib_data->l2_adj_ptr = l2_adj_ptr;
725 printf("%s: get port details %u %d\n\r", __FUNCTION__, portid,
727 /* Store the received MAC Address in L2 Adj HAsh Table */
730 rte_hash_add_key_data(fib_path_hash_handle, &path_key,
734 ("fib_path entry addition to hash table FAILED!! NextHop :%x , port %u, Refcount %u\n\r",
735 fib_data->nh_ip, fib_data->out_port,
741 ("fib_path entry Added into hash table for the NextHop :%x , port %u, Refcount %u\n\r",
742 fib_data->nh_ip, fib_data->out_port,
745 (" l2_adj_entry Addr: %p, Fib_path Addr: %p, FibPath->l2ADJ Addr:%p \n",
746 l2_adj_ptr, fib_data, fib_data->l2_adj_ptr);
748 (" ARP resolution success l2_adj_entry Addr: %p, Fib_path Addr: %p \n",
749 l2_adj_ptr, fib_data);
754 (" ARP resolution failed and unable to write fib path in fib_path cuckoo hash\n");
759 struct fib_path *retrieve_fib_path_entry(struct fib_path_key_ipv4 path_key)
761 printf("FIB PATH for NExtHOP IP : %x, port :%u\n", path_key.nh_ip,
764 struct fib_path *ret_fib_path_data = NULL;
766 rte_hash_lookup_data(fib_path_hash_handle, &path_key,
767 (void **)&ret_fib_path_data);
770 ("FIB PATH hash lookup Failed!! ret %d, EINVAL %d, ENOENT %d\n",
771 ret, EINVAL, ENOENT);
774 printf("FIB PATH ALREADY Exists for NExtHOP IP: %x, port: %u\n",
775 path_key.nh_ip, path_key.out_port);
776 return ret_fib_path_data;
780 void iterate_cuckoo_hash_table(void)
782 const void *next_key;
786 printf("\n\t\t\t FIB_path Cache table....");
788 ("\n----------------------------------------------------------------");
789 printf("\n\tNextHop IP Port Refcount l2_adj_ptr_addrress\n");
791 ("\n----------------------------------------------------------------\n");
793 while (rte_hash_iterate
794 (fib_path_hash_handle, &next_key, &next_data, &iter) >= 0) {
795 struct fib_path *tmp_data = (struct fib_path *)next_data;
796 struct fib_path_key_ipv4 tmp_key;
797 memcpy(&tmp_key, next_key, sizeof(tmp_key));
798 printf("\t %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32
799 " \t %u \t %u \t %p\n",
800 (tmp_data->nh_ip & 0xFF000000) >> 24,
801 (tmp_data->nh_ip & 0x00FF0000) >> 16,
802 (tmp_data->nh_ip & 0x0000FF00) >> 8,
803 (tmp_data->nh_ip & 0x000000FF), tmp_data->out_port,
804 tmp_data->refcount, tmp_data->l2_adj_ptr);
809 printf("\n\t\t\t L2 ADJ Cache table.....");
811 ("\n------------------------------------------------------------------------------------");
813 ("\n\tNextHop IP Port \t l2 Encap string \t l2_Phy_interface\n");
815 ("\n------------------------------------------------------------------------------------\n");
817 while (rte_hash_iterate
818 (l2_adj_hash_handle, &next_key, &next_data, &iter) >= 0) {
819 struct l2_adj_entry *l2_data = (struct l2_adj_entry *)next_data;
820 struct l2_adj_key_ipv4 l2_key;
821 memcpy(&l2_key, next_key, sizeof(l2_key));
822 printf("\t %" PRIu32 ".%" PRIu32 ".%" PRIu32 ".%" PRIu32
823 "\t %u \t%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x\t%p\n",
824 (l2_data->Next_hop_ip & 0xFF000000) >> 24,
825 (l2_data->Next_hop_ip & 0x00FF0000) >> 16,
826 (l2_data->Next_hop_ip & 0x0000FF00) >> 8,
827 (l2_data->Next_hop_ip & 0x000000FF),
828 l2_data->out_port_id, l2_data->l2_string[0],
829 l2_data->l2_string[1], l2_data->l2_string[2],
830 l2_data->l2_string[3], l2_data->l2_string[4],
831 l2_data->l2_string[5], l2_data->l2_string[6],
832 l2_data->l2_string[7], l2_data->l2_string[8],
833 l2_data->l2_string[9], l2_data->l2_string[10],
834 l2_data->l2_string[11], l2_data->phy_port);
838 void print_l3_stats(void)
840 printf("==============================================\n");
841 printf("\t\t L3 STATISTICS \t\n");
842 printf("==============================================\n");
843 printf(" Num of Received L3 Pkts : %lu\n", stats.nb_rx_l3_pkt);
844 printf(" Num of Dropped L3 Pkts : %lu\n", stats.nb_l3_drop_pkt);
845 printf(" Num of Transmitted L3 Pkts : %lu\n", stats.nb_tx_l3_pkt);
846 printf(" Num of ICMP Pkts Rcvd at L3 : %lu\n", stats.nb_rx_l3_icmp_pkt);
847 printf(" Num of ICMP Pkts Tx to ICMP : %lu\n", stats.nb_tx_l3_icmp_pkt);
848 stats.total_nb_rx_l3_pkt = stats.nb_rx_l3_icmp_pkt + stats.nb_rx_l3_pkt;
849 stats.total_nb_tx_l3_pkt = stats.nb_tx_l3_icmp_pkt + stats.nb_tx_l3_pkt;
850 printf(" Total Num of Rcvd pkts at L3: %lu\n",
851 stats.total_nb_rx_l3_pkt);
852 printf(" Total Num of Sent pkts at L3: %lu\n",
853 stats.total_nb_tx_l3_pkt);
857 ip_local_packets_process(struct rte_mbuf **pkt_burst, uint16_t nb_rx,
858 uint64_t icmp_pkt_mask, l2_phy_interface_t *port)
860 process_arpicmp_pkt_parse(pkt_burst, nb_rx, icmp_pkt_mask, port);
864 ip_forward_deliver(struct rte_mbuf **pkt_burst, uint16_t nb_pkts,
865 uint64_t ipv4_forward_pkts_mask, l2_phy_interface_t *port)
869 ("ip_forward_deliver BEFORE DROP: nb_pkts: %u\n from in_port %u",
870 nb_pkts, port->pmdid);
872 uint64_t pkts_for_process = ipv4_forward_pkts_mask;
874 struct ipv4_hdr *ipv4_hdr;
875 l2_phy_interface_t *port_ptr[RTE_PORT_IN_BURST_SIZE_MAX];
876 uint64_t hit_mask = 0;
878 for (; pkts_for_process;) {
879 /**< process only valid packets.*/
880 uint8_t pos = (uint8_t) __builtin_ctzll(pkts_for_process);
881 uint64_t pkt_mask = 1LLU << pos; /**< bitmask representing only this packet */
882 pkts_for_process &= ~pkt_mask; /**< remove this packet from the mask */
884 rte_pktmbuf_mtod_offset(pkt_burst[pos], struct ipv4_hdr *,
885 sizeof(struct ether_hdr));
886 /* Make sure the IPv4 packet is valid */
887 if (is_valid_ipv4_pkt(ipv4_hdr, pkt_burst[pos]->pkt_len) < 0) {
888 rte_pktmbuf_free(pkt_burst[pos]); /**< Drop the Unknown IPv4 Packet */
889 pkt_burst[pos] = NULL;
890 ipv4_forward_pkts_mask &= ~(1LLU << pos); /**< That will clear bit of that position*/
892 stats.nb_l3_drop_pkt++;
898 ("\nl3fwd_rx_ipv4_packets_received AFTER DROP: nb_pkts: %u, valid_Pkts_mask :%lu\n",
899 nb_pkts, ipv4_forward_pkts_mask);
902 /* Lookup for IP destination in LPMv4 table */
903 lpm4_table_lookup(pkt_burst, nb_pkts, ipv4_forward_pkts_mask, port_ptr,
907 /**< process only valid packets.*/
908 uint8_t pos = (uint8_t) __builtin_ctzll(hit_mask);
909 uint64_t pkt_mask = 1LLU << pos; /**< bitmask representing only this packet */
910 hit_mask &= ~pkt_mask; /**< remove this packet from the mask */
912 port_ptr[pos]->transmit_single_pkt(port_ptr[pos],
919 l3_protocol_type_add(uint8_t protocol_type,
920 void (*func) (struct rte_mbuf **, uint16_t, uint64_t,
921 l2_phy_interface_t *port))
923 switch (protocol_type) {
925 proto_type[IP_LOCAL] =
926 rte_malloc(NULL, sizeof(struct ip_protocol_type),
927 RTE_CACHE_LINE_SIZE);
928 proto_type[IP_LOCAL]->protocol_type = protocol_type;
929 proto_type[IP_LOCAL]->func = func;
932 case IPPROTO_TCP: // Time being treared as Remote forwarding
934 proto_type[IP_REMOTE] =
935 rte_malloc(NULL, sizeof(struct ip_protocol_type),
936 RTE_CACHE_LINE_SIZE);
937 proto_type[IP_REMOTE]->protocol_type = protocol_type;
938 proto_type[IP_REMOTE]->func = func;
945 void l3fwd_rx_ipv4_packets(struct rte_mbuf **m, uint16_t nb_pkts,
946 uint64_t valid_pkts_mask, l2_phy_interface_t *port)
950 ("l3fwd_rx_ipv4_packets_received BEFORE DROP: nb_pkts: %u\n from in_port %u",
951 nb_pkts, port->pmdid);
953 uint64_t pkts_for_process = valid_pkts_mask;
955 struct ipv4_hdr *ipv4_hdr;
956 uint32_t configure_port_ip = 0;
957 uint64_t icmp_pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
958 uint64_t ipv4_forward_pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
959 uint16_t nb_icmp_pkt = 0;
960 uint16_t nb_l3_pkt = 0;
962 if (port->ipv4_list != NULL)
964 (uint32_t) (((ipv4list_t *) (port->ipv4_list))->ipaddr);
966 for (; pkts_for_process;) {
967 /**< process only valid packets.*/
968 uint8_t pos = (uint8_t) __builtin_ctzll(pkts_for_process);
969 uint64_t pkt_mask = 1LLU << pos; /**< bitmask representing only this packet */
970 pkts_for_process &= ~pkt_mask; /**< remove this packet from the mask */
972 rte_pktmbuf_mtod_offset(m[pos], struct ipv4_hdr *,
973 sizeof(struct ether_hdr));
975 if ((ipv4_hdr->next_proto_id == IPPROTO_ICMP)
976 && (ipv4_hdr->dst_addr == configure_port_ip)) {
977 ipv4_forward_pkts_mask &= ~pkt_mask; /**< Its ICMP, remove this packet from the ipv4_forward_pkts_mask*/
978 stats.nb_rx_l3_icmp_pkt++; /**< Increment stats for ICMP PKT */
980 } else{ // Forward the packet
981 icmp_pkts_mask &= ~pkt_mask; /**< Not ICMP, remove this packet from the icmp_pkts_mask*/
982 stats.nb_rx_l3_pkt++;
983 nb_l3_pkt++; /**< Increment stats for L3 PKT */
987 if (icmp_pkts_mask) {
990 ("\n RECEiVED LOCAL ICMP PKT at L3...\n PROCESSING ICMP LOCAL PKT...\n");
991 proto_type[IP_LOCAL]->func(m, nb_icmp_pkt, icmp_pkts_mask,
995 if (ipv4_forward_pkts_mask) {
998 ("\n RECEIVED L3 PKT, \n\n FORWARDING L3 PKT....\n");
999 proto_type[IP_REMOTE]->func(m, nb_l3_pkt,
1000 ipv4_forward_pkts_mask, port);
1005 resolve_l2_adj(uint32_t nexthop_ip, uint8_t out_port_id,
1006 const struct ether_addr *hw_addr)
1008 struct l2_adj_key_ipv4 l2_adj_key = {
1009 .Next_hop_ip = nexthop_ip,
1010 .out_port_id = out_port_id,
1012 //uint16_t ether_type = 0x0800;
1014 struct l2_adj_entry *adj_data = retrieve_l2_adj_entry(l2_adj_key);
1016 if (adj_data) { /**< L2 Adj Entry Exists*/
1019 ("l2_adj_entry exists ip%x, port %d, Refcnt :%u Address :%p\n",
1020 l2_adj_key.Next_hop_ip, l2_adj_key.out_port_id,
1021 adj_data->refcount, adj_data);
1023 if (adj_data->flags == L2_ADJ_UNRESOLVED
1024 || memcmp(hw_addr, &adj_data->eth_addr,
1025 sizeof(struct ether_addr))) {
1026 memcpy(adj_data->l2_string, hw_addr, sizeof(struct ether_addr)); //** < Precompute the L2 String encap*/
1027 memcpy(&adj_data->l2_string[6],
1028 &adj_data->phy_port->macaddr,
1029 sizeof(struct ether_addr));
1030 //memcpy(&adj_data->l2_string[12], ðer_type, 2);
1032 ether_addr_copy(hw_addr, &adj_data->eth_addr);
1033 adj_data->flags = L2_ADJ_RESOLVED;
1039 l2_phy_interface_t *port;
1040 port = ifm_get_port(out_port_id);
1044 RTE_CACHE_LINE_ROUNDUP(sizeof(struct l2_adj_entry));
1045 adj_data = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
1046 if (adj_data == NULL) {
1047 printf("L2 Adjacency memory allocation failed !\n");
1051 adj_data->out_port_id = out_port_id;
1052 adj_data->Next_hop_ip = nexthop_ip;
1053 adj_data->phy_port = port;
1055 memcpy(adj_data->l2_string, hw_addr, sizeof(struct ether_addr)); //** < Precompute the L2 String encap*/
1056 memcpy(&adj_data->l2_string[6], &adj_data->phy_port->macaddr,
1057 sizeof(struct ether_addr));
1058 //memcpy(&adj_data->l2_string[12], ðer_type, 2);
1060 ether_addr_copy(hw_addr, &adj_data->eth_addr);
1061 adj_data->flags = L2_ADJ_RESOLVED;
1063 rte_hash_add_key_data(l2_adj_hash_handle, &l2_adj_key,
1066 ("L2 adj data stored in l2_adj_entry hash table,Addr:%p\n",
1069 printf("PORT:%u IS DOWN...\n", out_port_id);
1074 uint8_t ip_hash_load_balance(struct rte_mbuf *mbuf)
1076 uint32_t src_addr_offset =
1077 MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_SRC_ADR_OFST;
1078 uint32_t dst_addr_offset =
1079 MBUF_HDR_ROOM + ETH_HDR_SIZE + IP_HDR_DST_ADR_OFST;
1080 uint32_t *dst_addr = NULL;
1081 uint32_t *src_addr = NULL;
1083 (uint32_t *) RTE_MBUF_METADATA_UINT8_PTR(mbuf, src_addr_offset);
1085 (uint32_t *) RTE_MBUF_METADATA_UINT8_PTR(mbuf, dst_addr_offset);
1087 uint32_t hash_key1 = *src_addr; /* STORE SRC IP in key1 variable */
1088 uint32_t hash_key2 = *dst_addr; /* STORE DST IP in key variable */
1090 hash_key1 = hash_key1 ^ hash_key2; /* XOR With SRC and DST IP, Result is hask_key1 */
1091 hash_key2 = hash_key1; /* MOVE The result to hask_key2 */
1093 hash_key1 = rotr32(hash_key1, 16); /* Circular Rotate to 16 bit */
1094 hash_key1 = hash_key1 ^ hash_key2; /* XOR With Key1 with Key2 */
1096 hash_key2 = hash_key1; /* MOVE The result to hask_key2 */
1098 hash_key1 = rotr32(hash_key1, 8); /* Circular Rotate to 8 bit */
1099 hash_key1 = hash_key1 ^ hash_key2; /* XOR With Key1 with Key2 */
1101 hash_key1 = hash_key1 & (HASH_BUCKET_SIZE - 1); /* MASK the KEY with BUCKET SIZE */
1103 printf("Hash Result_key: %d, \n", hash_key1);
1107 uint32_t rotr32(uint32_t value, unsigned int count)
1109 const unsigned int mask = (CHAR_BIT * sizeof(value) - 1);
1111 return (value >> count) | (value << ((-count) & mask));
1115 ip_local_out_deliver(struct rte_mbuf **pkt_burst, uint16_t nb_rx,
1116 uint64_t ipv4_pkts_mask, l2_phy_interface_t *port)
1118 ip_forward_deliver(pkt_burst, nb_rx, ipv4_pkts_mask, port);