1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /* Copyright (c) 2019-2021 Marvell International Ltd. All rights reserved */ 3 4 #include <linux/kernel.h> 5 #include <linux/types.h> 6 #include <linux/inetdevice.h> 7 #include <net/inet_dscp.h> 8 #include <net/switchdev.h> 9 #include <linux/rhashtable.h> 10 #include <net/nexthop.h> 11 12 #include "prestera.h" 13 #include "prestera_router_hw.h" 14 15 struct prestera_kern_fib_cache_key { 16 struct prestera_ip_addr addr; 17 u32 prefix_len; 18 u32 kern_tb_id; /* tb_id from kernel (not fixed) */ 19 }; 20 21 /* Subscribing on neighbours in kernel */ 22 struct prestera_kern_fib_cache { 23 struct prestera_kern_fib_cache_key key; 24 struct { 25 struct prestera_fib_key fib_key; 26 enum prestera_fib_type fib_type; 27 } lpm_info; /* hold prepared lpm info */ 28 /* Indicate if route is not overlapped by another table */ 29 struct rhash_head ht_node; /* node of prestera_router */ 30 union { 31 struct fib_notifier_info info; /* point to any of 4/6 */ 32 struct fib_entry_notifier_info fen4_info; 33 }; 34 bool reachable; 35 }; 36 37 static const struct rhashtable_params __prestera_kern_fib_cache_ht_params = { 38 .key_offset = offsetof(struct prestera_kern_fib_cache, key), 39 .head_offset = offsetof(struct prestera_kern_fib_cache, ht_node), 40 .key_len = sizeof(struct prestera_kern_fib_cache_key), 41 .automatic_shrinking = true, 42 }; 43 44 /* This util to be used, to convert kernel rules for default vr in hw_vr */ 45 static u32 prestera_fix_tb_id(u32 tb_id) 46 { 47 if (tb_id == RT_TABLE_UNSPEC || 48 tb_id == RT_TABLE_LOCAL || 49 tb_id == RT_TABLE_DEFAULT) 50 tb_id = RT_TABLE_MAIN; 51 52 return tb_id; 53 } 54 55 static void 56 prestera_util_fen_info2fib_cache_key(struct fib_notifier_info *info, 57 struct prestera_kern_fib_cache_key *key) 58 { 59 struct fib_entry_notifier_info *fen_info = 60 container_of(info, struct fib_entry_notifier_info, info); 61 62 memset(key, 0, sizeof(*key)); 63 key->addr.v = PRESTERA_IPV4; 64 key->addr.u.ipv4 = cpu_to_be32(fen_info->dst); 65 key->prefix_len = fen_info->dst_len; 66 key->kern_tb_id = fen_info->tb_id; 67 } 68 69 static unsigned char 70 prestera_kern_fib_info_type(struct fib_notifier_info *info) 71 { 72 struct fib6_entry_notifier_info *fen6_info; 73 struct fib_entry_notifier_info *fen4_info; 74 75 if (info->family == AF_INET) { 76 fen4_info = container_of(info, struct fib_entry_notifier_info, 77 info); 78 return fen4_info->fi->fib_type; 79 } else if (info->family == AF_INET6) { 80 fen6_info = container_of(info, struct fib6_entry_notifier_info, 81 info); 82 /* TODO: ECMP in ipv6 is several routes. 83 * Every route has single nh. 84 */ 85 return fen6_info->rt->fib6_type; 86 } 87 88 return RTN_UNSPEC; 89 } 90 91 static struct prestera_kern_fib_cache * 92 prestera_kern_fib_cache_find(struct prestera_switch *sw, 93 struct prestera_kern_fib_cache_key *key) 94 { 95 struct prestera_kern_fib_cache *fib_cache; 96 97 fib_cache = 98 rhashtable_lookup_fast(&sw->router->kern_fib_cache_ht, key, 99 __prestera_kern_fib_cache_ht_params); 100 return fib_cache; 101 } 102 103 static void 104 __prestera_kern_fib_cache_destruct(struct prestera_switch *sw, 105 struct prestera_kern_fib_cache *fib_cache) 106 { 107 fib_info_put(fib_cache->fen4_info.fi); 108 } 109 110 static void 111 prestera_kern_fib_cache_destroy(struct prestera_switch *sw, 112 struct prestera_kern_fib_cache *fib_cache) 113 { 114 rhashtable_remove_fast(&sw->router->kern_fib_cache_ht, 115 &fib_cache->ht_node, 116 __prestera_kern_fib_cache_ht_params); 117 __prestera_kern_fib_cache_destruct(sw, fib_cache); 118 kfree(fib_cache); 119 } 120 121 /* Operations on fi (offload, etc) must be wrapped in utils. 122 * This function just create storage. 123 */ 124 static struct prestera_kern_fib_cache * 125 prestera_kern_fib_cache_create(struct prestera_switch *sw, 126 struct prestera_kern_fib_cache_key *key, 127 struct fib_notifier_info *info) 128 { 129 struct fib_entry_notifier_info *fen_info = 130 container_of(info, struct fib_entry_notifier_info, info); 131 struct prestera_kern_fib_cache *fib_cache; 132 int err; 133 134 fib_cache = kzalloc(sizeof(*fib_cache), GFP_KERNEL); 135 if (!fib_cache) 136 goto err_kzalloc; 137 138 memcpy(&fib_cache->key, key, sizeof(*key)); 139 fib_info_hold(fen_info->fi); 140 memcpy(&fib_cache->fen4_info, fen_info, sizeof(*fen_info)); 141 142 err = rhashtable_insert_fast(&sw->router->kern_fib_cache_ht, 143 &fib_cache->ht_node, 144 __prestera_kern_fib_cache_ht_params); 145 if (err) 146 goto err_ht_insert; 147 148 return fib_cache; 149 150 err_ht_insert: 151 fib_info_put(fen_info->fi); 152 kfree(fib_cache); 153 err_kzalloc: 154 return NULL; 155 } 156 157 static void 158 __prestera_k_arb_fib_lpm_offload_set(struct prestera_switch *sw, 159 struct prestera_kern_fib_cache *fc, 160 bool fail, bool offload, bool trap) 161 { 162 struct fib_rt_info fri; 163 164 switch (fc->key.addr.v) { 165 case PRESTERA_IPV4: 166 fri.fi = fc->fen4_info.fi; 167 fri.tb_id = fc->key.kern_tb_id; 168 fri.dst = fc->key.addr.u.ipv4; 169 fri.dst_len = fc->key.prefix_len; 170 fri.dscp = fc->fen4_info.dscp; 171 fri.type = fc->fen4_info.type; 172 /* flags begin */ 173 fri.offload = offload; 174 fri.trap = trap; 175 fri.offload_failed = fail; 176 /* flags end */ 177 fib_alias_hw_flags_set(&init_net, &fri); 178 return; 179 case PRESTERA_IPV6: 180 /* TODO */ 181 return; 182 } 183 } 184 185 static int 186 __prestera_pr_k_arb_fc_lpm_info_calc(struct prestera_switch *sw, 187 struct prestera_kern_fib_cache *fc) 188 { 189 memset(&fc->lpm_info, 0, sizeof(fc->lpm_info)); 190 191 switch (prestera_kern_fib_info_type(&fc->info)) { 192 case RTN_UNICAST: 193 fc->lpm_info.fib_type = PRESTERA_FIB_TYPE_TRAP; 194 break; 195 /* Unsupported. Leave it for kernel: */ 196 case RTN_BROADCAST: 197 case RTN_MULTICAST: 198 /* Routes we must trap by design: */ 199 case RTN_LOCAL: 200 case RTN_UNREACHABLE: 201 case RTN_PROHIBIT: 202 fc->lpm_info.fib_type = PRESTERA_FIB_TYPE_TRAP; 203 break; 204 case RTN_BLACKHOLE: 205 fc->lpm_info.fib_type = PRESTERA_FIB_TYPE_DROP; 206 break; 207 default: 208 dev_err(sw->dev->dev, "Unsupported fib_type"); 209 return -EOPNOTSUPP; 210 } 211 212 fc->lpm_info.fib_key.addr = fc->key.addr; 213 fc->lpm_info.fib_key.prefix_len = fc->key.prefix_len; 214 fc->lpm_info.fib_key.tb_id = prestera_fix_tb_id(fc->key.kern_tb_id); 215 216 return 0; 217 } 218 219 static int __prestera_k_arb_f_lpm_set(struct prestera_switch *sw, 220 struct prestera_kern_fib_cache *fc, 221 bool enabled) 222 { 223 struct prestera_fib_node *fib_node; 224 225 fib_node = prestera_fib_node_find(sw, &fc->lpm_info.fib_key); 226 if (fib_node) 227 prestera_fib_node_destroy(sw, fib_node); 228 229 if (!enabled) 230 return 0; 231 232 fib_node = prestera_fib_node_create(sw, &fc->lpm_info.fib_key, 233 fc->lpm_info.fib_type, NULL); 234 235 if (!fib_node) { 236 dev_err(sw->dev->dev, "fib_node=NULL %pI4n/%d kern_tb_id = %d", 237 &fc->key.addr.u.ipv4, fc->key.prefix_len, 238 fc->key.kern_tb_id); 239 return -ENOENT; 240 } 241 242 return 0; 243 } 244 245 static int __prestera_k_arb_fc_apply(struct prestera_switch *sw, 246 struct prestera_kern_fib_cache *fc) 247 { 248 int err; 249 250 err = __prestera_pr_k_arb_fc_lpm_info_calc(sw, fc); 251 if (err) 252 return err; 253 254 err = __prestera_k_arb_f_lpm_set(sw, fc, fc->reachable); 255 if (err) { 256 __prestera_k_arb_fib_lpm_offload_set(sw, fc, 257 true, false, false); 258 return err; 259 } 260 261 switch (fc->lpm_info.fib_type) { 262 case PRESTERA_FIB_TYPE_UC_NH: 263 break; 264 case PRESTERA_FIB_TYPE_TRAP: 265 __prestera_k_arb_fib_lpm_offload_set(sw, fc, false, 266 false, fc->reachable); 267 break; 268 case PRESTERA_FIB_TYPE_DROP: 269 __prestera_k_arb_fib_lpm_offload_set(sw, fc, false, true, 270 fc->reachable); 271 break; 272 case PRESTERA_FIB_TYPE_INVALID: 273 break; 274 } 275 276 return 0; 277 } 278 279 static struct prestera_kern_fib_cache * 280 __prestera_k_arb_util_fib_overlaps(struct prestera_switch *sw, 281 struct prestera_kern_fib_cache *fc) 282 { 283 struct prestera_kern_fib_cache_key fc_key; 284 struct prestera_kern_fib_cache *rfc; 285 286 /* TODO: parse kernel rules */ 287 rfc = NULL; 288 if (fc->key.kern_tb_id == RT_TABLE_LOCAL) { 289 memcpy(&fc_key, &fc->key, sizeof(fc_key)); 290 fc_key.kern_tb_id = RT_TABLE_MAIN; 291 rfc = prestera_kern_fib_cache_find(sw, &fc_key); 292 } 293 294 return rfc; 295 } 296 297 static struct prestera_kern_fib_cache * 298 __prestera_k_arb_util_fib_overlapped(struct prestera_switch *sw, 299 struct prestera_kern_fib_cache *fc) 300 { 301 struct prestera_kern_fib_cache_key fc_key; 302 struct prestera_kern_fib_cache *rfc; 303 304 /* TODO: parse kernel rules */ 305 rfc = NULL; 306 if (fc->key.kern_tb_id == RT_TABLE_MAIN) { 307 memcpy(&fc_key, &fc->key, sizeof(fc_key)); 308 fc_key.kern_tb_id = RT_TABLE_LOCAL; 309 rfc = prestera_kern_fib_cache_find(sw, &fc_key); 310 } 311 312 return rfc; 313 } 314 315 static int 316 prestera_k_arb_fib_evt(struct prestera_switch *sw, 317 bool replace, /* replace or del */ 318 struct fib_notifier_info *info) 319 { 320 struct prestera_kern_fib_cache *tfib_cache, *bfib_cache; /* top/btm */ 321 struct prestera_kern_fib_cache_key fc_key; 322 struct prestera_kern_fib_cache *fib_cache; 323 int err; 324 325 prestera_util_fen_info2fib_cache_key(info, &fc_key); 326 fib_cache = prestera_kern_fib_cache_find(sw, &fc_key); 327 if (fib_cache) { 328 fib_cache->reachable = false; 329 err = __prestera_k_arb_fc_apply(sw, fib_cache); 330 if (err) 331 dev_err(sw->dev->dev, 332 "Applying destroyed fib_cache failed"); 333 334 bfib_cache = __prestera_k_arb_util_fib_overlaps(sw, fib_cache); 335 tfib_cache = __prestera_k_arb_util_fib_overlapped(sw, fib_cache); 336 if (!tfib_cache && bfib_cache) { 337 bfib_cache->reachable = true; 338 err = __prestera_k_arb_fc_apply(sw, bfib_cache); 339 if (err) 340 dev_err(sw->dev->dev, 341 "Applying fib_cache btm failed"); 342 } 343 344 prestera_kern_fib_cache_destroy(sw, fib_cache); 345 } 346 347 if (replace) { 348 fib_cache = prestera_kern_fib_cache_create(sw, &fc_key, info); 349 if (!fib_cache) { 350 dev_err(sw->dev->dev, "fib_cache == NULL"); 351 return -ENOENT; 352 } 353 354 bfib_cache = __prestera_k_arb_util_fib_overlaps(sw, fib_cache); 355 tfib_cache = __prestera_k_arb_util_fib_overlapped(sw, fib_cache); 356 if (!tfib_cache) 357 fib_cache->reachable = true; 358 359 if (bfib_cache) { 360 bfib_cache->reachable = false; 361 err = __prestera_k_arb_fc_apply(sw, bfib_cache); 362 if (err) 363 dev_err(sw->dev->dev, 364 "Applying fib_cache btm failed"); 365 } 366 367 err = __prestera_k_arb_fc_apply(sw, fib_cache); 368 if (err) 369 dev_err(sw->dev->dev, "Applying fib_cache failed"); 370 } 371 372 return 0; 373 } 374 375 static void __prestera_k_arb_abort_fib_ht_cb(void *ptr, void *arg) 376 { 377 struct prestera_kern_fib_cache *fib_cache = ptr; 378 struct prestera_switch *sw = arg; 379 380 __prestera_k_arb_fib_lpm_offload_set(sw, fib_cache, 381 false, false, 382 false); 383 /* No need to destroy lpm. 384 * It will be aborted by destroy_ht 385 */ 386 __prestera_kern_fib_cache_destruct(sw, fib_cache); 387 kfree(fib_cache); 388 } 389 390 static void prestera_k_arb_abort(struct prestera_switch *sw) 391 { 392 /* Function to remove all arbiter entries and related hw objects. */ 393 /* Sequence: 394 * 1) Clear arbiter tables, but don't touch hw 395 * 2) Clear hw 396 * We use such approach, because arbiter object is not directly mapped 397 * to hw. So deletion of one arbiter object may even lead to creation of 398 * hw object (e.g. in case of overlapped routes). 399 */ 400 rhashtable_free_and_destroy(&sw->router->kern_fib_cache_ht, 401 __prestera_k_arb_abort_fib_ht_cb, 402 sw); 403 } 404 405 static int __prestera_inetaddr_port_event(struct net_device *port_dev, 406 unsigned long event, 407 struct netlink_ext_ack *extack) 408 { 409 struct prestera_port *port = netdev_priv(port_dev); 410 struct prestera_rif_entry_key re_key = {}; 411 struct prestera_rif_entry *re; 412 u32 kern_tb_id; 413 int err; 414 415 err = prestera_is_valid_mac_addr(port, port_dev->dev_addr); 416 if (err) { 417 NL_SET_ERR_MSG_MOD(extack, "RIF MAC must have the same prefix"); 418 return err; 419 } 420 421 kern_tb_id = l3mdev_fib_table(port_dev); 422 re_key.iface.type = PRESTERA_IF_PORT_E; 423 re_key.iface.dev_port.hw_dev_num = port->dev_id; 424 re_key.iface.dev_port.port_num = port->hw_id; 425 re = prestera_rif_entry_find(port->sw, &re_key); 426 427 switch (event) { 428 case NETDEV_UP: 429 if (re) { 430 NL_SET_ERR_MSG_MOD(extack, "RIF already exist"); 431 return -EEXIST; 432 } 433 re = prestera_rif_entry_create(port->sw, &re_key, 434 prestera_fix_tb_id(kern_tb_id), 435 port_dev->dev_addr); 436 if (!re) { 437 NL_SET_ERR_MSG_MOD(extack, "Can't create RIF"); 438 return -EINVAL; 439 } 440 dev_hold(port_dev); 441 break; 442 case NETDEV_DOWN: 443 if (!re) { 444 NL_SET_ERR_MSG_MOD(extack, "Can't find RIF"); 445 return -EEXIST; 446 } 447 prestera_rif_entry_destroy(port->sw, re); 448 dev_put(port_dev); 449 break; 450 } 451 452 return 0; 453 } 454 455 static int __prestera_inetaddr_event(struct prestera_switch *sw, 456 struct net_device *dev, 457 unsigned long event, 458 struct netlink_ext_ack *extack) 459 { 460 if (!prestera_netdev_check(dev) || netif_is_any_bridge_port(dev) || 461 netif_is_lag_port(dev)) 462 return 0; 463 464 return __prestera_inetaddr_port_event(dev, event, extack); 465 } 466 467 static int __prestera_inetaddr_cb(struct notifier_block *nb, 468 unsigned long event, void *ptr) 469 { 470 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; 471 struct net_device *dev = ifa->ifa_dev->dev; 472 struct prestera_router *router = container_of(nb, 473 struct prestera_router, 474 inetaddr_nb); 475 struct in_device *idev; 476 int err = 0; 477 478 if (event != NETDEV_DOWN) 479 goto out; 480 481 /* Ignore if this is not latest address */ 482 idev = __in_dev_get_rtnl(dev); 483 if (idev && idev->ifa_list) 484 goto out; 485 486 err = __prestera_inetaddr_event(router->sw, dev, event, NULL); 487 out: 488 return notifier_from_errno(err); 489 } 490 491 static int __prestera_inetaddr_valid_cb(struct notifier_block *nb, 492 unsigned long event, void *ptr) 493 { 494 struct in_validator_info *ivi = (struct in_validator_info *)ptr; 495 struct net_device *dev = ivi->ivi_dev->dev; 496 struct prestera_router *router = container_of(nb, 497 struct prestera_router, 498 inetaddr_valid_nb); 499 struct in_device *idev; 500 int err = 0; 501 502 if (event != NETDEV_UP) 503 goto out; 504 505 /* Ignore if this is not first address */ 506 idev = __in_dev_get_rtnl(dev); 507 if (idev && idev->ifa_list) 508 goto out; 509 510 if (ipv4_is_multicast(ivi->ivi_addr)) { 511 NL_SET_ERR_MSG_MOD(ivi->extack, 512 "Multicast addr on RIF is not supported"); 513 err = -EINVAL; 514 goto out; 515 } 516 517 err = __prestera_inetaddr_event(router->sw, dev, event, ivi->extack); 518 out: 519 return notifier_from_errno(err); 520 } 521 522 struct prestera_fib_event_work { 523 struct work_struct work; 524 struct prestera_switch *sw; 525 struct fib_entry_notifier_info fen_info; 526 unsigned long event; 527 }; 528 529 static void __prestera_router_fib_event_work(struct work_struct *work) 530 { 531 struct prestera_fib_event_work *fib_work = 532 container_of(work, struct prestera_fib_event_work, work); 533 struct prestera_switch *sw = fib_work->sw; 534 int err; 535 536 rtnl_lock(); 537 538 switch (fib_work->event) { 539 case FIB_EVENT_ENTRY_REPLACE: 540 err = prestera_k_arb_fib_evt(sw, true, 541 &fib_work->fen_info.info); 542 if (err) 543 goto err_out; 544 545 break; 546 case FIB_EVENT_ENTRY_DEL: 547 err = prestera_k_arb_fib_evt(sw, false, 548 &fib_work->fen_info.info); 549 if (err) 550 goto err_out; 551 552 break; 553 } 554 555 goto out; 556 557 err_out: 558 dev_err(sw->dev->dev, "Error when processing %pI4h/%d", 559 &fib_work->fen_info.dst, 560 fib_work->fen_info.dst_len); 561 out: 562 fib_info_put(fib_work->fen_info.fi); 563 rtnl_unlock(); 564 kfree(fib_work); 565 } 566 567 /* Called with rcu_read_lock() */ 568 static int __prestera_router_fib_event(struct notifier_block *nb, 569 unsigned long event, void *ptr) 570 { 571 struct prestera_fib_event_work *fib_work; 572 struct fib_entry_notifier_info *fen_info; 573 struct fib_notifier_info *info = ptr; 574 struct prestera_router *router; 575 576 if (info->family != AF_INET) 577 return NOTIFY_DONE; 578 579 router = container_of(nb, struct prestera_router, fib_nb); 580 581 switch (event) { 582 case FIB_EVENT_ENTRY_REPLACE: 583 case FIB_EVENT_ENTRY_DEL: 584 fen_info = container_of(info, struct fib_entry_notifier_info, 585 info); 586 if (!fen_info->fi) 587 return NOTIFY_DONE; 588 589 fib_work = kzalloc(sizeof(*fib_work), GFP_ATOMIC); 590 if (WARN_ON(!fib_work)) 591 return NOTIFY_BAD; 592 593 fib_info_hold(fen_info->fi); 594 fib_work->fen_info = *fen_info; 595 fib_work->event = event; 596 fib_work->sw = router->sw; 597 INIT_WORK(&fib_work->work, __prestera_router_fib_event_work); 598 prestera_queue_work(&fib_work->work); 599 break; 600 default: 601 return NOTIFY_DONE; 602 } 603 604 return NOTIFY_DONE; 605 } 606 607 int prestera_router_init(struct prestera_switch *sw) 608 { 609 struct prestera_router *router; 610 int err, nhgrp_cache_bytes; 611 612 router = kzalloc(sizeof(*sw->router), GFP_KERNEL); 613 if (!router) 614 return -ENOMEM; 615 616 sw->router = router; 617 router->sw = sw; 618 619 err = prestera_router_hw_init(sw); 620 if (err) 621 goto err_router_lib_init; 622 623 err = rhashtable_init(&router->kern_fib_cache_ht, 624 &__prestera_kern_fib_cache_ht_params); 625 if (err) 626 goto err_kern_fib_cache_ht_init; 627 628 nhgrp_cache_bytes = sw->size_tbl_router_nexthop / 8 + 1; 629 router->nhgrp_hw_state_cache = kzalloc(nhgrp_cache_bytes, GFP_KERNEL); 630 if (!router->nhgrp_hw_state_cache) { 631 err = -ENOMEM; 632 goto err_nh_state_cache_alloc; 633 } 634 635 router->inetaddr_valid_nb.notifier_call = __prestera_inetaddr_valid_cb; 636 err = register_inetaddr_validator_notifier(&router->inetaddr_valid_nb); 637 if (err) 638 goto err_register_inetaddr_validator_notifier; 639 640 router->inetaddr_nb.notifier_call = __prestera_inetaddr_cb; 641 err = register_inetaddr_notifier(&router->inetaddr_nb); 642 if (err) 643 goto err_register_inetaddr_notifier; 644 645 router->fib_nb.notifier_call = __prestera_router_fib_event; 646 err = register_fib_notifier(&init_net, &router->fib_nb, 647 /* TODO: flush fib entries */ NULL, NULL); 648 if (err) 649 goto err_register_fib_notifier; 650 651 return 0; 652 653 err_register_fib_notifier: 654 unregister_inetaddr_notifier(&router->inetaddr_nb); 655 err_register_inetaddr_notifier: 656 unregister_inetaddr_validator_notifier(&router->inetaddr_valid_nb); 657 err_register_inetaddr_validator_notifier: 658 kfree(router->nhgrp_hw_state_cache); 659 err_nh_state_cache_alloc: 660 rhashtable_destroy(&router->kern_fib_cache_ht); 661 err_kern_fib_cache_ht_init: 662 prestera_router_hw_fini(sw); 663 err_router_lib_init: 664 kfree(sw->router); 665 return err; 666 } 667 668 void prestera_router_fini(struct prestera_switch *sw) 669 { 670 unregister_fib_notifier(&init_net, &sw->router->fib_nb); 671 unregister_inetaddr_notifier(&sw->router->inetaddr_nb); 672 unregister_inetaddr_validator_notifier(&sw->router->inetaddr_valid_nb); 673 prestera_queue_drain(); 674 675 prestera_k_arb_abort(sw); 676 677 kfree(sw->router->nhgrp_hw_state_cache); 678 rhashtable_destroy(&sw->router->kern_fib_cache_ht); 679 prestera_router_hw_fini(sw); 680 kfree(sw->router); 681 sw->router = NULL; 682 } 683