^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Copyright (c) 2018 Cumulus Networks. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2018 David Ahern <dsa@cumulusnetworks.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * This software is licensed under the GNU General License Version 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * June 1991 as shown in the file COPYING in the top-level directory of this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * source tree.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/in6.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/rhashtable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/spinlock_types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <net/fib_notifier.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <net/ip_fib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <net/ip6_fib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <net/fib_rules.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <net/net_namespace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include "netdevsim.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct nsim_fib_entry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) u64 max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) u64 num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct nsim_per_fib_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct nsim_fib_entry fib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct nsim_fib_entry rules;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct nsim_fib_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct notifier_block fib_nb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct nsim_per_fib_data ipv4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct nsim_per_fib_data ipv6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct rhashtable fib_rt_ht;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct list_head fib_rt_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) spinlock_t fib_lock; /* Protects hashtable, list and accounting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct devlink *devlink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct nsim_fib_rt_key {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) unsigned char addr[sizeof(struct in6_addr)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) unsigned char prefix_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) int family;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) u32 tb_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct nsim_fib_rt {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct nsim_fib_rt_key key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct rhash_head ht_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct list_head list; /* Member of fib_rt_list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct nsim_fib4_rt {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct nsim_fib_rt common;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct fib_info *fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) u8 tos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u8 type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct nsim_fib6_rt {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct nsim_fib_rt common;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct list_head nh_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) unsigned int nhs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct nsim_fib6_rt_nh {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) struct list_head list; /* Member of nh_list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct fib6_info *rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static const struct rhashtable_params nsim_fib_rt_ht_params = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) .key_offset = offsetof(struct nsim_fib_rt, key),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) .head_offset = offsetof(struct nsim_fib_rt, ht_node),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) .key_len = sizeof(struct nsim_fib_rt_key),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) .automatic_shrinking = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) u64 nsim_fib_get_val(struct nsim_fib_data *fib_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) enum nsim_resource_id res_id, bool max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct nsim_fib_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) switch (res_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) case NSIM_RESOURCE_IPV4_FIB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) entry = &fib_data->ipv4.fib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) case NSIM_RESOURCE_IPV4_FIB_RULES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) entry = &fib_data->ipv4.rules;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) case NSIM_RESOURCE_IPV6_FIB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) entry = &fib_data->ipv6.fib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) case NSIM_RESOURCE_IPV6_FIB_RULES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) entry = &fib_data->ipv6.rules;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return max ? entry->max : entry->num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static void nsim_fib_set_max(struct nsim_fib_data *fib_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) enum nsim_resource_id res_id, u64 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct nsim_fib_entry *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) switch (res_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) case NSIM_RESOURCE_IPV4_FIB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) entry = &fib_data->ipv4.fib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) case NSIM_RESOURCE_IPV4_FIB_RULES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) entry = &fib_data->ipv4.rules;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) case NSIM_RESOURCE_IPV6_FIB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) entry = &fib_data->ipv6.fib;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) case NSIM_RESOURCE_IPV6_FIB_RULES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) entry = &fib_data->ipv6.rules;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) WARN_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) entry->max = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) static int nsim_fib_rule_account(struct nsim_fib_entry *entry, bool add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (add) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (entry->num < entry->max) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) entry->num++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) err = -ENOSPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported fib rule entries");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) entry->num--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static int nsim_fib_rule_event(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct fib_notifier_info *info, bool add)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) struct netlink_ext_ack *extack = info->extack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) switch (info->family) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) case AF_INET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) err = nsim_fib_rule_account(&data->ipv4.rules, add, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) case AF_INET6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) err = nsim_fib_rule_account(&data->ipv6.rules, add, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) static int nsim_fib_account(struct nsim_fib_entry *entry, bool add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (add) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (entry->num < entry->max) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) entry->num++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) err = -ENOSPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported fib entries");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) entry->num--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static void nsim_fib_rt_init(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) struct nsim_fib_rt *fib_rt, const void *addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) size_t addr_len, unsigned int prefix_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) int family, u32 tb_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) memcpy(fib_rt->key.addr, addr, addr_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) fib_rt->key.prefix_len = prefix_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) fib_rt->key.family = family;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) fib_rt->key.tb_id = tb_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) list_add(&fib_rt->list, &data->fib_rt_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) static void nsim_fib_rt_fini(struct nsim_fib_rt *fib_rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) list_del(&fib_rt->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) static struct nsim_fib_rt *nsim_fib_rt_lookup(struct rhashtable *fib_rt_ht,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) const void *addr, size_t addr_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) unsigned int prefix_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) int family, u32 tb_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) struct nsim_fib_rt_key key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) memset(&key, 0, sizeof(key));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) memcpy(key.addr, addr, addr_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) key.prefix_len = prefix_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) key.family = family;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) key.tb_id = tb_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return rhashtable_lookup_fast(fib_rt_ht, &key, nsim_fib_rt_ht_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) static struct nsim_fib4_rt *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) nsim_fib4_rt_create(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) struct fib_entry_notifier_info *fen_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) struct nsim_fib4_rt *fib4_rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) fib4_rt = kzalloc(sizeof(*fib4_rt), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (!fib4_rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) nsim_fib_rt_init(data, &fib4_rt->common, &fen_info->dst, sizeof(u32),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) fen_info->dst_len, AF_INET, fen_info->tb_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) fib4_rt->fi = fen_info->fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) fib_info_hold(fib4_rt->fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) fib4_rt->tos = fen_info->tos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) fib4_rt->type = fen_info->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return fib4_rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) static void nsim_fib4_rt_destroy(struct nsim_fib4_rt *fib4_rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) fib_info_put(fib4_rt->fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) nsim_fib_rt_fini(&fib4_rt->common);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) kfree(fib4_rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) static struct nsim_fib4_rt *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) nsim_fib4_rt_lookup(struct rhashtable *fib_rt_ht,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) const struct fib_entry_notifier_info *fen_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) struct nsim_fib_rt *fib_rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) fib_rt = nsim_fib_rt_lookup(fib_rt_ht, &fen_info->dst, sizeof(u32),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) fen_info->dst_len, AF_INET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) fen_info->tb_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (!fib_rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return container_of(fib_rt, struct nsim_fib4_rt, common);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) static void nsim_fib4_rt_hw_flags_set(struct net *net,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) const struct nsim_fib4_rt *fib4_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) bool trap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) u32 *p_dst = (u32 *) fib4_rt->common.key.addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) int dst_len = fib4_rt->common.key.prefix_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) struct fib_rt_info fri;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) fri.fi = fib4_rt->fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) fri.tb_id = fib4_rt->common.key.tb_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) fri.dst = cpu_to_be32(*p_dst);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) fri.dst_len = dst_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) fri.tos = fib4_rt->tos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) fri.type = fib4_rt->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) fri.offload = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) fri.trap = trap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) fib_alias_hw_flags_set(net, &fri);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) static int nsim_fib4_rt_add(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) struct nsim_fib4_rt *fib4_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct net *net = devlink_net(data->devlink);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) err = nsim_fib_account(&data->ipv4.fib, true, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) err = rhashtable_insert_fast(&data->fib_rt_ht,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) &fib4_rt->common.ht_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) nsim_fib_rt_ht_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) NL_SET_ERR_MSG_MOD(extack, "Failed to insert IPv4 route");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) goto err_fib_dismiss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) nsim_fib4_rt_hw_flags_set(net, fib4_rt, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) err_fib_dismiss:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) nsim_fib_account(&data->ipv4.fib, false, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) static int nsim_fib4_rt_replace(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) struct nsim_fib4_rt *fib4_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) struct nsim_fib4_rt *fib4_rt_old,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) struct net *net = devlink_net(data->devlink);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) /* We are replacing a route, so no need to change the accounting. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) err = rhashtable_replace_fast(&data->fib_rt_ht,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) &fib4_rt_old->common.ht_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) &fib4_rt->common.ht_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) nsim_fib_rt_ht_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) NL_SET_ERR_MSG_MOD(extack, "Failed to replace IPv4 route");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) nsim_fib4_rt_hw_flags_set(net, fib4_rt, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) nsim_fib4_rt_hw_flags_set(net, fib4_rt_old, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) nsim_fib4_rt_destroy(fib4_rt_old);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static int nsim_fib4_rt_insert(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) struct fib_entry_notifier_info *fen_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) struct netlink_ext_ack *extack = fen_info->info.extack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) struct nsim_fib4_rt *fib4_rt, *fib4_rt_old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) fib4_rt = nsim_fib4_rt_create(data, fen_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) if (!fib4_rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) fib4_rt_old = nsim_fib4_rt_lookup(&data->fib_rt_ht, fen_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (!fib4_rt_old)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) err = nsim_fib4_rt_add(data, fib4_rt, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) err = nsim_fib4_rt_replace(data, fib4_rt, fib4_rt_old, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) nsim_fib4_rt_destroy(fib4_rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) static void nsim_fib4_rt_remove(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) const struct fib_entry_notifier_info *fen_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) struct netlink_ext_ack *extack = fen_info->info.extack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) struct nsim_fib4_rt *fib4_rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) fib4_rt = nsim_fib4_rt_lookup(&data->fib_rt_ht, fen_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (WARN_ON_ONCE(!fib4_rt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) rhashtable_remove_fast(&data->fib_rt_ht, &fib4_rt->common.ht_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) nsim_fib_rt_ht_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) nsim_fib_account(&data->ipv4.fib, false, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) nsim_fib4_rt_destroy(fib4_rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) static int nsim_fib4_event(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) struct fib_notifier_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) unsigned long event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) struct fib_entry_notifier_info *fen_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) fen_info = container_of(info, struct fib_entry_notifier_info, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) if (fen_info->fi->nh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) NL_SET_ERR_MSG_MOD(info->extack, "IPv4 route with nexthop objects is not supported");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) case FIB_EVENT_ENTRY_REPLACE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) err = nsim_fib4_rt_insert(data, fen_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) case FIB_EVENT_ENTRY_DEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) nsim_fib4_rt_remove(data, fen_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) static struct nsim_fib6_rt_nh *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) nsim_fib6_rt_nh_find(const struct nsim_fib6_rt *fib6_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) const struct fib6_info *rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) struct nsim_fib6_rt_nh *fib6_rt_nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) list_for_each_entry(fib6_rt_nh, &fib6_rt->nh_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (fib6_rt_nh->rt == rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) return fib6_rt_nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) static int nsim_fib6_rt_nh_add(struct nsim_fib6_rt *fib6_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) struct fib6_info *rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) struct nsim_fib6_rt_nh *fib6_rt_nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) fib6_rt_nh = kzalloc(sizeof(*fib6_rt_nh), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) if (!fib6_rt_nh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) fib6_info_hold(rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) fib6_rt_nh->rt = rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) list_add_tail(&fib6_rt_nh->list, &fib6_rt->nh_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) fib6_rt->nhs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) static void nsim_fib6_rt_nh_del(struct nsim_fib6_rt *fib6_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) const struct fib6_info *rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) struct nsim_fib6_rt_nh *fib6_rt_nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) fib6_rt_nh = nsim_fib6_rt_nh_find(fib6_rt, rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) if (WARN_ON_ONCE(!fib6_rt_nh))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) fib6_rt->nhs--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) list_del(&fib6_rt_nh->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) #if IS_ENABLED(CONFIG_IPV6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) fib6_info_release(fib6_rt_nh->rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) kfree(fib6_rt_nh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) static struct nsim_fib6_rt *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) nsim_fib6_rt_create(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) struct fib6_entry_notifier_info *fen6_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) struct fib6_info *iter, *rt = fen6_info->rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) struct nsim_fib6_rt *fib6_rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) fib6_rt = kzalloc(sizeof(*fib6_rt), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) if (!fib6_rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) nsim_fib_rt_init(data, &fib6_rt->common, &rt->fib6_dst.addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) sizeof(rt->fib6_dst.addr), rt->fib6_dst.plen, AF_INET6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) rt->fib6_table->tb6_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) /* We consider a multipath IPv6 route as one entry, but it can be made
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) * up from several fib6_info structs (one for each nexthop), so we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) * add them all to the same list under the entry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) INIT_LIST_HEAD(&fib6_rt->nh_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) err = nsim_fib6_rt_nh_add(fib6_rt, rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) goto err_fib_rt_fini;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (!fen6_info->nsiblings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return fib6_rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) if (i == fen6_info->nsiblings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) err = nsim_fib6_rt_nh_add(fib6_rt, iter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) goto err_fib6_rt_nh_del;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) WARN_ON_ONCE(i != fen6_info->nsiblings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) return fib6_rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) err_fib6_rt_nh_del:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) list_for_each_entry_continue_reverse(iter, &rt->fib6_siblings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) fib6_siblings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) nsim_fib6_rt_nh_del(fib6_rt, iter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) nsim_fib6_rt_nh_del(fib6_rt, rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) err_fib_rt_fini:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) nsim_fib_rt_fini(&fib6_rt->common);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) kfree(fib6_rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) return ERR_PTR(err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) static void nsim_fib6_rt_destroy(struct nsim_fib6_rt *fib6_rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) struct nsim_fib6_rt_nh *iter, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) list_for_each_entry_safe(iter, tmp, &fib6_rt->nh_list, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) nsim_fib6_rt_nh_del(fib6_rt, iter->rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) WARN_ON_ONCE(!list_empty(&fib6_rt->nh_list));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) nsim_fib_rt_fini(&fib6_rt->common);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) kfree(fib6_rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) static struct nsim_fib6_rt *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) nsim_fib6_rt_lookup(struct rhashtable *fib_rt_ht, const struct fib6_info *rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) struct nsim_fib_rt *fib_rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) fib_rt = nsim_fib_rt_lookup(fib_rt_ht, &rt->fib6_dst.addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) sizeof(rt->fib6_dst.addr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) rt->fib6_dst.plen, AF_INET6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) rt->fib6_table->tb6_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if (!fib_rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) return container_of(fib_rt, struct nsim_fib6_rt, common);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) static int nsim_fib6_rt_append(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) struct fib6_entry_notifier_info *fen6_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) struct fib6_info *iter, *rt = fen6_info->rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) struct nsim_fib6_rt *fib6_rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) fib6_rt = nsim_fib6_rt_lookup(&data->fib_rt_ht, rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) if (WARN_ON_ONCE(!fib6_rt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) err = nsim_fib6_rt_nh_add(fib6_rt, rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) rt->trap = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) if (!fen6_info->nsiblings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) list_for_each_entry(iter, &rt->fib6_siblings, fib6_siblings) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) if (i == fen6_info->nsiblings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) err = nsim_fib6_rt_nh_add(fib6_rt, iter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) goto err_fib6_rt_nh_del;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) iter->trap = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) WARN_ON_ONCE(i != fen6_info->nsiblings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) err_fib6_rt_nh_del:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) list_for_each_entry_continue_reverse(iter, &rt->fib6_siblings,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) fib6_siblings) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) iter->trap = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) nsim_fib6_rt_nh_del(fib6_rt, iter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) rt->trap = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) nsim_fib6_rt_nh_del(fib6_rt, rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) static void nsim_fib6_rt_hw_flags_set(const struct nsim_fib6_rt *fib6_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) bool trap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) struct nsim_fib6_rt_nh *fib6_rt_nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) list_for_each_entry(fib6_rt_nh, &fib6_rt->nh_list, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) fib6_info_hw_flags_set(fib6_rt_nh->rt, false, trap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) static int nsim_fib6_rt_add(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) struct nsim_fib6_rt *fib6_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) err = nsim_fib_account(&data->ipv6.fib, true, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) err = rhashtable_insert_fast(&data->fib_rt_ht,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) &fib6_rt->common.ht_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) nsim_fib_rt_ht_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) NL_SET_ERR_MSG_MOD(extack, "Failed to insert IPv6 route");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) goto err_fib_dismiss;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) nsim_fib6_rt_hw_flags_set(fib6_rt, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) err_fib_dismiss:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) nsim_fib_account(&data->ipv6.fib, false, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) static int nsim_fib6_rt_replace(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) struct nsim_fib6_rt *fib6_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) struct nsim_fib6_rt *fib6_rt_old,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) /* We are replacing a route, so no need to change the accounting. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) err = rhashtable_replace_fast(&data->fib_rt_ht,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) &fib6_rt_old->common.ht_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) &fib6_rt->common.ht_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) nsim_fib_rt_ht_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) NL_SET_ERR_MSG_MOD(extack, "Failed to replace IPv6 route");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) nsim_fib6_rt_hw_flags_set(fib6_rt, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) nsim_fib6_rt_hw_flags_set(fib6_rt_old, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) nsim_fib6_rt_destroy(fib6_rt_old);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) static int nsim_fib6_rt_insert(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) struct fib6_entry_notifier_info *fen6_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) struct netlink_ext_ack *extack = fen6_info->info.extack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) struct nsim_fib6_rt *fib6_rt, *fib6_rt_old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) fib6_rt = nsim_fib6_rt_create(data, fen6_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) if (IS_ERR(fib6_rt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) return PTR_ERR(fib6_rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) fib6_rt_old = nsim_fib6_rt_lookup(&data->fib_rt_ht, fen6_info->rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) if (!fib6_rt_old)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) err = nsim_fib6_rt_add(data, fib6_rt, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) err = nsim_fib6_rt_replace(data, fib6_rt, fib6_rt_old, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) nsim_fib6_rt_destroy(fib6_rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) nsim_fib6_rt_remove(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) const struct fib6_entry_notifier_info *fen6_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) struct netlink_ext_ack *extack = fen6_info->info.extack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) struct nsim_fib6_rt *fib6_rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) /* Multipath routes are first added to the FIB trie and only then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) * notified. If we vetoed the addition, we will get a delete
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) * notification for a route we do not have. Therefore, do not warn if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) * route was not found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) fib6_rt = nsim_fib6_rt_lookup(&data->fib_rt_ht, fen6_info->rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) if (!fib6_rt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) /* If not all the nexthops are deleted, then only reduce the nexthop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) * group.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) if (fen6_info->nsiblings + 1 != fib6_rt->nhs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) nsim_fib6_rt_nh_del(fib6_rt, fen6_info->rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) rhashtable_remove_fast(&data->fib_rt_ht, &fib6_rt->common.ht_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) nsim_fib_rt_ht_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) nsim_fib_account(&data->ipv6.fib, false, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) nsim_fib6_rt_destroy(fib6_rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) static int nsim_fib6_event(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) struct fib_notifier_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) unsigned long event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) struct fib6_entry_notifier_info *fen6_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) fen6_info = container_of(info, struct fib6_entry_notifier_info, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) if (fen6_info->rt->nh) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) NL_SET_ERR_MSG_MOD(info->extack, "IPv6 route with nexthop objects is not supported");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (fen6_info->rt->fib6_src.plen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) NL_SET_ERR_MSG_MOD(info->extack, "IPv6 source-specific route is not supported");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) case FIB_EVENT_ENTRY_REPLACE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) err = nsim_fib6_rt_insert(data, fen6_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) case FIB_EVENT_ENTRY_APPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) err = nsim_fib6_rt_append(data, fen6_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) case FIB_EVENT_ENTRY_DEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) nsim_fib6_rt_remove(data, fen6_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) static int nsim_fib_event(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) struct fib_notifier_info *info, unsigned long event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) switch (info->family) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) case AF_INET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) err = nsim_fib4_event(data, info, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) case AF_INET6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) err = nsim_fib6_event(data, info, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) struct nsim_fib_data *data = container_of(nb, struct nsim_fib_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) fib_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) struct fib_notifier_info *info = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) /* IPv6 routes can be added via RAs from softIRQ. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) spin_lock_bh(&data->fib_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) case FIB_EVENT_RULE_ADD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) case FIB_EVENT_RULE_DEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) err = nsim_fib_rule_event(data, info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) event == FIB_EVENT_RULE_ADD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) case FIB_EVENT_ENTRY_REPLACE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) case FIB_EVENT_ENTRY_APPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) case FIB_EVENT_ENTRY_DEL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) err = nsim_fib_event(data, info, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) spin_unlock_bh(&data->fib_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) return notifier_from_errno(err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) static void nsim_fib4_rt_free(struct nsim_fib_rt *fib_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) struct nsim_fib_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) struct devlink *devlink = data->devlink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) struct nsim_fib4_rt *fib4_rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) fib4_rt = container_of(fib_rt, struct nsim_fib4_rt, common);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) nsim_fib4_rt_hw_flags_set(devlink_net(devlink), fib4_rt, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) nsim_fib_account(&data->ipv4.fib, false, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) nsim_fib4_rt_destroy(fib4_rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) static void nsim_fib6_rt_free(struct nsim_fib_rt *fib_rt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) struct nsim_fib_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) struct nsim_fib6_rt *fib6_rt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) fib6_rt = container_of(fib_rt, struct nsim_fib6_rt, common);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) nsim_fib6_rt_hw_flags_set(fib6_rt, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) nsim_fib_account(&data->ipv6.fib, false, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) nsim_fib6_rt_destroy(fib6_rt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) static void nsim_fib_rt_free(void *ptr, void *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) struct nsim_fib_rt *fib_rt = ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) struct nsim_fib_data *data = arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) switch (fib_rt->key.family) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) case AF_INET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) nsim_fib4_rt_free(fib_rt, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) case AF_INET6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) nsim_fib6_rt_free(fib_rt, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) WARN_ON_ONCE(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) /* inconsistent dump, trying again */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) static void nsim_fib_dump_inconsistent(struct notifier_block *nb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) struct nsim_fib_data *data = container_of(nb, struct nsim_fib_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) fib_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) struct nsim_fib_rt *fib_rt, *fib_rt_tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) /* The notifier block is still not registered, so we do not need to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) * take any locks here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) list_for_each_entry_safe(fib_rt, fib_rt_tmp, &data->fib_rt_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) rhashtable_remove_fast(&data->fib_rt_ht, &fib_rt->ht_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) nsim_fib_rt_ht_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) nsim_fib_rt_free(fib_rt, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) data->ipv4.rules.num = 0ULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) data->ipv6.rules.num = 0ULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) static u64 nsim_fib_ipv4_resource_occ_get(void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) struct nsim_fib_data *data = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) return nsim_fib_get_val(data, NSIM_RESOURCE_IPV4_FIB, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) static u64 nsim_fib_ipv4_rules_res_occ_get(void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) struct nsim_fib_data *data = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) return nsim_fib_get_val(data, NSIM_RESOURCE_IPV4_FIB_RULES, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) static u64 nsim_fib_ipv6_resource_occ_get(void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) struct nsim_fib_data *data = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) return nsim_fib_get_val(data, NSIM_RESOURCE_IPV6_FIB, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) static u64 nsim_fib_ipv6_rules_res_occ_get(void *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) struct nsim_fib_data *data = priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) return nsim_fib_get_val(data, NSIM_RESOURCE_IPV6_FIB_RULES, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) static void nsim_fib_set_max_all(struct nsim_fib_data *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) struct devlink *devlink)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) enum nsim_resource_id res_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) for (i = 0; i < ARRAY_SIZE(res_ids); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) u64 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) err = devlink_resource_size_get(devlink, res_ids[i], &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) val = (u64) -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) nsim_fib_set_max(data, res_ids[i], val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) struct nsim_fib_data *nsim_fib_create(struct devlink *devlink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) struct nsim_fib_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) data = kzalloc(sizeof(*data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) data->devlink = devlink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) spin_lock_init(&data->fib_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) INIT_LIST_HEAD(&data->fib_rt_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) err = rhashtable_init(&data->fib_rt_ht, &nsim_fib_rt_ht_params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) goto err_data_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) nsim_fib_set_max_all(data, devlink);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) data->fib_nb.notifier_call = nsim_fib_event_nb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) err = register_fib_notifier(devlink_net(devlink), &data->fib_nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) nsim_fib_dump_inconsistent, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) pr_err("Failed to register fib notifier\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) goto err_rhashtable_destroy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) devlink_resource_occ_get_register(devlink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) NSIM_RESOURCE_IPV4_FIB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) nsim_fib_ipv4_resource_occ_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) devlink_resource_occ_get_register(devlink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) NSIM_RESOURCE_IPV4_FIB_RULES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) nsim_fib_ipv4_rules_res_occ_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) devlink_resource_occ_get_register(devlink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) NSIM_RESOURCE_IPV6_FIB,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) nsim_fib_ipv6_resource_occ_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) devlink_resource_occ_get_register(devlink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) NSIM_RESOURCE_IPV6_FIB_RULES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) nsim_fib_ipv6_rules_res_occ_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) return data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) err_rhashtable_destroy:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) rhashtable_free_and_destroy(&data->fib_rt_ht, nsim_fib_rt_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) err_data_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) kfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) return ERR_PTR(err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) devlink_resource_occ_get_unregister(devlink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) NSIM_RESOURCE_IPV6_FIB_RULES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) devlink_resource_occ_get_unregister(devlink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) NSIM_RESOURCE_IPV6_FIB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) devlink_resource_occ_get_unregister(devlink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) NSIM_RESOURCE_IPV4_FIB_RULES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) devlink_resource_occ_get_unregister(devlink,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) NSIM_RESOURCE_IPV4_FIB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) unregister_fib_notifier(devlink_net(devlink), &data->fib_nb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) rhashtable_free_and_destroy(&data->fib_rt_ht, nsim_fib_rt_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) WARN_ON_ONCE(!list_empty(&data->fib_rt_list));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) kfree(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) }