1537d1343SAlexander V. Chernikov /*- 2537d1343SAlexander V. Chernikov * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3537d1343SAlexander V. Chernikov * 4537d1343SAlexander V. Chernikov * Copyright (c) 2020 Alexander V. Chernikov 5537d1343SAlexander V. Chernikov * 6537d1343SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 7537d1343SAlexander V. Chernikov * modification, are permitted provided that the following conditions 8537d1343SAlexander V. Chernikov * are met: 9537d1343SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 10537d1343SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 11537d1343SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 12537d1343SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 13537d1343SAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 14537d1343SAlexander V. Chernikov * 15537d1343SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16537d1343SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17537d1343SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18537d1343SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19537d1343SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20537d1343SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21537d1343SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22537d1343SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23537d1343SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24537d1343SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25537d1343SAlexander V. Chernikov * SUCH DAMAGE. 26537d1343SAlexander V. Chernikov */ 27537d1343SAlexander V. Chernikov 28537d1343SAlexander V. Chernikov #include <sys/cdefs.h> 29537d1343SAlexander V. Chernikov __FBSDID("$FreeBSD$"); 30537d1343SAlexander V. Chernikov #include "opt_inet6.h" 31537d1343SAlexander V. Chernikov 32537d1343SAlexander V. Chernikov #include <sys/param.h> 33537d1343SAlexander V. Chernikov #include <sys/kernel.h> 34537d1343SAlexander V. Chernikov #include <sys/lock.h> 35537d1343SAlexander V. Chernikov #include <sys/rmlock.h> 36537d1343SAlexander V. Chernikov #include <sys/malloc.h> 37537d1343SAlexander V. Chernikov #include <sys/module.h> 38537d1343SAlexander V. Chernikov #include <sys/kernel.h> 39537d1343SAlexander V. Chernikov #include <sys/socket.h> 40537d1343SAlexander V. Chernikov #include <sys/sysctl.h> 41537d1343SAlexander V. Chernikov #include <sys/syslog.h> 42537d1343SAlexander V. Chernikov #include <net/vnet.h> 43537d1343SAlexander V. Chernikov 44537d1343SAlexander V. Chernikov #include <net/if.h> 45537d1343SAlexander V. Chernikov #include <net/if_var.h> 46537d1343SAlexander V. Chernikov 47537d1343SAlexander V. Chernikov #include <netinet/in.h> 48537d1343SAlexander V. Chernikov #include <netinet/ip.h> 49537d1343SAlexander V. Chernikov #include <netinet/ip6.h> 50537d1343SAlexander V. Chernikov #include <netinet6/ip6_var.h> 51537d1343SAlexander V. Chernikov #include <netinet6/in6_fib.h> 52537d1343SAlexander V. Chernikov 53537d1343SAlexander V. Chernikov #include <net/route.h> 54537d1343SAlexander V. Chernikov #include <net/route/nhop.h> 55537d1343SAlexander V. Chernikov #include <net/route/route_ctl.h> 56537d1343SAlexander V. Chernikov #include <net/route/fib_algo.h> 57537d1343SAlexander V. Chernikov #define RTDEBUG 58537d1343SAlexander V. Chernikov 59537d1343SAlexander V. Chernikov #include "rte_lpm6.h" 60537d1343SAlexander V. Chernikov 61537d1343SAlexander V. Chernikov #define LPM6_MIN_TBL8 8 /* 2 pages of memory */ 62537d1343SAlexander V. Chernikov #define LPM6_MAX_TBL8 65536 * 16 /* 256M */ 63537d1343SAlexander V. Chernikov 64537d1343SAlexander V. Chernikov struct fib_algo_calldata { 65537d1343SAlexander V. Chernikov void *lookup; 66537d1343SAlexander V. Chernikov void *arg; 67537d1343SAlexander V. Chernikov }; 68537d1343SAlexander V. Chernikov 69537d1343SAlexander V. Chernikov struct dpdk_lpm6_data { 70537d1343SAlexander V. Chernikov struct rte_lpm6 *lpm6; 71537d1343SAlexander V. Chernikov uint64_t routes_added; 72537d1343SAlexander V. Chernikov uint64_t routes_failed; 73537d1343SAlexander V. Chernikov uint32_t number_tbl8s; 74537d1343SAlexander V. Chernikov uint32_t fibnum; 75537d1343SAlexander V. Chernikov uint8_t hit_tables; 76537d1343SAlexander V. Chernikov struct fib_data *fd; 77537d1343SAlexander V. Chernikov }; 78537d1343SAlexander V. Chernikov 79537d1343SAlexander V. Chernikov static struct nhop_object * 80537d1343SAlexander V. Chernikov lookup_ptr_ll(const struct rte_lpm6 *lpm6, const struct in6_addr *dst6, 81537d1343SAlexander V. Chernikov uint32_t scopeid) 82537d1343SAlexander V. Chernikov { 83537d1343SAlexander V. Chernikov const struct rte_lpm6_external *rte_ext; 84537d1343SAlexander V. Chernikov 85537d1343SAlexander V. Chernikov rte_ext = (const struct rte_lpm6_external *)lpm6; 86537d1343SAlexander V. Chernikov 87537d1343SAlexander V. Chernikov return (fib6_radix_lookup_nh(rte_ext->fibnum, dst6, scopeid)); 88537d1343SAlexander V. Chernikov } 89537d1343SAlexander V. Chernikov 90537d1343SAlexander V. Chernikov /* 91537d1343SAlexander V. Chernikov * Main datapath routing 92537d1343SAlexander V. Chernikov */ 93537d1343SAlexander V. Chernikov static struct nhop_object * 94537d1343SAlexander V. Chernikov lookup_ptr(void *algo_data, const struct flm_lookup_key key, uint32_t scopeid) 95537d1343SAlexander V. Chernikov { 96537d1343SAlexander V. Chernikov const struct rte_lpm6 *lpm6; 97537d1343SAlexander V. Chernikov const struct rte_lpm6_external *rte_ext; 98537d1343SAlexander V. Chernikov const struct in6_addr *addr6; 99537d1343SAlexander V. Chernikov uint32_t nhidx = 0; 100537d1343SAlexander V. Chernikov int ret; 101537d1343SAlexander V. Chernikov 102537d1343SAlexander V. Chernikov lpm6 = (const struct rte_lpm6 *)algo_data; 103537d1343SAlexander V. Chernikov addr6 = key.addr6; 104537d1343SAlexander V. Chernikov rte_ext = (const struct rte_lpm6_external *)lpm6; 105537d1343SAlexander V. Chernikov 106537d1343SAlexander V. Chernikov if (!IN6_IS_SCOPE_LINKLOCAL(addr6)) { 107537d1343SAlexander V. Chernikov ret = rte_lpm6_lookup(lpm6, (const uint8_t *)addr6, &nhidx); 108537d1343SAlexander V. Chernikov if (ret == 0) { 109537d1343SAlexander V. Chernikov /* Success! */ 110537d1343SAlexander V. Chernikov return (rte_ext->nh_idx[nhidx]); 111537d1343SAlexander V. Chernikov } else { 112537d1343SAlexander V. Chernikov /* Not found. Check default route */ 113537d1343SAlexander V. Chernikov if (rte_ext->default_idx > 0) 114537d1343SAlexander V. Chernikov return (rte_ext->nh_idx[rte_ext->default_idx]); 115537d1343SAlexander V. Chernikov else 116537d1343SAlexander V. Chernikov return (NULL); 117537d1343SAlexander V. Chernikov } 118537d1343SAlexander V. Chernikov } else { 119537d1343SAlexander V. Chernikov /* LL */ 120537d1343SAlexander V. Chernikov return (lookup_ptr_ll(lpm6, addr6, scopeid)); 121537d1343SAlexander V. Chernikov } 122537d1343SAlexander V. Chernikov } 123537d1343SAlexander V. Chernikov 124537d1343SAlexander V. Chernikov static uint8_t 125537d1343SAlexander V. Chernikov rte6_get_pref(const struct rib_rtable_info *rinfo) 126537d1343SAlexander V. Chernikov { 127537d1343SAlexander V. Chernikov 128537d1343SAlexander V. Chernikov if (rinfo->num_prefixes < 10) 129537d1343SAlexander V. Chernikov return (1); 130537d1343SAlexander V. Chernikov else if (rinfo->num_prefixes < 1000) 131537d1343SAlexander V. Chernikov return (rinfo->num_prefixes / 10); 132d5be41beSAlexander V. Chernikov else if (rinfo->num_prefixes < 100000) 133d5be41beSAlexander V. Chernikov return (100 + rinfo->num_prefixes / 667); 134537d1343SAlexander V. Chernikov else 135537d1343SAlexander V. Chernikov return (250); 136537d1343SAlexander V. Chernikov } 137537d1343SAlexander V. Chernikov 138537d1343SAlexander V. Chernikov static enum flm_op_result 139537d1343SAlexander V. Chernikov handle_default_change(struct dpdk_lpm6_data *dd, struct rib_cmd_info *rc) 140537d1343SAlexander V. Chernikov { 141537d1343SAlexander V. Chernikov struct rte_lpm6_external *rte_ext; 142537d1343SAlexander V. Chernikov rte_ext = (struct rte_lpm6_external *)dd->lpm6; 143537d1343SAlexander V. Chernikov 144537d1343SAlexander V. Chernikov if (rc->rc_cmd != RTM_DELETE) { 145537d1343SAlexander V. Chernikov /* Reference new */ 146537d1343SAlexander V. Chernikov uint32_t nhidx = fib_get_nhop_idx(dd->fd, rc->rc_nh_new); 147537d1343SAlexander V. Chernikov 148537d1343SAlexander V. Chernikov if (nhidx == 0) 149537d1343SAlexander V. Chernikov return (FLM_REBUILD); 150537d1343SAlexander V. Chernikov rte_ext->default_idx = nhidx; 151537d1343SAlexander V. Chernikov } else { 152537d1343SAlexander V. Chernikov /* No default route */ 153537d1343SAlexander V. Chernikov rte_ext->default_idx = 0; 154537d1343SAlexander V. Chernikov } 155537d1343SAlexander V. Chernikov 156537d1343SAlexander V. Chernikov return (FLM_SUCCESS); 157537d1343SAlexander V. Chernikov } 158537d1343SAlexander V. Chernikov 159537d1343SAlexander V. Chernikov static enum flm_op_result 160537d1343SAlexander V. Chernikov handle_ll_change(struct dpdk_lpm6_data *dd, struct rib_cmd_info *rc, 161537d1343SAlexander V. Chernikov const struct in6_addr addr6, int plen, uint32_t scopeid) 162537d1343SAlexander V. Chernikov { 163537d1343SAlexander V. Chernikov 164537d1343SAlexander V. Chernikov return (FLM_SUCCESS); 165537d1343SAlexander V. Chernikov } 166537d1343SAlexander V. Chernikov 167537d1343SAlexander V. Chernikov static struct rte_lpm6_rule * 168*36e15b71SAlexander V. Chernikov pack_parent_rule(struct dpdk_lpm6_data *dd, const struct in6_addr *addr6, int plen, 169*36e15b71SAlexander V. Chernikov int *pplen, uint32_t *pnhop_idx, char *buffer) 170537d1343SAlexander V. Chernikov { 171537d1343SAlexander V. Chernikov struct rte_lpm6_rule *lsp_rule = NULL; 172537d1343SAlexander V. Chernikov struct rtentry *rt; 173537d1343SAlexander V. Chernikov 174*36e15b71SAlexander V. Chernikov *pnhop_idx = 0; 175*36e15b71SAlexander V. Chernikov *pplen = 0; 176*36e15b71SAlexander V. Chernikov 177*36e15b71SAlexander V. Chernikov rt = rt_get_inet6_parent(dd->fibnum, addr6, plen); 178537d1343SAlexander V. Chernikov /* plen = 0 means default route and it's out of scope */ 179537d1343SAlexander V. Chernikov if (rt != NULL) { 180*36e15b71SAlexander V. Chernikov uint32_t nhop_idx, scopeid; 181537d1343SAlexander V. Chernikov struct in6_addr new_addr6; 182537d1343SAlexander V. Chernikov rt_get_inet6_prefix_plen(rt, &new_addr6, &plen, &scopeid); 183537d1343SAlexander V. Chernikov if (plen > 0) { 184*36e15b71SAlexander V. Chernikov nhop_idx = fib_get_nhop_idx(dd->fd, rt_get_raw_nhop(rt)); 185*36e15b71SAlexander V. Chernikov lsp_rule = fill_rule6(buffer, (uint8_t *)&new_addr6, plen, nhop_idx); 186*36e15b71SAlexander V. Chernikov *pnhop_idx = nhop_idx; 187*36e15b71SAlexander V. Chernikov *pplen = plen; 188537d1343SAlexander V. Chernikov } 189537d1343SAlexander V. Chernikov } 190537d1343SAlexander V. Chernikov 191537d1343SAlexander V. Chernikov return (lsp_rule); 192537d1343SAlexander V. Chernikov } 193537d1343SAlexander V. Chernikov 194537d1343SAlexander V. Chernikov static enum flm_op_result 195537d1343SAlexander V. Chernikov handle_gu_change(struct dpdk_lpm6_data *dd, const struct rib_cmd_info *rc, 196537d1343SAlexander V. Chernikov const struct in6_addr *addr6, int plen) 197537d1343SAlexander V. Chernikov { 198537d1343SAlexander V. Chernikov int ret; 199537d1343SAlexander V. Chernikov char abuf[INET6_ADDRSTRLEN]; 200537d1343SAlexander V. Chernikov inet_ntop(AF_INET6, addr6, abuf, sizeof(abuf)); 201537d1343SAlexander V. Chernikov 202537d1343SAlexander V. Chernikov /* So we get sin6, plen and nhidx */ 203537d1343SAlexander V. Chernikov if (rc->rc_cmd != RTM_DELETE) { 204537d1343SAlexander V. Chernikov /* 205537d1343SAlexander V. Chernikov * Addition or change. Save nhop in the internal table 206537d1343SAlexander V. Chernikov * and get index. 207537d1343SAlexander V. Chernikov */ 208537d1343SAlexander V. Chernikov uint32_t nhidx = fib_get_nhop_idx(dd->fd, rc->rc_nh_new); 209537d1343SAlexander V. Chernikov if (nhidx == 0) { 210537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, dd->fd, "nhop limit reached, need rebuild"); 211537d1343SAlexander V. Chernikov return (FLM_REBUILD); 212537d1343SAlexander V. Chernikov } 213537d1343SAlexander V. Chernikov 214537d1343SAlexander V. Chernikov ret = rte_lpm6_add(dd->lpm6, (const uint8_t *)addr6, 215537d1343SAlexander V. Chernikov plen, nhidx, (rc->rc_cmd == RTM_ADD) ? 1 : 0); 216*36e15b71SAlexander V. Chernikov FIB_PRINTF(LOG_DEBUG, dd->fd, "DPDK GU: %s %s/%d nhop %u -> %u ret: %d", 217537d1343SAlexander V. Chernikov (rc->rc_cmd == RTM_ADD) ? "ADD" : "UPDATE", 218*36e15b71SAlexander V. Chernikov abuf, plen, 219*36e15b71SAlexander V. Chernikov rc->rc_nh_old != NULL ? fib_get_nhop_idx(dd->fd, rc->rc_nh_old) : 0, 220*36e15b71SAlexander V. Chernikov nhidx, ret); 221537d1343SAlexander V. Chernikov } else { 222537d1343SAlexander V. Chernikov /* 223537d1343SAlexander V. Chernikov * Need to lookup parent. Assume deletion happened already 224537d1343SAlexander V. Chernikov */ 225537d1343SAlexander V. Chernikov char buffer[RTE_LPM6_RULE_SIZE]; 226537d1343SAlexander V. Chernikov struct rte_lpm6_rule *lsp_rule = NULL; 227*36e15b71SAlexander V. Chernikov int parent_plen; 228*36e15b71SAlexander V. Chernikov uint32_t parent_nhop_idx; 229*36e15b71SAlexander V. Chernikov lsp_rule = pack_parent_rule(dd, addr6, plen, &parent_plen, 230*36e15b71SAlexander V. Chernikov &parent_nhop_idx, buffer); 231537d1343SAlexander V. Chernikov 232537d1343SAlexander V. Chernikov ret = rte_lpm6_delete(dd->lpm6, (const uint8_t *)addr6, plen, lsp_rule); 233*36e15b71SAlexander V. Chernikov FIB_PRINTF(LOG_DEBUG, dd->fd, "DPDK GU: %s %s/%d -> /%d nhop %u -> %u ret: %d", 234*36e15b71SAlexander V. Chernikov "DEL", abuf, plen, parent_plen, fib_get_nhop_idx(dd->fd, rc->rc_nh_old), 235*36e15b71SAlexander V. Chernikov parent_nhop_idx, ret); 236537d1343SAlexander V. Chernikov } 237537d1343SAlexander V. Chernikov 238537d1343SAlexander V. Chernikov if (ret != 0) { 239537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, dd->fd, "error: %d", ret); 240537d1343SAlexander V. Chernikov if (ret == -ENOSPC) 241537d1343SAlexander V. Chernikov return (FLM_REBUILD); 242537d1343SAlexander V. Chernikov return (FLM_ERROR); 243537d1343SAlexander V. Chernikov } 244537d1343SAlexander V. Chernikov return (FLM_SUCCESS); 245537d1343SAlexander V. Chernikov } 246537d1343SAlexander V. Chernikov 247537d1343SAlexander V. Chernikov static enum flm_op_result 248537d1343SAlexander V. Chernikov handle_any_change(struct dpdk_lpm6_data *dd, struct rib_cmd_info *rc) 249537d1343SAlexander V. Chernikov { 250537d1343SAlexander V. Chernikov enum flm_op_result ret; 251537d1343SAlexander V. Chernikov struct in6_addr addr6; 252537d1343SAlexander V. Chernikov uint32_t scopeid; 253537d1343SAlexander V. Chernikov int plen; 254537d1343SAlexander V. Chernikov 255537d1343SAlexander V. Chernikov rt_get_inet6_prefix_plen(rc->rc_rt, &addr6, &plen, &scopeid); 256537d1343SAlexander V. Chernikov 257537d1343SAlexander V. Chernikov if (IN6_IS_SCOPE_LINKLOCAL(&addr6)) 258537d1343SAlexander V. Chernikov ret = handle_ll_change(dd, rc, addr6, plen, scopeid); 259537d1343SAlexander V. Chernikov else if (plen == 0) 260537d1343SAlexander V. Chernikov ret = handle_default_change(dd, rc); 261537d1343SAlexander V. Chernikov else 262537d1343SAlexander V. Chernikov ret = handle_gu_change(dd, rc, &addr6, plen); 263537d1343SAlexander V. Chernikov 264537d1343SAlexander V. Chernikov if (ret != 0) 265537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, dd->fd, "error handling route"); 266537d1343SAlexander V. Chernikov return (ret); 267537d1343SAlexander V. Chernikov } 268537d1343SAlexander V. Chernikov 269537d1343SAlexander V. Chernikov static enum flm_op_result 270537d1343SAlexander V. Chernikov handle_rtable_change_cb(struct rib_head *rnh, struct rib_cmd_info *rc, 271537d1343SAlexander V. Chernikov void *_data) 272537d1343SAlexander V. Chernikov { 273537d1343SAlexander V. Chernikov struct dpdk_lpm6_data *dd; 274537d1343SAlexander V. Chernikov 275537d1343SAlexander V. Chernikov dd = (struct dpdk_lpm6_data *)_data; 276537d1343SAlexander V. Chernikov 277537d1343SAlexander V. Chernikov return (handle_any_change(dd, rc)); 278537d1343SAlexander V. Chernikov } 279537d1343SAlexander V. Chernikov 280537d1343SAlexander V. Chernikov static void 281537d1343SAlexander V. Chernikov destroy_dd(struct dpdk_lpm6_data *dd) 282537d1343SAlexander V. Chernikov { 283537d1343SAlexander V. Chernikov 284537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, dd->fd, "destroy dd %p", dd); 285537d1343SAlexander V. Chernikov if (dd->lpm6 != NULL) 286537d1343SAlexander V. Chernikov rte_lpm6_free(dd->lpm6); 287537d1343SAlexander V. Chernikov free(dd, M_TEMP); 288537d1343SAlexander V. Chernikov } 289537d1343SAlexander V. Chernikov 290537d1343SAlexander V. Chernikov static void 291537d1343SAlexander V. Chernikov destroy_table(void *_data) 292537d1343SAlexander V. Chernikov { 293537d1343SAlexander V. Chernikov 294537d1343SAlexander V. Chernikov destroy_dd((struct dpdk_lpm6_data *)_data); 295537d1343SAlexander V. Chernikov } 296537d1343SAlexander V. Chernikov 297537d1343SAlexander V. Chernikov static enum flm_op_result 298537d1343SAlexander V. Chernikov add_route_cb(struct rtentry *rt, void *_data) 299537d1343SAlexander V. Chernikov { 300537d1343SAlexander V. Chernikov struct dpdk_lpm6_data *dd = (struct dpdk_lpm6_data *)_data; 301537d1343SAlexander V. Chernikov struct in6_addr addr6; 302537d1343SAlexander V. Chernikov struct nhop_object *nh; 303537d1343SAlexander V. Chernikov uint32_t scopeid; 304537d1343SAlexander V. Chernikov int plen; 305537d1343SAlexander V. Chernikov int ret; 306537d1343SAlexander V. Chernikov 307537d1343SAlexander V. Chernikov rt_get_inet6_prefix_plen(rt, &addr6, &plen, &scopeid); 308537d1343SAlexander V. Chernikov nh = rt_get_raw_nhop(rt); 309537d1343SAlexander V. Chernikov 310537d1343SAlexander V. Chernikov if (IN6_IS_SCOPE_LINKLOCAL(&addr6)) { 311537d1343SAlexander V. Chernikov 312537d1343SAlexander V. Chernikov /* 313537d1343SAlexander V. Chernikov * We don't operate on LL directly, however 314537d1343SAlexander V. Chernikov * reference them to maintain guarantee on 315537d1343SAlexander V. Chernikov * ability to refcount nhops in epoch. 316537d1343SAlexander V. Chernikov */ 317537d1343SAlexander V. Chernikov fib_get_nhop_idx(dd->fd, nh); 318537d1343SAlexander V. Chernikov return (FLM_SUCCESS); 319537d1343SAlexander V. Chernikov } 320537d1343SAlexander V. Chernikov 321537d1343SAlexander V. Chernikov char abuf[INET6_ADDRSTRLEN]; 322537d1343SAlexander V. Chernikov inet_ntop(AF_INET6, &addr6, abuf, sizeof(abuf)); 323537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_DEBUG, dd->fd, "Operating on %s/%d", abuf, plen); 324537d1343SAlexander V. Chernikov 325537d1343SAlexander V. Chernikov if (plen == 0) { 326537d1343SAlexander V. Chernikov struct rib_cmd_info rc = { 327537d1343SAlexander V. Chernikov .rc_cmd = RTM_ADD, 328537d1343SAlexander V. Chernikov .rc_nh_new = nh, 329537d1343SAlexander V. Chernikov }; 330537d1343SAlexander V. Chernikov 331537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_DEBUG, dd->fd, "Adding default route"); 332537d1343SAlexander V. Chernikov return (handle_default_change(dd, &rc)); 333537d1343SAlexander V. Chernikov } 334537d1343SAlexander V. Chernikov 335537d1343SAlexander V. Chernikov uint32_t nhidx = fib_get_nhop_idx(dd->fd, nh); 336537d1343SAlexander V. Chernikov if (nhidx == 0) { 337537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, dd->fd, "unable to get nhop index"); 338537d1343SAlexander V. Chernikov return (FLM_REBUILD); 339537d1343SAlexander V. Chernikov } 340537d1343SAlexander V. Chernikov ret = rte_lpm6_add(dd->lpm6, (const uint8_t *)&addr6, plen, nhidx, 1); 341537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_DEBUG, dd->fd, "ADD %p %s/%d nh %u = %d", 342537d1343SAlexander V. Chernikov dd->lpm6, abuf, plen, nhidx, ret); 343537d1343SAlexander V. Chernikov 344537d1343SAlexander V. Chernikov if (ret != 0) { 345537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, dd->fd, "rte_lpm6_add() returned %d", ret); 346537d1343SAlexander V. Chernikov if (ret == -ENOSPC) { 347537d1343SAlexander V. Chernikov dd->hit_tables = 1; 348537d1343SAlexander V. Chernikov return (FLM_REBUILD); 349537d1343SAlexander V. Chernikov } 350537d1343SAlexander V. Chernikov dd->routes_failed++; 351537d1343SAlexander V. Chernikov return (FLM_ERROR); 352537d1343SAlexander V. Chernikov } else 353537d1343SAlexander V. Chernikov dd->routes_added++; 354537d1343SAlexander V. Chernikov 355537d1343SAlexander V. Chernikov return (FLM_SUCCESS); 356537d1343SAlexander V. Chernikov } 357537d1343SAlexander V. Chernikov 358537d1343SAlexander V. Chernikov static enum flm_op_result 359537d1343SAlexander V. Chernikov check_dump_success(void *_data, struct fib_dp *dp) 360537d1343SAlexander V. Chernikov { 361537d1343SAlexander V. Chernikov struct dpdk_lpm6_data *dd; 362537d1343SAlexander V. Chernikov 363537d1343SAlexander V. Chernikov dd = (struct dpdk_lpm6_data *)_data; 364537d1343SAlexander V. Chernikov 365537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, dd->fd, "scan completed. added: %zu failed: %zu", 366537d1343SAlexander V. Chernikov dd->routes_added, dd->routes_failed); 367537d1343SAlexander V. Chernikov if (dd->hit_tables || dd->routes_failed > 0) 368537d1343SAlexander V. Chernikov return (FLM_REBUILD); 369537d1343SAlexander V. Chernikov 370537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, dd->fd, 371537d1343SAlexander V. Chernikov "DPDK lookup engine synced with IPv6 RIB id %u, %zu routes", 372537d1343SAlexander V. Chernikov dd->fibnum, dd->routes_added); 373537d1343SAlexander V. Chernikov 374537d1343SAlexander V. Chernikov dp->f = lookup_ptr; 375537d1343SAlexander V. Chernikov dp->arg = dd->lpm6; 376537d1343SAlexander V. Chernikov 377537d1343SAlexander V. Chernikov return (FLM_SUCCESS); 378537d1343SAlexander V. Chernikov } 379537d1343SAlexander V. Chernikov 380537d1343SAlexander V. Chernikov static void 381537d1343SAlexander V. Chernikov estimate_scale(const struct dpdk_lpm6_data *dd_src, struct dpdk_lpm6_data *dd) 382537d1343SAlexander V. Chernikov { 383537d1343SAlexander V. Chernikov 384537d1343SAlexander V. Chernikov /* XXX: update at 75% capacity */ 385537d1343SAlexander V. Chernikov if (dd_src->hit_tables) 386537d1343SAlexander V. Chernikov dd->number_tbl8s = dd_src->number_tbl8s * 2; 387537d1343SAlexander V. Chernikov else 388537d1343SAlexander V. Chernikov dd->number_tbl8s = dd_src->number_tbl8s; 389537d1343SAlexander V. Chernikov 390537d1343SAlexander V. Chernikov /* TODO: look into the appropriate RIB to adjust */ 391537d1343SAlexander V. Chernikov } 392537d1343SAlexander V. Chernikov 393537d1343SAlexander V. Chernikov static struct dpdk_lpm6_data * 394537d1343SAlexander V. Chernikov build_table(struct dpdk_lpm6_data *dd_prev, struct fib_data *fd) 395537d1343SAlexander V. Chernikov { 396537d1343SAlexander V. Chernikov struct dpdk_lpm6_data *dd; 397537d1343SAlexander V. Chernikov struct rte_lpm6 *lpm6; 398537d1343SAlexander V. Chernikov 399537d1343SAlexander V. Chernikov dd = malloc(sizeof(struct dpdk_lpm6_data), M_TEMP, M_NOWAIT | M_ZERO); 400537d1343SAlexander V. Chernikov if (dd == NULL) { 401537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, fd, "Unable to allocate base datastructure"); 402537d1343SAlexander V. Chernikov return (NULL); 403537d1343SAlexander V. Chernikov } 404537d1343SAlexander V. Chernikov dd->fibnum = dd_prev->fibnum; 405537d1343SAlexander V. Chernikov dd->fd = fd; 406537d1343SAlexander V. Chernikov 407537d1343SAlexander V. Chernikov estimate_scale(dd_prev, dd); 408537d1343SAlexander V. Chernikov 409537d1343SAlexander V. Chernikov struct rte_lpm6_config cfg = {.number_tbl8s = dd->number_tbl8s}; 410537d1343SAlexander V. Chernikov lpm6 = rte_lpm6_create("test", 0, &cfg); 411537d1343SAlexander V. Chernikov if (lpm6 == NULL) { 412537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, fd, "unable to create lpm6"); 413537d1343SAlexander V. Chernikov free(dd, M_TEMP); 414537d1343SAlexander V. Chernikov return (NULL); 415537d1343SAlexander V. Chernikov } 416537d1343SAlexander V. Chernikov dd->lpm6 = lpm6; 417537d1343SAlexander V. Chernikov struct rte_lpm6_external *ext = (struct rte_lpm6_external *)lpm6; 418537d1343SAlexander V. Chernikov ext->nh_idx = fib_get_nhop_array(dd->fd); 419537d1343SAlexander V. Chernikov 420537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, fd, "allocated %u tbl8s", dd->number_tbl8s); 421537d1343SAlexander V. Chernikov 422537d1343SAlexander V. Chernikov return (dd); 423537d1343SAlexander V. Chernikov } 424537d1343SAlexander V. Chernikov 425537d1343SAlexander V. Chernikov static enum flm_op_result 426537d1343SAlexander V. Chernikov init_table(uint32_t fibnum, struct fib_data *fd, void *_old_data, void **data) 427537d1343SAlexander V. Chernikov { 428537d1343SAlexander V. Chernikov struct dpdk_lpm6_data *dd, dd_base; 429537d1343SAlexander V. Chernikov 430537d1343SAlexander V. Chernikov if (_old_data == NULL) { 431537d1343SAlexander V. Chernikov bzero(&dd_base, sizeof(struct dpdk_lpm6_data)); 432537d1343SAlexander V. Chernikov dd_base.fibnum = fibnum; 433537d1343SAlexander V. Chernikov /* TODO: get rib statistics */ 434537d1343SAlexander V. Chernikov dd_base.number_tbl8s = LPM6_MIN_TBL8; 435537d1343SAlexander V. Chernikov dd = &dd_base; 436537d1343SAlexander V. Chernikov } else { 437537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, fd, "Starting with old data"); 438537d1343SAlexander V. Chernikov dd = (struct dpdk_lpm6_data *)_old_data; 439537d1343SAlexander V. Chernikov } 440537d1343SAlexander V. Chernikov 441537d1343SAlexander V. Chernikov /* Guaranteed to be in epoch */ 442537d1343SAlexander V. Chernikov dd = build_table(dd, fd); 443537d1343SAlexander V. Chernikov if (dd == NULL) { 444537d1343SAlexander V. Chernikov FIB_PRINTF(LOG_INFO, fd, "table creation failed"); 445537d1343SAlexander V. Chernikov return (FLM_REBUILD); 446537d1343SAlexander V. Chernikov } 447537d1343SAlexander V. Chernikov 448537d1343SAlexander V. Chernikov *data = dd; 449537d1343SAlexander V. Chernikov return (FLM_SUCCESS); 450537d1343SAlexander V. Chernikov } 451537d1343SAlexander V. Chernikov 452537d1343SAlexander V. Chernikov static struct fib_lookup_module dpdk_lpm6 = { 453537d1343SAlexander V. Chernikov .flm_name = "dpdk_lpm6", 454537d1343SAlexander V. Chernikov .flm_family = AF_INET6, 455537d1343SAlexander V. Chernikov .flm_init_cb = init_table, 456537d1343SAlexander V. Chernikov .flm_destroy_cb = destroy_table, 457537d1343SAlexander V. Chernikov .flm_dump_rib_item_cb = add_route_cb, 458537d1343SAlexander V. Chernikov .flm_dump_end_cb = check_dump_success, 459537d1343SAlexander V. Chernikov .flm_change_rib_item_cb = handle_rtable_change_cb, 460537d1343SAlexander V. Chernikov .flm_get_pref = rte6_get_pref, 461537d1343SAlexander V. Chernikov }; 462537d1343SAlexander V. Chernikov 463537d1343SAlexander V. Chernikov static int 464537d1343SAlexander V. Chernikov lpm6_modevent(module_t mod, int type, void *unused) 465537d1343SAlexander V. Chernikov { 466537d1343SAlexander V. Chernikov int error = 0; 467537d1343SAlexander V. Chernikov 468537d1343SAlexander V. Chernikov switch (type) { 469537d1343SAlexander V. Chernikov case MOD_LOAD: 470537d1343SAlexander V. Chernikov fib_module_register(&dpdk_lpm6); 471537d1343SAlexander V. Chernikov break; 472537d1343SAlexander V. Chernikov case MOD_UNLOAD: 473537d1343SAlexander V. Chernikov error = fib_module_unregister(&dpdk_lpm6); 474537d1343SAlexander V. Chernikov break; 475537d1343SAlexander V. Chernikov default: 476537d1343SAlexander V. Chernikov error = EOPNOTSUPP; 477537d1343SAlexander V. Chernikov break; 478537d1343SAlexander V. Chernikov } 479537d1343SAlexander V. Chernikov return (error); 480537d1343SAlexander V. Chernikov } 481537d1343SAlexander V. Chernikov 482537d1343SAlexander V. Chernikov static moduledata_t lpm6mod = { 483537d1343SAlexander V. Chernikov "dpdk_lpm6", 484537d1343SAlexander V. Chernikov lpm6_modevent, 485537d1343SAlexander V. Chernikov 0 486537d1343SAlexander V. Chernikov }; 487537d1343SAlexander V. Chernikov 488537d1343SAlexander V. Chernikov DECLARE_MODULE(lpm6mod, lpm6mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 489537d1343SAlexander V. Chernikov MODULE_VERSION(lpm6mod, 1); 490