199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation 399a2dd95SBruce Richardson */ 499a2dd95SBruce Richardson 5e9fd1ebfSTyler Retzlaff #include <stdalign.h> 699a2dd95SBruce Richardson #include <stdio.h> 7e9fd1ebfSTyler Retzlaff #include <string.h> 899a2dd95SBruce Richardson 999a2dd95SBruce Richardson #include <rte_common.h> 1099a2dd95SBruce Richardson #include <rte_malloc.h> 1199a2dd95SBruce Richardson #include <rte_log.h> 1299a2dd95SBruce Richardson #include <rte_lpm6.h> 1399a2dd95SBruce Richardson 1499a2dd95SBruce Richardson #include "rte_table_lpm_ipv6.h" 1599a2dd95SBruce Richardson 16ae67895bSDavid Marchand #include "table_log.h" 17ae67895bSDavid Marchand 1899a2dd95SBruce Richardson #define RTE_TABLE_LPM_MAX_NEXT_HOPS 256 1999a2dd95SBruce Richardson 2099a2dd95SBruce Richardson #ifdef RTE_TABLE_STATS_COLLECT 2199a2dd95SBruce Richardson 2299a2dd95SBruce Richardson #define RTE_TABLE_LPM_IPV6_STATS_PKTS_IN_ADD(table, val) \ 2399a2dd95SBruce Richardson table->stats.n_pkts_in += val 2499a2dd95SBruce Richardson #define RTE_TABLE_LPM_IPV6_STATS_PKTS_LOOKUP_MISS(table, val) \ 2599a2dd95SBruce Richardson table->stats.n_pkts_lookup_miss += val 2699a2dd95SBruce Richardson 2799a2dd95SBruce Richardson #else 2899a2dd95SBruce Richardson 2999a2dd95SBruce Richardson #define RTE_TABLE_LPM_IPV6_STATS_PKTS_IN_ADD(table, val) 3099a2dd95SBruce Richardson #define RTE_TABLE_LPM_IPV6_STATS_PKTS_LOOKUP_MISS(table, val) 3199a2dd95SBruce Richardson 3299a2dd95SBruce Richardson #endif 3399a2dd95SBruce Richardson 3499a2dd95SBruce Richardson struct rte_table_lpm_ipv6 { 3599a2dd95SBruce Richardson struct rte_table_stats stats; 3699a2dd95SBruce Richardson 3799a2dd95SBruce Richardson /* Input parameters */ 3899a2dd95SBruce Richardson uint32_t entry_size; 3999a2dd95SBruce Richardson uint32_t entry_unique_size; 4099a2dd95SBruce Richardson uint32_t n_rules; 4199a2dd95SBruce Richardson uint32_t offset; 4299a2dd95SBruce Richardson 4399a2dd95SBruce Richardson /* Handle to low-level LPM table */ 4499a2dd95SBruce Richardson struct rte_lpm6 *lpm; 4599a2dd95SBruce Richardson 4699a2dd95SBruce Richardson /* Next Hop Table (NHT) */ 4799a2dd95SBruce Richardson uint32_t nht_users[RTE_TABLE_LPM_MAX_NEXT_HOPS]; 4885e32708STyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) uint8_t nht[]; 4999a2dd95SBruce Richardson }; 5099a2dd95SBruce Richardson 5199a2dd95SBruce Richardson static void * 5299a2dd95SBruce Richardson rte_table_lpm_ipv6_create(void *params, int socket_id, uint32_t entry_size) 5399a2dd95SBruce Richardson { 5499a2dd95SBruce Richardson struct rte_table_lpm_ipv6_params *p = 5599a2dd95SBruce Richardson params; 5699a2dd95SBruce Richardson struct rte_table_lpm_ipv6 *lpm; 5799a2dd95SBruce Richardson struct rte_lpm6_config lpm6_config; 5899a2dd95SBruce Richardson uint32_t total_size, nht_size; 5999a2dd95SBruce Richardson 6099a2dd95SBruce Richardson /* Check input parameters */ 6199a2dd95SBruce Richardson if (p == NULL) { 62ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: NULL input parameters", __func__); 6399a2dd95SBruce Richardson return NULL; 6499a2dd95SBruce Richardson } 6599a2dd95SBruce Richardson if (p->n_rules == 0) { 66ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: Invalid n_rules", __func__); 6799a2dd95SBruce Richardson return NULL; 6899a2dd95SBruce Richardson } 6999a2dd95SBruce Richardson if (p->number_tbl8s == 0) { 70ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: Invalid n_rules", __func__); 7199a2dd95SBruce Richardson return NULL; 7299a2dd95SBruce Richardson } 7399a2dd95SBruce Richardson if (p->entry_unique_size == 0) { 74ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: Invalid entry_unique_size", 7599a2dd95SBruce Richardson __func__); 7699a2dd95SBruce Richardson return NULL; 7799a2dd95SBruce Richardson } 7899a2dd95SBruce Richardson if (p->entry_unique_size > entry_size) { 79ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: Invalid entry_unique_size", 8099a2dd95SBruce Richardson __func__); 8199a2dd95SBruce Richardson return NULL; 8299a2dd95SBruce Richardson } 8399a2dd95SBruce Richardson if (p->name == NULL) { 84ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: Table name is NULL", 8599a2dd95SBruce Richardson __func__); 8699a2dd95SBruce Richardson return NULL; 8799a2dd95SBruce Richardson } 8899a2dd95SBruce Richardson entry_size = RTE_ALIGN(entry_size, sizeof(uint64_t)); 8999a2dd95SBruce Richardson 9099a2dd95SBruce Richardson /* Memory allocation */ 9199a2dd95SBruce Richardson nht_size = RTE_TABLE_LPM_MAX_NEXT_HOPS * entry_size; 9299a2dd95SBruce Richardson total_size = sizeof(struct rte_table_lpm_ipv6) + nht_size; 9399a2dd95SBruce Richardson lpm = rte_zmalloc_socket("TABLE", total_size, RTE_CACHE_LINE_SIZE, 9499a2dd95SBruce Richardson socket_id); 9599a2dd95SBruce Richardson if (lpm == NULL) { 96ae67895bSDavid Marchand TABLE_LOG(ERR, 97ae67895bSDavid Marchand "%s: Cannot allocate %u bytes for LPM IPv6 table", 9899a2dd95SBruce Richardson __func__, total_size); 9999a2dd95SBruce Richardson return NULL; 10099a2dd95SBruce Richardson } 10199a2dd95SBruce Richardson 10299a2dd95SBruce Richardson /* LPM low-level table creation */ 10399a2dd95SBruce Richardson lpm6_config.max_rules = p->n_rules; 10499a2dd95SBruce Richardson lpm6_config.number_tbl8s = p->number_tbl8s; 10599a2dd95SBruce Richardson lpm6_config.flags = 0; 10699a2dd95SBruce Richardson lpm->lpm = rte_lpm6_create(p->name, socket_id, &lpm6_config); 10799a2dd95SBruce Richardson if (lpm->lpm == NULL) { 10899a2dd95SBruce Richardson rte_free(lpm); 109ae67895bSDavid Marchand TABLE_LOG(ERR, 110ae67895bSDavid Marchand "Unable to create low-level LPM IPv6 table"); 11199a2dd95SBruce Richardson return NULL; 11299a2dd95SBruce Richardson } 11399a2dd95SBruce Richardson 11499a2dd95SBruce Richardson /* Memory initialization */ 11599a2dd95SBruce Richardson lpm->entry_size = entry_size; 11699a2dd95SBruce Richardson lpm->entry_unique_size = p->entry_unique_size; 11799a2dd95SBruce Richardson lpm->n_rules = p->n_rules; 11899a2dd95SBruce Richardson lpm->offset = p->offset; 11999a2dd95SBruce Richardson 12099a2dd95SBruce Richardson return lpm; 12199a2dd95SBruce Richardson } 12299a2dd95SBruce Richardson 12399a2dd95SBruce Richardson static int 12499a2dd95SBruce Richardson rte_table_lpm_ipv6_free(void *table) 12599a2dd95SBruce Richardson { 12699a2dd95SBruce Richardson struct rte_table_lpm_ipv6 *lpm = table; 12799a2dd95SBruce Richardson 12899a2dd95SBruce Richardson /* Check input parameters */ 12999a2dd95SBruce Richardson if (lpm == NULL) { 130ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: table parameter is NULL", __func__); 13199a2dd95SBruce Richardson return -EINVAL; 13299a2dd95SBruce Richardson } 13399a2dd95SBruce Richardson 13499a2dd95SBruce Richardson /* Free previously allocated resources */ 13599a2dd95SBruce Richardson rte_lpm6_free(lpm->lpm); 13699a2dd95SBruce Richardson rte_free(lpm); 13799a2dd95SBruce Richardson 13899a2dd95SBruce Richardson return 0; 13999a2dd95SBruce Richardson } 14099a2dd95SBruce Richardson 14199a2dd95SBruce Richardson static int 14299a2dd95SBruce Richardson nht_find_free(struct rte_table_lpm_ipv6 *lpm, uint32_t *pos) 14399a2dd95SBruce Richardson { 14499a2dd95SBruce Richardson uint32_t i; 14599a2dd95SBruce Richardson 14699a2dd95SBruce Richardson for (i = 0; i < RTE_TABLE_LPM_MAX_NEXT_HOPS; i++) { 14799a2dd95SBruce Richardson if (lpm->nht_users[i] == 0) { 14899a2dd95SBruce Richardson *pos = i; 14999a2dd95SBruce Richardson return 1; 15099a2dd95SBruce Richardson } 15199a2dd95SBruce Richardson } 15299a2dd95SBruce Richardson 15399a2dd95SBruce Richardson return 0; 15499a2dd95SBruce Richardson } 15599a2dd95SBruce Richardson 15699a2dd95SBruce Richardson static int 15799a2dd95SBruce Richardson nht_find_existing(struct rte_table_lpm_ipv6 *lpm, void *entry, uint32_t *pos) 15899a2dd95SBruce Richardson { 15999a2dd95SBruce Richardson uint32_t i; 16099a2dd95SBruce Richardson 16199a2dd95SBruce Richardson for (i = 0; i < RTE_TABLE_LPM_MAX_NEXT_HOPS; i++) { 16299a2dd95SBruce Richardson uint8_t *nht_entry = &lpm->nht[i * lpm->entry_size]; 16399a2dd95SBruce Richardson 16499a2dd95SBruce Richardson if ((lpm->nht_users[i] > 0) && (memcmp(nht_entry, entry, 16599a2dd95SBruce Richardson lpm->entry_unique_size) == 0)) { 16699a2dd95SBruce Richardson *pos = i; 16799a2dd95SBruce Richardson return 1; 16899a2dd95SBruce Richardson } 16999a2dd95SBruce Richardson } 17099a2dd95SBruce Richardson 17199a2dd95SBruce Richardson return 0; 17299a2dd95SBruce Richardson } 17399a2dd95SBruce Richardson 17499a2dd95SBruce Richardson static int 17599a2dd95SBruce Richardson rte_table_lpm_ipv6_entry_add( 17699a2dd95SBruce Richardson void *table, 17799a2dd95SBruce Richardson void *key, 17899a2dd95SBruce Richardson void *entry, 17999a2dd95SBruce Richardson int *key_found, 18099a2dd95SBruce Richardson void **entry_ptr) 18199a2dd95SBruce Richardson { 18299a2dd95SBruce Richardson struct rte_table_lpm_ipv6 *lpm = table; 18399a2dd95SBruce Richardson struct rte_table_lpm_ipv6_key *ip_prefix = 18499a2dd95SBruce Richardson key; 18599a2dd95SBruce Richardson uint32_t nht_pos = 0, nht_pos0 = 0, nht_pos0_valid = 0; 18699a2dd95SBruce Richardson int status; 18799a2dd95SBruce Richardson 18899a2dd95SBruce Richardson /* Check input parameters */ 18999a2dd95SBruce Richardson if (lpm == NULL) { 190ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: table parameter is NULL", __func__); 19199a2dd95SBruce Richardson return -EINVAL; 19299a2dd95SBruce Richardson } 19399a2dd95SBruce Richardson if (ip_prefix == NULL) { 194ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: ip_prefix parameter is NULL", 19599a2dd95SBruce Richardson __func__); 19699a2dd95SBruce Richardson return -EINVAL; 19799a2dd95SBruce Richardson } 19899a2dd95SBruce Richardson if (entry == NULL) { 199ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: entry parameter is NULL", __func__); 20099a2dd95SBruce Richardson return -EINVAL; 20199a2dd95SBruce Richardson } 20299a2dd95SBruce Richardson 20399a2dd95SBruce Richardson if ((ip_prefix->depth == 0) || (ip_prefix->depth > 128)) { 204ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: invalid depth (%d)", __func__, 20599a2dd95SBruce Richardson ip_prefix->depth); 20699a2dd95SBruce Richardson return -EINVAL; 20799a2dd95SBruce Richardson } 20899a2dd95SBruce Richardson 20999a2dd95SBruce Richardson /* Check if rule is already present in the table */ 210*e1a06e39SRobin Jarry status = rte_lpm6_is_rule_present(lpm->lpm, &ip_prefix->ip, 21199a2dd95SBruce Richardson ip_prefix->depth, &nht_pos0); 21299a2dd95SBruce Richardson nht_pos0_valid = status > 0; 21399a2dd95SBruce Richardson 21499a2dd95SBruce Richardson /* Find existing or free NHT entry */ 21599a2dd95SBruce Richardson if (nht_find_existing(lpm, entry, &nht_pos) == 0) { 21699a2dd95SBruce Richardson uint8_t *nht_entry; 21799a2dd95SBruce Richardson 21899a2dd95SBruce Richardson if (nht_find_free(lpm, &nht_pos) == 0) { 219ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: NHT full", __func__); 22099a2dd95SBruce Richardson return -1; 22199a2dd95SBruce Richardson } 22299a2dd95SBruce Richardson 22399a2dd95SBruce Richardson nht_entry = &lpm->nht[nht_pos * lpm->entry_size]; 22499a2dd95SBruce Richardson memcpy(nht_entry, entry, lpm->entry_size); 22599a2dd95SBruce Richardson } 22699a2dd95SBruce Richardson 22799a2dd95SBruce Richardson /* Add rule to low level LPM table */ 228*e1a06e39SRobin Jarry if (rte_lpm6_add(lpm->lpm, &ip_prefix->ip, ip_prefix->depth, 22999a2dd95SBruce Richardson nht_pos) < 0) { 230ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: LPM IPv6 rule add failed", __func__); 23199a2dd95SBruce Richardson return -1; 23299a2dd95SBruce Richardson } 23399a2dd95SBruce Richardson 23499a2dd95SBruce Richardson /* Commit NHT changes */ 23599a2dd95SBruce Richardson lpm->nht_users[nht_pos]++; 23699a2dd95SBruce Richardson lpm->nht_users[nht_pos0] -= nht_pos0_valid; 23799a2dd95SBruce Richardson 23899a2dd95SBruce Richardson *key_found = nht_pos0_valid; 23999a2dd95SBruce Richardson *entry_ptr = (void *) &lpm->nht[nht_pos * lpm->entry_size]; 24099a2dd95SBruce Richardson return 0; 24199a2dd95SBruce Richardson } 24299a2dd95SBruce Richardson 24399a2dd95SBruce Richardson static int 24499a2dd95SBruce Richardson rte_table_lpm_ipv6_entry_delete( 24599a2dd95SBruce Richardson void *table, 24699a2dd95SBruce Richardson void *key, 24799a2dd95SBruce Richardson int *key_found, 24899a2dd95SBruce Richardson void *entry) 24999a2dd95SBruce Richardson { 25099a2dd95SBruce Richardson struct rte_table_lpm_ipv6 *lpm = table; 25199a2dd95SBruce Richardson struct rte_table_lpm_ipv6_key *ip_prefix = 25299a2dd95SBruce Richardson key; 25399a2dd95SBruce Richardson uint32_t nht_pos; 25499a2dd95SBruce Richardson int status; 25599a2dd95SBruce Richardson 25699a2dd95SBruce Richardson /* Check input parameters */ 25799a2dd95SBruce Richardson if (lpm == NULL) { 258ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: table parameter is NULL", __func__); 25999a2dd95SBruce Richardson return -EINVAL; 26099a2dd95SBruce Richardson } 26199a2dd95SBruce Richardson if (ip_prefix == NULL) { 262ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: ip_prefix parameter is NULL", 26399a2dd95SBruce Richardson __func__); 26499a2dd95SBruce Richardson return -EINVAL; 26599a2dd95SBruce Richardson } 26699a2dd95SBruce Richardson if ((ip_prefix->depth == 0) || (ip_prefix->depth > 128)) { 267ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: invalid depth (%d)", __func__, 26899a2dd95SBruce Richardson ip_prefix->depth); 26999a2dd95SBruce Richardson return -EINVAL; 27099a2dd95SBruce Richardson } 27199a2dd95SBruce Richardson 27299a2dd95SBruce Richardson /* Return if rule is not present in the table */ 273*e1a06e39SRobin Jarry status = rte_lpm6_is_rule_present(lpm->lpm, &ip_prefix->ip, 27499a2dd95SBruce Richardson ip_prefix->depth, &nht_pos); 27599a2dd95SBruce Richardson if (status < 0) { 276ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: LPM IPv6 algorithmic error", 27799a2dd95SBruce Richardson __func__); 27899a2dd95SBruce Richardson return -1; 27999a2dd95SBruce Richardson } 28099a2dd95SBruce Richardson if (status == 0) { 28199a2dd95SBruce Richardson *key_found = 0; 28299a2dd95SBruce Richardson return 0; 28399a2dd95SBruce Richardson } 28499a2dd95SBruce Richardson 28599a2dd95SBruce Richardson /* Delete rule from the low-level LPM table */ 286*e1a06e39SRobin Jarry status = rte_lpm6_delete(lpm->lpm, &ip_prefix->ip, ip_prefix->depth); 28799a2dd95SBruce Richardson if (status) { 288ae67895bSDavid Marchand TABLE_LOG(ERR, "%s: LPM IPv6 rule delete failed", 28999a2dd95SBruce Richardson __func__); 29099a2dd95SBruce Richardson return -1; 29199a2dd95SBruce Richardson } 29299a2dd95SBruce Richardson 29399a2dd95SBruce Richardson /* Commit NHT changes */ 29499a2dd95SBruce Richardson lpm->nht_users[nht_pos]--; 29599a2dd95SBruce Richardson 29699a2dd95SBruce Richardson *key_found = 1; 29799a2dd95SBruce Richardson if (entry) 29899a2dd95SBruce Richardson memcpy(entry, &lpm->nht[nht_pos * lpm->entry_size], 29999a2dd95SBruce Richardson lpm->entry_size); 30099a2dd95SBruce Richardson 30199a2dd95SBruce Richardson return 0; 30299a2dd95SBruce Richardson } 30399a2dd95SBruce Richardson 30499a2dd95SBruce Richardson static int 30599a2dd95SBruce Richardson rte_table_lpm_ipv6_lookup( 30699a2dd95SBruce Richardson void *table, 30799a2dd95SBruce Richardson struct rte_mbuf **pkts, 30899a2dd95SBruce Richardson uint64_t pkts_mask, 30999a2dd95SBruce Richardson uint64_t *lookup_hit_mask, 31099a2dd95SBruce Richardson void **entries) 31199a2dd95SBruce Richardson { 31299a2dd95SBruce Richardson struct rte_table_lpm_ipv6 *lpm = (struct rte_table_lpm_ipv6 *) table; 31399a2dd95SBruce Richardson uint64_t pkts_out_mask = 0; 31499a2dd95SBruce Richardson uint32_t i; 31599a2dd95SBruce Richardson 3163d4e27fdSDavid Marchand __rte_unused uint32_t n_pkts_in = rte_popcount64(pkts_mask); 31799a2dd95SBruce Richardson RTE_TABLE_LPM_IPV6_STATS_PKTS_IN_ADD(lpm, n_pkts_in); 31899a2dd95SBruce Richardson 31999a2dd95SBruce Richardson pkts_out_mask = 0; 32099a2dd95SBruce Richardson for (i = 0; i < (uint32_t)(RTE_PORT_IN_BURST_SIZE_MAX - 3213d4e27fdSDavid Marchand rte_clz64(pkts_mask)); i++) { 32299a2dd95SBruce Richardson uint64_t pkt_mask = 1LLU << i; 32399a2dd95SBruce Richardson 32499a2dd95SBruce Richardson if (pkt_mask & pkts_mask) { 32599a2dd95SBruce Richardson struct rte_mbuf *pkt = pkts[i]; 326*e1a06e39SRobin Jarry const struct rte_ipv6_addr *ip; 32799a2dd95SBruce Richardson int status; 32899a2dd95SBruce Richardson uint32_t nht_pos; 32999a2dd95SBruce Richardson 330*e1a06e39SRobin Jarry ip = (struct rte_ipv6_addr *)RTE_MBUF_METADATA_UINT8_PTR(pkt, lpm->offset); 33199a2dd95SBruce Richardson status = rte_lpm6_lookup(lpm->lpm, ip, &nht_pos); 33299a2dd95SBruce Richardson if (status == 0) { 33399a2dd95SBruce Richardson pkts_out_mask |= pkt_mask; 33499a2dd95SBruce Richardson entries[i] = (void *) &lpm->nht[nht_pos * 33599a2dd95SBruce Richardson lpm->entry_size]; 33699a2dd95SBruce Richardson } 33799a2dd95SBruce Richardson } 33899a2dd95SBruce Richardson } 33999a2dd95SBruce Richardson 34099a2dd95SBruce Richardson *lookup_hit_mask = pkts_out_mask; 3413d4e27fdSDavid Marchand RTE_TABLE_LPM_IPV6_STATS_PKTS_LOOKUP_MISS(lpm, n_pkts_in - rte_popcount64(pkts_out_mask)); 34299a2dd95SBruce Richardson return 0; 34399a2dd95SBruce Richardson } 34499a2dd95SBruce Richardson 34599a2dd95SBruce Richardson static int 34699a2dd95SBruce Richardson rte_table_lpm_ipv6_stats_read(void *table, struct rte_table_stats *stats, int clear) 34799a2dd95SBruce Richardson { 34899a2dd95SBruce Richardson struct rte_table_lpm_ipv6 *t = table; 34999a2dd95SBruce Richardson 35099a2dd95SBruce Richardson if (stats != NULL) 35199a2dd95SBruce Richardson memcpy(stats, &t->stats, sizeof(t->stats)); 35299a2dd95SBruce Richardson 35399a2dd95SBruce Richardson if (clear) 35499a2dd95SBruce Richardson memset(&t->stats, 0, sizeof(t->stats)); 35599a2dd95SBruce Richardson 35699a2dd95SBruce Richardson return 0; 35799a2dd95SBruce Richardson } 35899a2dd95SBruce Richardson 35999a2dd95SBruce Richardson struct rte_table_ops rte_table_lpm_ipv6_ops = { 36099a2dd95SBruce Richardson .f_create = rte_table_lpm_ipv6_create, 36199a2dd95SBruce Richardson .f_free = rte_table_lpm_ipv6_free, 36299a2dd95SBruce Richardson .f_add = rte_table_lpm_ipv6_entry_add, 36399a2dd95SBruce Richardson .f_delete = rte_table_lpm_ipv6_entry_delete, 36499a2dd95SBruce Richardson .f_add_bulk = NULL, 36599a2dd95SBruce Richardson .f_delete_bulk = NULL, 36699a2dd95SBruce Richardson .f_lookup = rte_table_lpm_ipv6_lookup, 36799a2dd95SBruce Richardson .f_stats = rte_table_lpm_ipv6_stats_read, 36899a2dd95SBruce Richardson }; 369